Jenkinsfile 13.6 KB
pipeline {
    agent {
        label 'jenkins-agent'
    }
    
    tools {
        maven 'maven-3.9.10'
    }
    
    environment {
        AWS_ACCOUNT_ID = '319998871902'
        AWS_REGION = 'us-east-1'
        ECR_REPO = "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/user-management"
        CLUSTER_NAME = 'comic-website-prod'
        KUBE_NAMESPACE = 'user-management'
        DOCKER_IMAGE = "${ECR_REPO}:${env.BUILD_NUMBER}"
        APP_NAME = "user-management-system"
        VPC_NAME = "comic-website-prod-vpc"  
        TERRAFORM_DIR = "terraform-api-gateway"
    }
    
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
        timeout(time: 45, unit: 'MINUTES')
        disableConcurrentBuilds()
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
                sh '''
                    echo "=== 代码信息 ==="
                    echo "仓库: ${GIT_URL}"
                    echo "分支: ${GIT_BRANCH}"
                    echo "Commit: ${GIT_COMMIT}"
                    git log -1 --oneline
                '''
            }
        }
        
        stage('Build Application') {
            steps {
                sh '''
                    echo "=== 开始构建应用 ==="
                    echo "Maven 版本:"
                    mvn --version
                    mvn clean package -DskipTests=true
                    echo "构建完成!"
                '''
            }
        }
        
        stage('Docker Build') {
            steps {
                script {
                    echo "=== 构建 Docker 镜像 ==="
                    sh 'docker --version'
                    docker.build("${DOCKER_IMAGE}")
                }
            }
        }
        
        stage('Docker Push to ECR') {
            steps {
                script {
                    withCredentials([[
                        $class: 'AmazonWebServicesCredentialsBinding',
                        credentialsId: 'dev-user-aws-credentials',
                        accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                        secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                    ]]) {
                        sh """
                            echo "=== 推送镜像到 ECR ==="
                            
                            # 检查 ECR 仓库是否存在,不存在则创建
                            if ! aws ecr describe-repositories --repository-names user-management --region ${AWS_REGION} > /dev/null 2>&1; then
                                echo "创建 ECR 仓库..."
                                aws ecr create-repository --repository-name user-management --region ${AWS_REGION}
                            fi
                            
                            # 登录 ECR
                            aws ecr get-login-password --region ${AWS_REGION} | \
                            docker login --username AWS --password-stdin ${ECR_REPO}
                            
                            # 推送构建版本
                            echo "推送镜像: ${DOCKER_IMAGE}"
                            docker push ${DOCKER_IMAGE}
                            
                            # 推送 latest 标签
                            echo "推送 latest 标签"
                            docker tag ${DOCKER_IMAGE} ${ECR_REPO}:latest
                            docker push ${ECR_REPO}:latest
                            
                            echo "镜像推送完成!"
                        """
                    }
                }
            }
        }
        
        stage('Deploy to EKS') {
            steps {
                script {
                    withCredentials([[
                        $class: 'AmazonWebServicesCredentialsBinding',
                        credentialsId: 'dev-user-aws-credentials',
                        accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                        secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                    ]]) {
                        sh """
                            echo "=== 部署应用到 EKS ==="
                            
                            # 配置 kubeconfig
                            aws eks update-kubeconfig \
                                --region ${AWS_REGION} \
                                --name ${CLUSTER_NAME}
                            
                            echo "当前集群:"
                            kubectl config current-context
                        """
                        
                        // 部署命名空间
                        sh """
                            kubectl apply -f k8s/namespace.yaml
                        """
                        
                        // 部署数据库
                        sh """
                            echo "部署数据库..."
                            kubectl apply -f k8s/database/ -n ${KUBE_NAMESPACE}
                            
                            # 等待数据库就绪
                            echo "等待数据库启动..."
                            sleep 60
                        """
                        
                        // 部署应用
                        sh """
                            echo "部署应用..."
                            kubectl apply -f k8s/application/ -n ${KUBE_NAMESPACE}
                        """
                        
                        // 部署 NLB Service
                        sh """
                            echo "部署 NLB Service..."
                            kubectl apply -f k8s/networking/nlb-service.yaml -n ${KUBE_NAMESPACE}
                            
                            # 等待 NLB 创建
                            echo "等待 NLB 创建..."
                            sleep 30
                        """
                        
                        // 更新镜像
                        sh """
                            echo "更新应用镜像..."
                            kubectl set image deployment/user-management-app \
                                user-management-app=${DOCKER_IMAGE} \
                                -n ${KUBE_NAMESPACE}
                        """
                        
                        // 等待部署完成
                        sh """
                            echo "等待部署完成..."
                            kubectl rollout status deployment/user-management-app \
                                -n ${KUBE_NAMESPACE} --timeout=600s
                        """
                        
                        // 显示部署状态
                        sh """
                            echo "=== 部署状态 ==="
                            echo "Pods:"
                            kubectl get pods -n ${KUBE_NAMESPACE} -o wide
                            echo ""
                            echo "Services:"
                            kubectl get service -n ${KUBE_NAMESPACE}
                            echo ""
                            echo "NLB Service 状态:"
                            kubectl get svc user-management-nlb -n ${KUBE_NAMESPACE} -o wide
                            echo ""
                            echo "💡 架构: 用户 → NLB → EKS Pods"
                        """
                    }
                }
            }
        }
        
        stage('Health Check') {
            steps {
                script {
                    echo "=== 健康检查 ==="
                    
                    // 动态获取 NLB DNS 进行健康检查
                    def NLB_DNS = sh(
                        script: "kubectl get svc user-management-nlb -n ${KUBE_NAMESPACE} -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'",
                        returnStdout: true
                    ).trim()
                    
                    sh """
                        echo "通过 NLB 进行健康检查..."
                        echo "NLB DNS: ${NLB_DNS}"
                        echo "测试健康检查端点..."
                        curl -s http://${NLB_DNS}/api/health || echo "健康检查请求失败"
                    """
                    
                    // 保存 NLB DNS 到环境变量供后续使用
                    env.NLB_DNS = NLB_DNS
                }
            }
        }

        // ========== 部署 API Gateway ==========
        stage('Deploy API Gateway(Terraform)') {
            steps {
                script {
                    withCredentials([[
                        $class: 'AmazonWebServicesCredentialsBinding',
                        credentialsId: 'dev-user-aws-credentials',
                        accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                        secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                    ]]) {
                        dir("${TERRAFORM_DIR}") {
                            sh """
                                echo "=== 部署 API Gateway ==="
                                
                                # 显示当前 Terraform 文件
                                echo "=== Terraform 文件列表 ==="
                                ls -la
                                echo ""
                                echo "=== terraform.tfvars 内容 ==="
                                cat terraform.tfvars || echo "无法读取 terraform.tfvars"
                                
                                echo "初始化 Terraform..."
                                terraform init -input=false
                                
                                echo "执行 Terraform Plan..."
                                terraform plan -input=false
                                
                                echo "应用 Terraform 配置..."
                                terraform apply -auto-approve -input=false
                                
                                echo "获取输出信息..."
                                terraform output -json > tf_output.json
                                
                                # 保存 API Gateway URL 到文件,供后续阶段使用
                                terraform output -raw api_gateway_invoke_url > ../api_gateway_url.txt 2>/dev/null || echo "无法获取 API Gateway URL"
                            """
                            
                            // 读取 Terraform 输出
                            def tfOutput = readJSON file: 'tf_output.json'
                            env.API_GATEWAY_URL = tfOutput.api_gateway_invoke_url?.value ?: ""
                        }
                    }
                }
            }
        }
    }
    
    post {
        always {
            script {
                cleanWs()
                currentBuild.description = "Build ${env.BUILD_NUMBER}"
                
                echo "=========================================="
                echo "构建结果: ${currentBuild.result}"
                echo "构建号: ${env.BUILD_NUMBER}"
                echo "=========================================="
            }
        }
        success {
            script {
                echo "🎉 部署成功!"
                
                // 安全地获取 NLB DNS(如果 Health Check 阶段失败)
                def NLB_DNS = env.NLB_DNS ?: sh(
                    script: "kubectl get svc user-management-nlb -n ${KUBE_NAMESPACE} -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo 'NLB_NOT_AVAILABLE'",
                    returnStdout: true
                ).trim()
                
                // 安全地获取 API Gateway URL
                def API_GATEWAY_URL = ""
                try {
                    if (fileExists('api_gateway_url.txt')) {
                        API_GATEWAY_URL = readFile('api_gateway_url.txt').trim()
                    } else if (env.API_GATEWAY_URL) {
                        API_GATEWAY_URL = env.API_GATEWAY_URL
                    } else {
                        API_GATEWAY_URL = "API_GATEWAY_NOT_DEPLOYED"
                    }
                } catch (Exception e) {
                    API_GATEWAY_URL = "API_GATEWAY_NOT_DEPLOYED"
                }
                
                // 构建输出信息
                def message = """
📦 应用已部署到 EKS
🌐 NLB 地址: https://${NLB_DNS}
"""
                
                if (API_GATEWAY_URL != "API_GATEWAY_NOT_DEPLOYED" && API_GATEWAY_URL != "") {
                    message += """
🎯 API Gateway 地址: ${API_GATEWAY_URL}

🔗 API Gateway 访问:
   ❤️  健康检查: ${API_GATEWAY_URL}api/health
   👥 用户管理: ${API_GATEWAY_URL}api/users
   📚 API文档: ${API_GATEWAY_URL}swagger-ui.html
"""
                }
                
                message += """
💡 架构说明:
   用户 → NLB → EKS Pods (直接访问)
"""
                
                if (API_GATEWAY_URL != "API_GATEWAY_NOT_DEPLOYED" && API_GATEWAY_URL != "") {
                    message += "   用户 → API Gateway → NLB → EKS Pods"
                }
                
                echo message
                
                // 清理临时文件
                sh "rm -f api_gateway_url.txt || true"
            }
        }
        failure {
            script {
                echo "❌ 部署失败!"
                echo "🔍 详细日志: ${env.BUILD_URL}console"
                
                // 显示错误诊断信息
                sh """
                    echo "=== 错误诊断 ==="
                    echo "Pod 状态:"
                    kubectl get pods -n ${KUBE_NAMESPACE} || true
                    echo ""
                    echo "Service 状态:"
                    kubectl get service -n ${KUBE_NAMESPACE} || true
                """
            }
        }
    }
}