name: 构建并部署 Spring Boot 应用 on: push: branches: [master, develop] pull_request: branches: [master, develop] jobs: build-and-deploy: runs-on: ubuntu-latest # 使用自托管 Runner steps: - name: 检出代码 uses: actions/checkout@v4.1.1 with: fetch-depth: 0 - name: 从本地服务器下载并安装 JDK 17 run: | echo "开始从本地服务器下载 JDK..." wget http://115.190.121.151:8081/openjdk-17.0.2_linux-x64_bin.tar.gz -O jdk.tar.gz # 验证下载文件 if [ ! -f jdk.tar.gz ]; then echo "❌ JDK 下载失败" exit 1 fi echo "解压并安装 JDK..." sudo mkdir -p /opt/java sudo tar -xzf jdk.tar.gz -C /opt/java --strip-components=1 echo "设置环境变量..." echo "JAVA_HOME=/opt/java" >> $GITHUB_ENV echo "/opt/java/bin" >> $GITHUB_PATH # 清理临时文件 rm -f jdk.tar.gz echo "✅ JDK 安装完成" - name: 验证 Java 安装 run: | echo "验证 Java 安装:" java -version javac -version echo "JAVA_HOME: $JAVA_HOME" echo "PATH: $PATH" - name: 验证环境 run: | echo "Runner 工作目录: $(pwd)" echo "Docker 信息:" docker --version if ! docker info >/dev/null 2>&1; then echo "❌ Docker 守护进程不可访问" exit 1 else echo "✅ Docker 守护进程可访问" docker info fi 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 clean package -DskipTests ls -la target/ - name: 运行测试 run: mvn test - name: 构建 Docker 镜像 run: | # 使用 Dockerfile 构建镜像 docker build -t light-delivery-app:latest . - 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 compose -f deploy.yml up -d - name: 等待应用启动并健康检查 run: | echo "等待应用启动..." # 最大重试次数 MAX_RETRIES=12 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do # 使用正确的端口 (8443) 和协议 (HTTPS),不跳过SSL验证 if curl -f -s https://localhost:8443/actuator/health > /dev/null 2>&1; then echo "✅ 应用健康检查通过" # 获取详细的健康信息 HEALTH_INFO=$(curl -s https://localhost:8443/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}}')"