diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 1feb08b..c4f2a02 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,50 +1,147 @@ name: 构建并部署 Spring Boot 应用 -on: [push] + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] jobs: build-and-deploy: - container: - image: maven:3.8.6-openjdk-17 - options: --pull=always - - runs-on: ubuntu-24.04 # 使用更稳定的标签 - + 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: 使用 Maven 打包 - run: mvn clean package -DskipTests + - name: 运行测试 + run: mvn test - - name: 验证构建结果 - run: ls -la target/*.jar - - - name: 构建 Docker 镜像 - run: docker build -t light-delivery-app:latest . - - - name: 部署到服务器 - env: - SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} - SERVER_IP: ${{ secrets.SERVER_IP }} + - name: 使用 Jib 构建到本地 Docker run: | - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key - chmod 600 ~/.ssh/deploy_key - ssh-keyscan $SERVER_IP >> ~/.ssh/known_hosts + # 使用 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 - ssh -i ~/.ssh/deploy_key root@$SERVER_IP ' - docker stop light-delivery-container || true - docker rm light-delivery-container || true - docker run -d \ - --name light-delivery-container \ - -p 443:443 -p 80:80 \ - -v /etc/ssl/certs:/etc/ssl/certs:ro \ - -e KEY_STORE_PASSWORD="$(cat /etc/ssl/certs/keyStorePass.txt)" \ - light-delivery-app:latest - ' \ No newline at end of file + 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}}')" \ No newline at end of file