stages.k8s.python.groovy 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // -------------
  2. // python on K8S
  3. sharedLibsPath = "${env.WORKSPACE}/sharedLibs"
  4. backup_destination = '/var/jenkins_home/backups'
  5. backup_targetFile = 'dockerImage.tar'
  6. backup_num = 3
  7. // 获取镜像URL
  8. generateFullImageUri = {Map DOCKER, String base_branch, String BUILD_NUMBER ->
  9. return "${DOCKER.registry}/${DOCKER.image}:${base_branch}-${BUILD_NUMBER}"
  10. }
  11. // 获取镜像名
  12. generateImageName = {Map DOCKER, String base_branch, String BUILD_NUMBER ->
  13. return "${DOCKER.image}:${base_branch}-${BUILD_NUMBER}"
  14. }
  15. def cleanDockerImage(String dockerImgName) {
  16. sh "docker rmi ${dockerImgName}"
  17. }
  18. def backupDockerImage(String dockerImgName) {
  19. echo "-----> Backup artifact(docker image : ${dockerImgName}) ..."
  20. path = "${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}"
  21. sh """
  22. docker save ${dockerImgName} -o ${backup_targetFile}
  23. if [ -d ${path} ];
  24. then
  25. echo \"${path} already exists\"
  26. else
  27. mkdir -p ${path}
  28. fi
  29. mv ${backup_targetFile} ${path}
  30. """
  31. }
  32. def backupK8sConfigs(String[] files2backup) {
  33. path = "${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}/k8s"
  34. sh """if [ -d ${path} ];
  35. then
  36. echo \"${path} already exists!\"
  37. else
  38. mkdir -p ${path}
  39. fi
  40. """
  41. for(file in files2backup) {
  42. sh "cp -r ${file} ${path}"
  43. }
  44. }
  45. def generateDockerfile(Object SERVICE, String pathOfDockerfile='projdir') {
  46. def module = SERVICE.module == null ? '' : (SERVICE.module[-1] == '/' ? SERVICE.module : SERVICE.module + '/')
  47. echo "-----> Generating Dockerfile: ${pathOfDockerfile}/Dockerfile ..."
  48. sh """cat > ${pathOfDockerfile}/Dockerfile<<EOF
  49. FROM python:3.10-slim as final
  50. COPY ./requirements.txt /app
  51. COPY ./spider.py /app
  52. RUN pip install --upgrade pip
  53. RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
  54. RUN pip install --no-cache-dir -r requirements.txt
  55. EOF
  56. """
  57. return pathOfDockerfile
  58. }
  59. def buildDockerImage(Object SERVICE, Object DOCKER, String base_branch, projDir='projdir', String filter2Remove=null) {
  60. def imageUri = generateFullImageUri(DOCKER, base_branch, BUILD_NUMBER)
  61. echo "-----> Building docker image: ${imageUri} ..."
  62. dir(projDir) {
  63. docker.withRegistry("http://${DOCKER.registry}", "${DOCKER.push_credentialId}") {
  64. def imageName = generateImageName(DOCKER, base_branch, BUILD_NUMBER)
  65. def image = docker.build(imageName)
  66. image.push()
  67. sh "docker rmi ${imageName}"
  68. if(filter2Remove != null)
  69. sh "docker image prune --filter label=${filter2Remove} -f"
  70. }
  71. }
  72. return imageUri
  73. }
  74. def restoreDockerImage(Object DOCKER, String workspace, String base_branch, String rollbackBuildNumber) {
  75. dir(workspace) {
  76. imageUri = generateFullImageUri(DOCKER, base_branch, rollbackBuildNumber)
  77. // gunzip ${backup_targetFile}.tar.gz | docker load
  78. sh "docker load -i ${backup_targetFile}"
  79. // in case, docker image doesn't exist in remote registry
  80. docker.withRegistry("http://${DOCKER.registry}", "${DOCKER.push_credentialId}") {
  81. def image = docker.image(imageUri)
  82. image.push()
  83. }
  84. }
  85. return imageUri
  86. }
  87. def deployWithConfigmapEnvOnly(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", namespace='default') {
  88. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  89. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  90. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  91. def python_args = '['
  92. args.each{item -> python_args += "\"$item\","}
  93. python_args = python_args[0..-2] + ']'
  94. kvs = [:]
  95. kvs.put('<service_name>', SERVICE.name)
  96. kvs.put('<service_version>', SERVICE.version)
  97. kvs.put('<release>', base_branch)
  98. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  99. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  100. kvs.put('<docker_image>', imageUri)
  101. kvs.put('<python_args>', python_args)
  102. if (SERVICE.health != null)
  103. kvs.put('<service_health>', SERVICE.health)
  104. kvs.put('<configmap_env_name>', configmap_env_name)
  105. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  106. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  107. k3sUtils.generateService(kvs, 'service.yaml')
  108. k3sUtils.applyService(K3S, 'service.yaml')
  109. }
  110. def deployWithConfigmapEnvOnly_rollback(SERVICE, K3S, String rollbackBuildNumber, String[] args, configmapEnv="./configmap-env.ini", namespace='default') {
  111. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  112. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  113. dir("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/k8s") {
  114. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  115. def java_args = '['
  116. args.each{item -> java_args += "\"$item\","}
  117. java_args = java_args[0..-2] + ']'
  118. kvs = [:]
  119. kvs.put('<service_name>', SERVICE.name)
  120. kvs.put('<service_version>', SERVICE.version)
  121. kvs.put('<release>', BASE_BRANCH)
  122. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  123. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  124. kvs.put('<docker_image>', imageUri)
  125. kvs.put('<java_args>', java_args)
  126. if (SERVICE.health != null)
  127. kvs.put('<service_health>', SERVICE.health)
  128. kvs.put('<configmap_env_name>', configmap_env_name)
  129. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  130. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  131. k3sUtils.generateService(kvs, 'service.yaml')
  132. k3sUtils.applyService(K3S, 'service.yaml')
  133. }
  134. }
  135. def deployWithConfigmaps_rollback(SERVICE, K3S, String rollbackBuildNumber, String[] args, configmapEnv="./configmap-env.ini", configmapConf="./configmap") {
  136. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  137. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  138. dir("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/k8s") {
  139. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv)
  140. def configmap_conf_name = k3sUtils.applyConfigMapConfig(SERVICE, K3S, configmapConf)
  141. def java_args = '['
  142. args.each{item -> java_args += "\"$item\","}
  143. java_args = java_args[0..-2] + ']'
  144. kvs = [:]
  145. kvs.put('<service_name>', SERVICE.name)
  146. kvs.put('<service_version>', SERVICE.version)
  147. kvs.put('<release>', BASE_BRANCH)
  148. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  149. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  150. kvs.put('<docker_image>', imageUri)
  151. kvs.put('<java_args>', java_args)
  152. if (SERVICE.health != null)
  153. kvs.put('<service_health>', SERVICE.health)
  154. kvs.put('<configmap_env_name>', configmap_env_name)
  155. kvs.put('<configmap_conf_name>', configmap_conf_name)
  156. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  157. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  158. k3sUtils.generateService(kvs, 'service.yaml')
  159. k3sUtils.applyService(K3S, 'service.yaml')
  160. }
  161. }
  162. def deployWithConfigmaps(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", configmapConf="./configmap") {
  163. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  164. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  165. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv)
  166. def configmap_conf_name = k3sUtils.applyConfigMapConfig(SERVICE, K3S, configmapConf)
  167. def java_args = '['
  168. args.each{item -> java_args += "\"$item\","}
  169. java_args = java_args[0..-2] + ']'
  170. kvs = [:]
  171. kvs.put('<service_name>', SERVICE.name)
  172. kvs.put('<service_version>', SERVICE.version)
  173. kvs.put('<release>', base_branch)
  174. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  175. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  176. kvs.put('<docker_image>', imageUri)
  177. kvs.put('<java_args>', java_args)
  178. if (SERVICE.health != null)
  179. kvs.put('<service_health>', SERVICE.health)
  180. kvs.put('<configmap_env_name>', configmap_env_name)
  181. kvs.put('<configmap_conf_name>', configmap_conf_name)
  182. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  183. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  184. k3sUtils.generateService(kvs, 'service.yaml')
  185. k3sUtils.applyService(K3S, 'service.yaml')
  186. }
  187. // Jenkins pipeline stages
  188. def upgrade(Object CONFIG, String base_branch, String[] k8sBackupFiles, closures=[:]) {
  189. stage('Source code check out') {
  190. println "loading ${sharedLibsPath}/gitUtil.groovy..."
  191. def gitUtils = load "${sharedLibsPath}/gitUtil.groovy"
  192. COMMIT_SHA = closures.GITCLONE == null ? gitUtils.clone(CONFIG.git, base_branch) : closures.GITCLONE()
  193. if (closures.POST_GITCLONE != null)
  194. closures.POST_GITCLONE()
  195. }
  196. stage("Docker image build") {
  197. def projDir = 'projdir'
  198. if (closures.GENERATEDOCKERFILE != null)
  199. projDir = closures.GENERATEDOCKERFILE()
  200. else
  201. projDir = generateDockerfile(CONFIG.service) //default
  202. if (closures.BUILDIMAGE != null)
  203. imageUri = closures.BUILDIMAGE()
  204. else
  205. imageUri = buildDockerImage(CONFIG.service, CONFIG.docker, base_branch, projDir)
  206. // stage("Docker Image backup") {
  207. if (k8sBackupFiles != null && k8sBackupFiles.size() > 0) {
  208. backupDockerImage(imageUri)
  209. envFile = new File("${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}/env")
  210. envFile << "${COMMIT_SHA}\n"
  211. envFile << "${base_branch}\n"
  212. }
  213. // }
  214. cleanDockerImage(imageUri)
  215. }
  216. stage("Apply K8S ConfigMaps && Deployment") {
  217. // stage("K8s configs backup") {
  218. if (k8sBackupFiles != null && k8sBackupFiles.size() > 0)
  219. backupK8sConfigs(k8sBackupFiles)
  220. // }
  221. if (closures.K3SDEPLOY != null) {
  222. closures.K3SDEPLOY()
  223. return
  224. }
  225. }
  226. stage("Post Execution Script") {
  227. print "Clear older backup version"
  228. // 清理旧的备份
  229. dir("${backup_destination}/${JOB_NAME}") {
  230. sh """
  231. save_file=`ls -ltr | tail -${backup_num} | awk '{print \$NF}'`
  232. ls | grep -v "\$save_file" | xargs rm -rf
  233. """
  234. }
  235. }
  236. }
  237. def rollback(CONFIG, rollbackBuildNumber, closures=[:]) {
  238. // 1. restore specified version
  239. path = "${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}"
  240. if (fileExists(path)) {
  241. stage('Source code check out') {
  242. print("souce code check out. Skipped!")
  243. }
  244. envFile = new File("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/env")
  245. def lines = envFile.readLines()
  246. COMMIT_SHA = lines[0]
  247. BASE_BRANCH = lines[1]
  248. // 2. docker image build
  249. stage("Docker image build") {
  250. print("restore docker image from rollbackNo. #${rollbackBuildNumber}")
  251. imageUri = restoreDockerImage(CONFIG.docker, path, BASE_BRANCH, rollbackBuildNumber)
  252. cleanDockerImage(imageUri)
  253. }
  254. // 3. k8s configmap && deployment apply
  255. stage("Apply K8S ConfigMaps && Deployment") {
  256. if (closures.K3SDEPLOY != null)
  257. closures.K3SDEPLOY()
  258. }
  259. stage("Post Execution Script") {
  260. print "Clear rollback workspace"
  261. // 清理rollback工作目录
  262. dir("${backup_destination}/${JOB_NAME}") {
  263. sh "rm -rf *@tmp"
  264. }
  265. }
  266. }
  267. }
  268. return this