pipelines.k8s.java.groovy 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /**
  2. * Unified Java + Docker + K3s pipeline runner for this repo.
  3. *
  4. * Goal: keep service Jenkinsfiles thin by moving per-service differences into cfg.yaml:
  5. * project.pipeline: { jdkTool, baseImage, enableSkywalking, deployMode, k8sBackups, ... }
  6. *
  7. * This file is designed to be backward compatible: if `CONFIG.pipeline` is missing,
  8. * defaults match the most common existing Jenkinsfile patterns in this repo.
  9. */
  10. def _get(Map m, String k, def dflt=null) {
  11. return (m != null && m.containsKey(k) && m[k] != null) ? m[k] : dflt
  12. }
  13. def _asStringArray(def v) {
  14. if (v == null) return [] as String[]
  15. if (v instanceof String[]) return v
  16. if (v instanceof List) return (v.collect { it.toString() }) as String[]
  17. return [v.toString()] as String[]
  18. }
  19. def _asList(def v) {
  20. if (v == null) return []
  21. if (v instanceof List) return v
  22. return [v]
  23. }
  24. def _normalizeModulePath(def module) {
  25. def moduleText = module == null ? '' : module.toString().trim()
  26. if (!moduleText) return ''
  27. return moduleText.endsWith('/') ? moduleText : moduleText + '/'
  28. }
  29. def _pipelineArgs(def pipeline) {
  30. return pipeline instanceof Map ? _get(pipeline, "args", null) : null
  31. }
  32. def _skywalkingArgs(Map CONFIG) {
  33. def p = CONFIG.pipeline ?: [:]
  34. if (_get(p, "addSkywalkingArgs", false) != true) return []
  35. return [
  36. "-javaagent:/app/skywalking-agent/skywalking-agent.jar",
  37. "-Dskywalking.agent.service_name=${CONFIG.service.name}",
  38. "-Dskywalking.collector.backend_service=${CONFIG.skywalking.address}"
  39. ]
  40. }
  41. def _splitJavaArgs(String[] rawArgs) {
  42. def jvmArgs = []
  43. def appArgs = []
  44. rawArgs.each { arg ->
  45. def text = arg == null ? '' : arg.toString().trim()
  46. if (!text) return
  47. if (text.startsWith('--')) {
  48. appArgs << text
  49. return
  50. }
  51. jvmArgs << text
  52. }
  53. return [jvmArgs, appArgs]
  54. }
  55. def _buildJavaArgs(Map CONFIG) {
  56. def p = CONFIG.pipeline ?: [:]
  57. def args = _pipelineArgs(p)
  58. def buildNumberArg = _get(p, "includeBuildNumber", false) ? ["-DBuild.number=${BUILD_NUMBER}"] : []
  59. if (args instanceof List || args instanceof String[]) {
  60. def directArgs = _asStringArray(args)
  61. if (directArgs.length > 0) {
  62. def (jvmArgs, appArgs) = _splitJavaArgs(directArgs)
  63. return (jvmArgs + _skywalkingArgs(CONFIG) + buildNumberArg + ["-jar", "/app/target/${CONFIG.service.jar}"] + appArgs) as String[]
  64. }
  65. }
  66. if (args instanceof String && args.toString().trim()) {
  67. def (jvmArgs, appArgs) = _splitJavaArgs([args.toString().trim()] as String[])
  68. return (jvmArgs + _skywalkingArgs(CONFIG) + buildNumberArg + ["-jar", "/app/target/${CONFIG.service.jar}"] + appArgs) as String[]
  69. }
  70. if (args instanceof Map) {
  71. def explicitArgs = _asStringArray(_get(args, "javaArgs", null))
  72. if (explicitArgs.length > 0) {
  73. def (jvmArgs, appArgs) = _splitJavaArgs(explicitArgs)
  74. return (jvmArgs + _skywalkingArgs(CONFIG) + buildNumberArg + ["-jar", "/app/target/${CONFIG.service.jar}"] + appArgs) as String[]
  75. }
  76. }
  77. def explicitArgs = _asStringArray(_get(p, "javaArgs", null))
  78. if (explicitArgs.length > 0) return explicitArgs
  79. def jvmArgs = ["-Djava.security.egd=file:/dev/./urandom"]
  80. jvmArgs.addAll(_skywalkingArgs(CONFIG))
  81. jvmArgs.addAll(buildNumberArg)
  82. def xmx = args instanceof Map ? _get(args, "xmx", _get(p, "xmx", null)) : _get(p, "xmx", null)
  83. if (xmx != null && xmx.toString().trim()) {
  84. jvmArgs << "-Xmx${xmx.toString().trim()}"
  85. }
  86. def serverPort = args instanceof Map ? _get(args, "serverPort", _get(p, "serverPort", null)) : _get(p, "serverPort", null)
  87. if (serverPort != null && serverPort.toString().trim()) {
  88. jvmArgs << "-Dserver.port=${serverPort.toString().trim()}"
  89. }
  90. def appArgs = []
  91. def springProfile = args instanceof Map ? _get(args, "springProfile", _get(p, "springProfile", null)) : _get(p, "springProfile", null)
  92. if (springProfile != null && springProfile.toString().trim()) {
  93. appArgs << "--spring.profiles.active=${springProfile.toString().trim()}"
  94. }
  95. return (jvmArgs + ["-jar", "/app/target/${CONFIG.service.jar}"] + appArgs) as String[]
  96. }
  97. def _generateDockerfile(Map CONFIG, String pathOfDockerfile='projdir') {
  98. def p = CONFIG.pipeline ?: [:]
  99. def module = _normalizeModulePath(CONFIG.service.module)
  100. def baseImage = _get(p, "baseImage", "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/openjdk:17-jdk-alpine")
  101. def addSkywalking = _get(p, "enableSkywalking", false)
  102. def jar = CONFIG.service.jar
  103. def skywalkingAddLine = addSkywalking ? "ADD skywalking-agent /app/skywalking-agent" : ""
  104. sh """cat > ${pathOfDockerfile}/Dockerfile<<EOF
  105. FROM ${baseImage}
  106. ${skywalkingAddLine}
  107. ADD ${module}target/${jar} /app/target/${jar}
  108. EOF
  109. """
  110. return pathOfDockerfile
  111. }
  112. def _maybeCopySkywalking(Map CONFIG) {
  113. def p = CONFIG.pipeline ?: [:]
  114. if (!_get(p, "enableSkywalking", false)) return
  115. def srcRel = _get(p, "skywalkingAgentSrc", "../../skywalking-agent-9.0.0")
  116. sh "cp -r ${srcRel} projdir/skywalking-agent"
  117. }
  118. def _maybeCleanupSkywalking(Map CONFIG) {
  119. def p = CONFIG.pipeline ?: [:]
  120. if (!_get(p, "enableSkywalking", false)) return
  121. sh "rm -rf projdir/skywalking-agent"
  122. }
  123. def _deployAdditionalConfigmapEnvOnly(def stages, Map CONFIG, String baseBranch, String[] javaArgs, String configmapEnv, String namespace='default') {
  124. def p = CONFIG.pipeline ?: [:]
  125. def additionalDeployments = _asList(_get(p, "additionalConfigmapEnvOnlyDeployments", []))
  126. additionalDeployments.each { deployment ->
  127. if (!(deployment instanceof Map)) {
  128. error("pipeline.additionalConfigmapEnvOnlyDeployments entries must be maps")
  129. }
  130. def deploymentTemplate = _get(deployment, "deploymentTemplate", "")
  131. def serviceTemplate = _get(deployment, "serviceTemplate", "")
  132. if (!deploymentTemplate || !serviceTemplate) {
  133. error("additional configmap-env-only deployments require deploymentTemplate and serviceTemplate")
  134. }
  135. stages.deployWithConfigmapEnvOnlyTemplate(
  136. CONFIG.service,
  137. CONFIG.k3s,
  138. baseBranch,
  139. javaArgs,
  140. configmapEnv,
  141. deploymentTemplate,
  142. serviceTemplate,
  143. namespace
  144. )
  145. }
  146. }
  147. def run(Map CONFIG, String action, def stages, String baseBranch, String namespace='default', String rollbackBuildNumber='') {
  148. // Ensure docker image name is formatted consistently with existing Jenkinsfiles.
  149. // 装备docker镜像路径
  150. CONFIG.docker.image = String.format(CONFIG.docker.image, CONFIG.service.name)
  151. // 选择jdk环境
  152. def p = CONFIG.pipeline ?: [:]
  153. def jdkTool = _get(p, "jdkTool", null)
  154. if (jdkTool != null && jdkTool.toString().trim()) {
  155. jdk = tool name: jdkTool
  156. env.JAVA_HOME = "${jdk}"
  157. }
  158. def base_branch = baseBranch
  159. String[] JAVA_ARGS = _buildJavaArgs(CONFIG)
  160. String[] K8S_BACKUPS = _asStringArray(_get(p, "k8sBackups", []))
  161. def deployMode = _get(p, "deployMode", "configmapEnvOnly")
  162. // Optional per-service file names; keep defaults matching existing code.
  163. def configmapEnv = _get(p, "configmapEnvFile", "./configmap-env.ini")
  164. def configmapConf = _get(p, "configmapConfFile", "./configmap")
  165. if ("upgrade" == action || "upgrade:selected" == action) {
  166. stages.upgrade(CONFIG, base_branch, K8S_BACKUPS, [
  167. 'POST_GITCLONE': { _maybeCopySkywalking(CONFIG) },
  168. 'GENERATEDOCKERFILE': { _generateDockerfile(CONFIG) },
  169. 'K3SDEPLOY': {
  170. if (deployMode == "configmapEnvOnly") {
  171. stages.deployWithConfigmapEnvOnly(CONFIG.service, CONFIG.k3s, base_branch, JAVA_ARGS, configmapEnv, namespace)
  172. _deployAdditionalConfigmapEnvOnly(stages, CONFIG, base_branch, JAVA_ARGS, configmapEnv, namespace)
  173. return
  174. }
  175. if (deployMode == "configmaps") {
  176. stages.deployWithConfigmaps(CONFIG.service, CONFIG.k3s, base_branch, JAVA_ARGS, configmapEnv, configmapConf, namespace)
  177. return
  178. }
  179. // Fallback to repo default (env-only).
  180. stages.deployWithConfigmapEnvOnly(CONFIG.service, CONFIG.k3s, base_branch, JAVA_ARGS, configmapEnv, namespace)
  181. }
  182. ])
  183. _maybeCleanupSkywalking(CONFIG)
  184. return
  185. }
  186. if ("rollback" == action) {
  187. stages.rollback(CONFIG, rollbackBuildNumber, [
  188. 'K3SDEPLOY': {
  189. if (deployMode == "configmapEnvOnly") {
  190. stages.deployWithConfigmapEnvOnly_rollback(CONFIG.service, CONFIG.k3s, rollbackBuildNumber, JAVA_ARGS, configmapEnv, namespace)
  191. return
  192. }
  193. if (deployMode == "configmaps") {
  194. stages.deployWithConfigmaps_rollback(CONFIG.service, CONFIG.k3s, rollbackBuildNumber, JAVA_ARGS, configmapEnv, configmapConf, namespace)
  195. return
  196. }
  197. stages.deployWithConfigmapEnvOnly_rollback(CONFIG.service, CONFIG.k3s, rollbackBuildNumber, JAVA_ARGS, configmapEnv, namespace)
  198. }
  199. ])
  200. return
  201. }
  202. }
  203. return this