Jenkinsfile 13.4 KB
pipeline {
    agent {
        label 'jenkins-agent'
    }

    environment {
        // AWS Configuration
        AWS_ACCOUNT_ID = '319998871902'
        AWS_REGION = 'us-east-1'
        EKS_CLUSTER_NAME = 'comic-website-prod'
        DOCKER_REGISTRY = "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
        
        // Project Configuration
        PROJECT_NAME = 'ecommerce'
        NAMESPACE = 'ecommerce'
        
        // Docker Images
        FRONTEND_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-frontend"
        USER_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-user-service"
        PRODUCT_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-product-service"
        ORDER_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-order-service"
        PAYMENT_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-payment-service"
        INVENTORY_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-inventory-service"
        NOTIFICATION_SERVICE_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}-notification-service"
        
        // Versioning
        BUILD_VERSION = "${env.BUILD_NUMBER}"
        DOCKER_TAG = "${BUILD_VERSION}-${env.GIT_COMMIT.substring(0, 7)}"
        
        // Java Configuration
        JAVA_HOME = "/opt/java/openjdk"
    }

    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
        timeout(time: 60, unit: 'MINUTES')
        disableConcurrentBuilds()
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
                script {
                    currentBuild.displayName = "#${BUILD_VERSION}"
                    currentBuild.description = "Commit: ${env.GIT_COMMIT}"
                }
            }
        }

        stage('Setup Environment') {
            steps {
                withCredentials([[
                    $class: 'AmazonWebServicesCredentialsBinding',
                    credentialsId: 'dev-user-aws-credentials',
                    accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                    secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                ]]) {
                    script {
                        sh '''
                            echo "=== Environment Setup ==="
                            echo "Java Home: $JAVA_HOME"
                            echo "Java Version:"
                            java -version
                            echo "Gradle Version:"
                            gradle --version
                            echo "Node Version:"
                            node --version || echo "Node.js not installed"
                            
                            # Configure AWS and EKS
                            aws configure set region ${AWS_REGION}
                            aws configure set output json
                            aws eks update-kubeconfig --region ${AWS_REGION} --name ${EKS_CLUSTER_NAME}
                            
                            echo "Kubernetes cluster info:"
                            kubectl cluster-info
                            
                            echo "Available disk space:"
                            df -h
                            
                            echo "=== Environment setup completed ==="
                        '''
                    }
                }
            }
        }

        stage('Build User Service') {
            steps {
                script {
                    buildServiceSequential('user-service')
                }
            }
        }

        stage('Build Product Service') {
            steps {
                script {
                    buildServiceSequential('product-service')
                }
            }
        }

        stage('Build Order Service') {
            steps {
                script {
                    buildServiceSequential('order-service')
                }
            }
        }

        stage('Build Payment Service') {
            steps {
                script {
                    buildServiceSequential('payment-service')
                }
            }
        }

        stage('Build Inventory Service') {
            steps {
                script {
                    buildServiceSequential('inventory-service')
                }
            }
        }

        stage('Build Notification Service') {
            steps {
                script {
                    buildServiceSequential('notification-service')
                }
            }
        }

        stage('Build Frontend') {
            steps {
                dir('frontend') {
                    sh '''
                        echo "Building Frontend..."
                        npm ci
                        npm run build
                        echo "Frontend build completed"
                    '''
                }
            }
        }

        stage('ECR Login') {
            steps {
                withCredentials([[
                    $class: 'AmazonWebServicesCredentialsBinding',
                    credentialsId: 'dev-user-aws-credentials',
                    accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                    secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                ]]) {
                    script {
                        sh """
                            echo "Logging into ECR..."
                            aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${DOCKER_REGISTRY}
                            echo "✅ ECR login successful"
                        """
                    }
                }
            }
        }

        stage('Docker Build Frontend') {
            steps {
                script {
                    dockerBuildPushSequential('frontend', "${FRONTEND_IMAGE}")
                }
            }
        }

        stage('Docker Build User Service') {
            steps {
                script {
                    dockerBuildPushSequential('user-service', "${USER_SERVICE_IMAGE}")
                }
            }
        }

        stage('Docker Build Product Service') {
            steps {
                script {
                    dockerBuildPushSequential('product-service', "${PRODUCT_SERVICE_IMAGE}")
                }
            }
        }

        stage('Docker Build Order Service') {
            steps {
                script {
                    dockerBuildPushSequential('order-service', "${ORDER_SERVICE_IMAGE}")
                }
            }
        }

        stage('Docker Build Payment Service') {
            steps {
                script {
                    dockerBuildPushSequential('payment-service', "${PAYMENT_SERVICE_IMAGE}")
                }
            }
        }

        stage('Docker Build Inventory Service') {
            steps {
                script {
                    dockerBuildPushSequential('inventory-service', "${INVENTORY_SERVICE_IMAGE}")
                }
            }
        }

        stage('Docker Build Notification Service') {
            steps {
                script {
                    dockerBuildPushSequential('notification-service', "${NOTIFICATION_SERVICE_IMAGE}")
                }
            }
        }

        stage('Deploy to EKS') {
            steps {
                withCredentials([[
                    $class: 'AmazonWebServicesCredentialsBinding',
                    credentialsId: 'dev-user-aws-credentials',
                    accessKeyVariable: 'AWS_ACCESS_KEY_ID',
                    secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
                ]]) {
                    script {
                        sh """
                            echo "🚀 Starting deployment to EKS..."
                            
                            # Update kubeconfig
                            aws eks update-kubeconfig --region ${AWS_REGION} --name ${EKS_CLUSTER_NAME}
                            
                            # Create namespace if not exists
                            kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
                            
                            echo "Deploying databases..."
                            kubectl apply -f kubernetes/databases/ -n ${NAMESPACE} || echo "No databases configuration found"
                            
                            echo "Deploying message queue..."
                            kubectl apply -f kubernetes/message-queue/ -n ${NAMESPACE} || echo "No message queue configuration found"
                            
                            echo "Deploying microservices..."
                            kubectl apply -f kubernetes/microservices/ -n ${NAMESPACE}
                            
                            echo "Deploying frontend..."
                            kubectl apply -f kubernetes/frontend/ -n ${NAMESPACE}
                            
                            echo "Deploying networking..."
                            kubectl apply -f kubernetes/networking/ -n ${NAMESPACE} || echo "No networking configuration found"
                            
                            echo "✅ Deployment completed!"
                            
                            # Wait for deployments to be ready
                            echo "Waiting for deployments to be ready..."
                            sleep 30
                            
                            # Check deployment status
                            echo "Current pod status:"
                            kubectl get pods -n ${NAMESPACE} --sort-by='.metadata.creationTimestamp'
                            
                            # Show services
                            echo "Services:"
                            kubectl get services -n ${NAMESPACE}
                        """
                    }
                }
            }
        }
    }

    post {
        always {
            // Archive build artifacts
            archiveArtifacts artifacts: '**/build/libs/*.jar', fingerprint: true
            
            // Clean up Docker to free space
            sh '''
                echo "Cleaning up Docker resources..."
                docker system prune -f || true
                echo "Cleanup completed"
            '''
            
            // Log disk space after build
            sh '''
                echo "Disk space after build:"
                df -h
            '''
        }
        success {
            echo "🎉 Build and deployment successful!"
            sh '''
                echo "✅ All tasks completed successfully"
                echo "📊 Final resource usage:"
                df -h
                echo "🚀 Application deployed successfully!"
            '''
        }
        failure {
            echo "❌ Build failed! Check the logs for details."
            sh '''
                echo "💡 Troubleshooting tips:"
                echo "1. Check disk space: df -h"
                echo "2. Check Docker: docker system df"
                echo "3. Check Gradle cache: du -sh ~/.gradle/"
                echo "4. Check Kubernetes resources: kubectl get pods -n ecommerce"
            '''
        }
    }
}

// 串行构建微服务的函数
def buildServiceSequential(serviceName) {
    echo "🔨 Building ${serviceName}..."
    dir("microservices/${serviceName}") {
        // 添加重试机制和资源监控
        retry(2) {
            sh """
                echo "=== Starting Gradle build for ${serviceName} ==="
                echo "Current directory: \$(pwd)"
                echo "Java version:"
                java -version
                echo "Gradle version:"
                gradle --version
                
                # 清理 Gradle 缓存以防万一
                echo "Cleaning project..."
                gradle clean --no-daemon
                
                # 构建项目(跳过测试以减少资源使用)
                echo "Building project..."
                gradle build -x test --no-daemon --stacktrace
                
                echo "✅ ${serviceName} build completed"
                echo "Build artifacts:"
                ls -la build/libs/
            """
        }
    }
    echo "✅ ${serviceName} build completed successfully"
}

// 串行构建和推送 Docker 镜像的函数
def dockerBuildPushSequential(serviceDir, imageName) {
    echo "🐳 Building and pushing Docker image for ${serviceDir}..."
    
    def contextDir = serviceDir == 'frontend' ? 'frontend' : "microservices/${serviceDir}"
    
    dir(contextDir) {
        retry(2) {
            sh """
                echo "=== Building Docker image: ${imageName}:${DOCKER_TAG} ==="
                echo "Build context: \$(pwd)"
                
                # 检查 Dockerfile 是否存在
                echo "Checking for Dockerfile..."
                ls -la Dockerfile || echo "Dockerfile not found, listing all files:"
                ls -la
                
                # 构建 Docker 镜像
                echo "Building Docker image..."
                docker build -t ${imageName}:${DOCKER_TAG} .
                
                # 推送 Docker 镜像
                echo "Pushing Docker image to ECR..."
                docker push ${imageName}:${DOCKER_TAG}
                
                echo "✅ ${serviceDir} Docker image pushed successfully"
                
                # 清理本地镜像以节省空间
                echo "Cleaning up local Docker image..."
                docker rmi ${imageName}:${DOCKER_TAG} || true
                
                echo "=== ${serviceDir} Docker build completed ==="
            """
        }
    }
}