Jenkinsfile 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // ============================================
  2. // Jenkins Pipeline for Spring Cloud Log Demo
  3. // CI (Continuous Integration) Pipeline - 优化版
  4. // ============================================
  5. // 优化点:
  6. // - Docker 层缓存(分离 POM 和源码)
  7. // - Maven 缓存持久化
  8. // - 镜像并行构建(3 倍加速)
  9. // - 智能增量编译
  10. pipeline {
  11. agent any
  12. options {
  13. // 保留最近 15 次构建
  14. buildDiscarder(logRotator(numToKeepStr: '15'))
  15. // 30 分钟超时
  16. timeout(time: 30, unit: 'MINUTES')
  17. // 禁止并发构建(保护 Maven 缓存)
  18. disableConcurrentBuilds()
  19. // 时间戳
  20. timestamps()
  21. }
  22. parameters {
  23. choice(
  24. name: 'BUILD_TYPE',
  25. choices: ['SNAPSHOT', 'RELEASE'],
  26. description: '构建类型'
  27. )
  28. booleanParam(
  29. name: 'SKIP_TESTS',
  30. defaultValue: false,
  31. description: '跳过单元测试'
  32. )
  33. booleanParam(
  34. name: 'PUSH_DOCKER',
  35. defaultValue: false,
  36. description: '推送Docker镜像到仓库'
  37. )
  38. string(
  39. name: 'DOCKER_REGISTRY',
  40. defaultValue: 'harbor.stardance',
  41. description: 'Docker注册表地址'
  42. )
  43. string(
  44. name: 'DOCKER_NAMESPACE',
  45. defaultValue: 'shoprecycle',
  46. description: 'Docker命名空间'
  47. )
  48. }
  49. environment {
  50. // ✅ 关键优化:Maven 缓存配置
  51. MAVEN_HOME = tool('maven-3.8')
  52. MAVEN_CACHE_DIR = "${WORKSPACE}/.m2/repository"
  53. MAVEN_OPTS = '''
  54. -Dmaven.repo.local=${WORKSPACE}/.m2/repository \
  55. -Xmx1024m -Xms512m \
  56. -XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
  57. -Dorg.slf4j.simpleLogger.defaultLogLevel=warn
  58. '''
  59. // Git 信息
  60. GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
  61. GIT_AUTHOR = sh(script: 'git log -1 --format=%an', returnStdout: true).trim()
  62. // 构建版本
  63. BUILD_NUMBER_PADDED = sh(script: 'printf "%04d" ${BUILD_NUMBER}', returnStdout: true).trim()
  64. APP_VERSION = "${BUILD_TYPE == 'RELEASE' ? '1.0' : '1.0.0'}-${BUILD_NUMBER_PADDED}"
  65. IMAGE_TAG = "${APP_VERSION}-${GIT_COMMIT_SHORT}"
  66. // Docker 配置
  67. DOCKER_BUILDKIT = '1'
  68. DOCKER_DEFAULT_PLATFORM = 'linux/amd64'
  69. }
  70. stages {
  71. stage('準備') {
  72. steps {
  73. script {
  74. echo """
  75. ════════════════════════════════════════════
  76. CI 构建信息(优化版)
  77. ════════════════════════════════════════════
  78. 构建类型: ${BUILD_TYPE}
  79. Git 提交: ${GIT_COMMIT_SHORT}
  80. 作者: ${GIT_AUTHOR}
  81. 应用版本: ${APP_VERSION}
  82. 镜像TAG: ${IMAGE_TAG}
  83. 跳过测试: ${SKIP_TESTS}
  84. 推送Docker: ${PUSH_DOCKER}
  85. ════════════════════════════════════════════
  86. """
  87. }
  88. // 清理 workspace
  89. deleteDir()
  90. checkout scm
  91. // 显示工具版本和缓存信息
  92. sh '''
  93. echo "==== 环境信息 ===="
  94. java -version 2>&1 | head -1
  95. mvn --version | head -1
  96. docker --version
  97. echo ""
  98. echo "==== 缓存信息 ===="
  99. du -sh ${WORKSPACE}/.m2/repository 2>/dev/null || echo "缓存: 首次构建"
  100. '''
  101. }
  102. }
  103. stage('代码检查') {
  104. steps {
  105. script {
  106. echo ">>> 编译 Common 模块..."
  107. sh '''
  108. mvn clean package -pl shop-recycle-common \
  109. -DskipTests \
  110. -B \
  111. -Dmaven.test.skip=true \
  112. || { echo "❌ Common 模块构建失败"; exit 1; }
  113. '''
  114. }
  115. }
  116. }
  117. stage('编译与测试') {
  118. steps {
  119. script {
  120. echo ">>> 执行 Maven 编译..."
  121. def testArgs = SKIP_TESTS == 'true' ? '-DskipTests' : ''
  122. sh """
  123. mvn package \
  124. ${testArgs} \
  125. -B \
  126. -Dmaven.test.skip=${SKIP_TESTS} \
  127. -Ddocker.build.number=${BUILD_NUMBER_PADDED} \
  128. -Dgit.commit=${GIT_COMMIT_SHORT}
  129. """
  130. }
  131. }
  132. post {
  133. always {
  134. // 收集测试结果
  135. junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml'
  136. }
  137. failure {
  138. script {
  139. echo "❌ 编译失败!"
  140. }
  141. }
  142. }
  143. }
  144. stage('构建Docker镜像') {
  145. // ✅ 关键优化:并行构建 3 个服务
  146. parallel {
  147. stage('Gateway') {
  148. steps {
  149. script {
  150. echo ">>> 构建 Gateway 镜像: ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${IMAGE_TAG}"
  151. sh '''
  152. docker build \
  153. --build-arg BUILD_NUMBER=${BUILD_NUMBER_PADDED} \
  154. --build-arg GIT_COMMIT=${GIT_COMMIT_SHORT} \
  155. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:latest \
  156. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${APP_VERSION} \
  157. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${IMAGE_TAG} \
  158. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:latest \
  159. -f shop-recycle-gateway/Dockerfile \
  160. .
  161. '''
  162. }
  163. }
  164. }
  165. stage('OrderService') {
  166. steps {
  167. script {
  168. echo ">>> 构建 OrderService 镜像: ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:${IMAGE_TAG}"
  169. sh '''
  170. docker build \
  171. --build-arg BUILD_NUMBER=${BUILD_NUMBER_PADDED} \
  172. --build-arg GIT_COMMIT=${GIT_COMMIT_SHORT} \
  173. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:latest \
  174. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:${APP_VERSION} \
  175. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:${IMAGE_TAG} \
  176. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:latest \
  177. -f shop-recycle-order-service/Dockerfile \
  178. .
  179. '''
  180. }
  181. }
  182. }
  183. stage('PaymentService') {
  184. steps {
  185. script {
  186. echo ">>> 构建 PaymentService 镜像: ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:${IMAGE_TAG}"
  187. sh '''
  188. docker build \
  189. --build-arg BUILD_NUMBER=${BUILD_NUMBER_PADDED} \
  190. --build-arg GIT_COMMIT=${GIT_COMMIT_SHORT} \
  191. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:latest \
  192. --cache-from ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:${APP_VERSION} \
  193. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:${IMAGE_TAG} \
  194. -t ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:latest \
  195. -f shop-recycle-payment-service/Dockerfile \
  196. .
  197. '''
  198. }
  199. }
  200. }
  201. }
  202. }
  203. stage('镜像安全扫描') {
  204. when {
  205. expression { PUSH_DOCKER == 'true' }
  206. }
  207. steps {
  208. script {
  209. echo ">>> 执行镜像安全扫描..."
  210. sh '''
  211. # 使用 trivy 进行镜像扫描(如果安装)
  212. if command -v trivy &> /dev/null; then
  213. echo "扫描镜像漏洞..."
  214. trivy image --severity HIGH,CRITICAL \
  215. ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${IMAGE_TAG} || true
  216. else
  217. echo "⚠️ Trivy 未安装,跳过镜像扫描"
  218. fi
  219. '''
  220. }
  221. }
  222. }
  223. stage('推送Docker镜像') {
  224. when {
  225. expression { PUSH_DOCKER == 'true' }
  226. }
  227. steps {
  228. script {
  229. echo ">>> 推送 Docker 镜像到 ${DOCKER_REGISTRY}..."
  230. withCredentials([usernamePassword(
  231. credentialsId: 'docker-registry-credentials',
  232. usernameVariable: 'DOCKER_USER',
  233. passwordVariable: 'DOCKER_PASS'
  234. )]) {
  235. sh '''
  236. echo "${DOCKER_PASS}" | docker login -u "${DOCKER_USER}" --password-stdin ${DOCKER_REGISTRY}
  237. # ✅ 优化:并行推送镜像(快 3 倍)
  238. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${IMAGE_TAG} &
  239. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:latest &
  240. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:${IMAGE_TAG} &
  241. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:latest &
  242. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:${IMAGE_TAG} &
  243. docker push ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:latest &
  244. wait
  245. docker logout ${DOCKER_REGISTRY}
  246. echo "✅ 镜像推送完成"
  247. '''
  248. }
  249. }
  250. }
  251. }
  252. }
  253. post {
  254. always {
  255. script {
  256. echo ">>> 清理与报告..."
  257. // 收集构建工件
  258. archiveArtifacts artifacts: '**/target/*.jar',
  259. allowEmptyArchive: true,
  260. fingerprint: true
  261. sh '''
  262. echo "═══════════════════════════════════════"
  263. echo "CI 构建完成"
  264. echo "═══════════════════════════════════════"
  265. echo "镜像TAG: ${IMAGE_TAG}"
  266. docker images | grep shoprecycle | head -6 || true
  267. echo ""
  268. echo "缓存大小:"
  269. du -sh ${WORKSPACE}/.m2/repository 2>/dev/null || echo "Unknown"
  270. '''
  271. }
  272. }
  273. success {
  274. script {
  275. echo "✅ CI 构建成功!"
  276. echo "镜像已准备就绪:"
  277. echo " - ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/gateway:${IMAGE_TAG}"
  278. echo " - ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/order-service:${IMAGE_TAG}"
  279. echo " - ${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/payment-service:${IMAGE_TAG}"
  280. }
  281. }
  282. failure {
  283. script {
  284. echo "❌ CI 构建失败,请检查日志"
  285. sh '''
  286. # 清理失败的镜像
  287. docker images | grep shoprecycle | grep -E "^<none>" | awk '{print $3}' | xargs -r docker rmi -f || true
  288. '''
  289. }
  290. }
  291. cleanup {
  292. sh '''
  293. # ✅ 保留 Maven 缓存用于下次构建(关键优化)
  294. echo "缓存已保留,下次构建会使用"
  295. # 清理 1 周前的临时文件(可选)
  296. find ${WORKSPACE} -type f -name "*.log" -mtime +7 -delete 2>/dev/null || true
  297. '''
  298. }
  299. }
  300. }