Jenkinsfile 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. pipeline {
  2. agent any
  3. parameters {
  4. choice(name: 'env', choices: ['dev', 'test', 'prod'], description: '部署环境(dev/test/prod)')
  5. string(name: 'NAMESPACE', defaultValue: 'device', description: 'Kubernetes 命名空间')
  6. string(name: 'DOMAIN', defaultValue: '', description: 'Ingress 域名(留空则不创建 Ingress)')
  7. }
  8. environment {
  9. PROJECT_NAME = 'device-service'
  10. MODULE_NAME = 'device-service-server'
  11. MAVEN_HOME = '/usr/local/apache-maven-3.9.9/bin'
  12. HARBOR_HOST = '8.130.28.21:81'
  13. KUBECONFIG_PATH = '/root/.kube/config'
  14. NODE1_IP = '172.27.73.147'
  15. NODE2_IP = '172.27.73.146'
  16. HARBOR_USER = 'admin'
  17. HARBOR_PASSWORD = 'Hfln@1024'
  18. SPRING_PROFILES_ACTIVE = "${params.env}"
  19. }
  20. stages {
  21. stage('🧬 拉取 Git 代码') {
  22. steps {
  23. script {
  24. echo ">>> 正在拉取 Git 代码..."
  25. checkout scm
  26. echo ">>> 拉取完成 ✅"
  27. }
  28. }
  29. }
  30. stage('📦 Maven 构建项目') {
  31. steps {
  32. script {
  33. echo ">>> 开始构建模块 ${MODULE_NAME}"
  34. sh "${MAVEN_HOME}/mvn clean package -DskipTests"
  35. echo ">>> 构建完成 ✅"
  36. }
  37. }
  38. }
  39. stage('🐳 构建并推送 Docker 镜像') {
  40. steps {
  41. script {
  42. def imageTag = "${HARBOR_HOST}/${params.env}/${PROJECT_NAME}:${BUILD_NUMBER}"
  43. echo ">>> 构建 Docker 镜像: ${imageTag}"
  44. sh """
  45. docker login -u ${HARBOR_USER} -p ${HARBOR_PASSWORD} ${HARBOR_HOST}
  46. docker build --build-arg env=${params.env} -t ${imageTag} .
  47. docker push ${imageTag}
  48. docker rmi ${imageTag}
  49. """
  50. echo ">>> 镜像推送完成 ✅"
  51. }
  52. }
  53. }
  54. stage('🔍 测试节点能否拉取镜像') {
  55. steps {
  56. script {
  57. def imageTag = "${HARBOR_HOST}/${params.env}/${PROJECT_NAME}:${BUILD_NUMBER}"
  58. echo ">>> 测试节点能否拉取镜像..."
  59. sh """
  60. ssh root@${NODE1_IP} docker login -u ${HARBOR_USER} -p ${HARBOR_PASSWORD} ${HARBOR_HOST} && docker pull ${imageTag} || echo '[❌ 节点 node1 拉取失败]'
  61. ssh root@${NODE2_IP} docker login -u ${HARBOR_USER} -p ${HARBOR_PASSWORD} ${HARBOR_HOST} && docker pull ${imageTag} || echo '[❌ 节点 node2 拉取失败]'
  62. """
  63. }
  64. }
  65. }
  66. stage('🚀 部署到 Kubernetes') {
  67. steps {
  68. script {
  69. def imageTag = "${HARBOR_HOST}/${params.env}/${PROJECT_NAME}:${BUILD_NUMBER}"
  70. def domain = params.DOMAIN.trim()
  71. def ingressBlock = domain ? """
  72. ---
  73. apiVersion: networking.k8s.io/v1
  74. kind: Ingress
  75. metadata:
  76. name: ${PROJECT_NAME}
  77. annotations:
  78. nginx.ingress.kubernetes.io/rewrite-target: /
  79. spec:
  80. rules:
  81. - host: ${domain}
  82. http:
  83. paths:
  84. - path: /
  85. pathType: Prefix
  86. backend:
  87. service:
  88. name: ${PROJECT_NAME}
  89. port:
  90. number: 80
  91. """ : ""
  92. echo ">>> 开始部署至 Kubernetes 命名空间:${params.NAMESPACE}"
  93. sh """
  94. export KUBECONFIG=${KUBECONFIG_PATH}
  95. kubectl get ns ${params.NAMESPACE} || kubectl create ns ${params.NAMESPACE}
  96. kubectl apply -n ${params.NAMESPACE} -f - <<EOF
  97. apiVersion: apps/v1
  98. kind: Deployment
  99. metadata:
  100. name: ${PROJECT_NAME}
  101. spec:
  102. replicas: 2
  103. selector:
  104. matchLabels:
  105. app: ${PROJECT_NAME}
  106. template:
  107. metadata:
  108. labels:
  109. app: ${PROJECT_NAME}
  110. spec:
  111. containers:
  112. - name: ${PROJECT_NAME}
  113. image: ${imageTag}
  114. ports:
  115. - containerPort: 8092
  116. env:
  117. - name: SPRING_PROFILES_ACTIVE
  118. value: "${params.env}"
  119. ---
  120. apiVersion: v1
  121. kind: Service
  122. metadata:
  123. name: ${PROJECT_NAME}
  124. spec:
  125. type: NodePort
  126. selector:
  127. app: ${PROJECT_NAME}
  128. ports:
  129. - port: 80
  130. targetPort: 8092
  131. nodePort: 30086
  132. ${ingressBlock}
  133. EOF
  134. """
  135. if (domain) {
  136. echo ">>> ✅ 部署完成,访问地址:http://${domain}/"
  137. } else {
  138. echo ">>> ✅ 部署完成,访问地址:http://${NODE1_IP}:30085/"
  139. }
  140. }
  141. }
  142. }
  143. }
  144. post {
  145. success {
  146. echo "✅ 构建 & 部署成功 🎉"
  147. script {
  148. echo "🧹 清理本地旧镜像(保留最近 3 个)"
  149. sh """
  150. docker images --format '{{.Repository}}:{{.Tag}} {{.CreatedAt}}' | \
  151. grep '${HARBOR_HOST}/${params.env}/${PROJECT_NAME}:' | \
  152. sort -rk2 | \
  153. tail -n +4 | \
  154. awk '{print \$1}' | \
  155. xargs -r docker rmi || true
  156. """
  157. }
  158. }
  159. failure {
  160. echo "❌ 构建或部署失败,请检查日志。"
  161. }
  162. always {
  163. echo "🧼 清理 Jenkins 工作目录..."
  164. cleanWs()
  165. }
  166. }
  167. }