name: 构建并部署 Spring Boot 应用 on: push: branches: [main, develop] pull_request: branches: [main] jobs: build-and-deploy: runs-on: self-hosted # 使用自托管 Runner steps: - name: 检出代码 uses: actions/checkout@v4 with: fetch-depth: 0 - name: 设置 JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: 'maven' - name: 验证环境 run: | echo "Runner 工作目录: $(pwd)" echo "Docker 信息:" docker --version docker info echo "Maven 信息:" mvn --version - name: 缓存 Maven 依赖 uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: 运行测试 run: mvn test - name: 使用 Jib 构建到本地 Docker run: | # 使用 Jib 直接构建到本地 Docker 守护进程 # 这会利用 Jib 的分层缓存机制,后续构建会更快 mvn compile jib:dockerBuild -DskipTests \ -Djib.to.image=light-delivery-app:latest \ -Djib.container.ports=8080,8443 \ -Djib.container.environment.SPRING_PROFILES_ACTIVE=prod \ -Djib.container.jvmFlags=-Xmx512m,-Xms256m - name: 验证镜像构建 run: | echo "构建的 Docker 镜像:" docker images | grep light-delivery-app echo "镜像详情:" docker inspect light-delivery-app:latest --format='Size: {{.Size}} bytes, Created: {{.Created}}' - name: 停止旧容器 run: | # 优雅停止旧容器 docker stop light-delivery-container 2>/dev/null || echo "没有运行中的容器" docker rm light-delivery-container 2>/dev/null || echo "没有可删除的容器" - name: 备份当前镜像(可选) run: | # 为当前运行中的镜像创建备份标签 if docker images light-delivery-app:latest --quiet | grep -q .; then BACKUP_TAG="backup-$(date +%Y%m%d-%H%M%S)" docker tag light-delivery-app:latest light-delivery-app:$BACKUP_TAG echo "已创建备份: light-delivery-app:$BACKUP_TAG" fi - name: 运行新容器 run: | # 创建必要的目录 sudo mkdir -p /app/logs sudo mkdir -p /etc/ssl/certs sudo chown $USER:$USER /app/logs 2>/dev/null || true echo "启动新容器..." docker run -d \ --name light-delivery-container \ --restart=unless-stopped \ --log-opt max-size=10m \ --log-opt max-file=3 \ -p 8080:8080 \ -p 8443:8443 \ -e SPRING_PROFILES_ACTIVE=prod \ -e JAVA_OPTS="-Xmx512m -Xms256m -Djava.security.egd=file:/dev/./urandom" \ -v /app/logs:/app/logs \ -v /etc/ssl/certs:/etc/ssl/certs:ro \ -e SERVER_SSL_KEY_STORE_PASSWORD="${{ secrets.KEY_STORE_PASSWORD }}" \ light-delivery-app:latest - name: 等待应用启动并健康检查 run: | echo "等待应用启动..." # 最大重试次数 MAX_RETRIES=12 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do if curl -f -s http://localhost:8080/actuator/health > /dev/null 2>&1; then echo "✅ 应用健康检查通过" # 获取详细的健康信息 HEALTH_INFO=$(curl -s http://localhost:8080/actuator/health) echo "健康状态: $HEALTH_INFO" break fi RETRY_COUNT=$((RETRY_COUNT + 1)) echo "健康检查失败 ($RETRY_COUNT/$MAX_RETRIES),10秒后重试..." sleep 10 done if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then echo "❌ 应用启动超时,查看日志:" docker logs light-delivery-container --tail 50 exit 1 fi - name: 清理资源 run: | # 清理旧的备份镜像(保留最近5个) echo "清理旧的备份镜像..." docker images light-delivery-app --filter "reference=light-delivery-app:backup-*" \ --format "{{.Tag}}\t{{.CreatedAt}}" | \ sort -k2 -r | \ tail -n +6 | \ awk '{print $1}' | \ xargs -r -I {} docker rmi light-delivery-app:{} || echo "无需清理" # 清理无用镜像和容器 docker system prune -f - name: 部署完成通知 run: | echo "🎉 部署完成!" echo "应用运行在: http://localhost:8080" echo "容器状态: $(docker inspect light-delivery-container --format='{{.State.Status}}')" echo "启动时间: $(docker inspect light-delivery-container --format='{{.State.StartedAt}}')"