pipeline { agent { kubernetes { yaml ''' apiVersion: v1 kind: Pod spec: serviceAccountName: jenkins containers: - name: kaniko image: gcr.io/kaniko-project/executor:v1.23.2-debug command: ["sleep"] args: ["999999"] volumeMounts: - name: docker-config mountPath: /kaniko/.docker - name: kubectl image: rancher/kubectl:v1.34.9 command: ["sleep"] args: ["999999"] volumes: - name: docker-config secret: secretName: harbor-dockerconfig items: - key: .dockerconfigjson path: config.json ''' } } options { timestamps() buildDiscarder(logRotator(numToKeepStr: '10')) timeout(time: 20, unit: 'MINUTES') } environment { REGISTRY = 'harbor.nineleaves.cn' IMAGE = 'harbor.nineleaves.cn/apps/blog' NS = 'apps' } stages { stage('准备') { steps { echo "构建号 #${env.BUILD_NUMBER},分支 ${env.BRANCH_NAME ?: 'main'}" sh 'ls -la' } } stage('构建镜像并推送 Harbor') { steps { container('kaniko') { sh ''' set -e TAG="build-${BUILD_NUMBER}" echo "开始构建 ${IMAGE}:${TAG}" /kaniko/executor \ --context=dir://${WORKSPACE} \ --dockerfile=${WORKSPACE}/Dockerfile \ --destination=${IMAGE}:${TAG} \ --destination=${IMAGE}:latest \ --skip-tls-verify \ --skip-tls-verify-pull \ --cache=false \ --verbosity=info echo "镜像已推送: ${IMAGE}:${TAG}" ''' } } } stage('部署到 Kubernetes') { steps { container('kubectl') { sh ''' set -e TAG="build-${BUILD_NUMBER}" kubectl apply -f ${WORKSPACE}/k8s/deployment.yaml kubectl -n ${NS} set image deployment/blog blog=${IMAGE}:${TAG} kubectl -n ${NS} rollout status deployment/blog --timeout=180s kubectl -n ${NS} get pods -l app=blog ''' } } } stage('冒烟测试') { steps { container('kubectl') { sh ''' set -e for i in $(seq 1 20); do CODE=$(kubectl -n apps run smoke-$$ --rm -i --restart=Never \ --image=curlimages/curl:8.10.1 --quiet -- \ -s -o /dev/null -w "%{http_code}" http://blog/healthz 2>/dev/null || echo 000) if [ "$CODE" = "200" ]; then echo "健康检查通过"; exit 0; fi echo "第 $i 次: $CODE, 等待中..."; sleep 3 done echo "健康检查失败"; exit 1 ''' } } } } post { success { echo "✅ 部署成功:https://blog.nineleaves.cn" } failure { echo "❌ 流水线失败,查看上面的日志" } } }