name: Deploy to Production on: push: branches: [main] tags: ['v*'] pull_request: branches: [main] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: name: Run Tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: rustfmt, clippy - name: Cache dependencies uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Check formatting run: cargo fmt -- --check - name: Run clippy run: cargo clippy -- -D warnings - name: Run tests run: cargo test --verbose - name: Run integration tests run: cargo test --test integration_tests --verbose security-scan: name: Security Scan runs-on: ubuntu-latest needs: test steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: Install cargo-audit run: cargo install cargo-audit - name: Run security audit run: cargo audit - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: 'trivy-results.sarif' build: name: Build Docker Image runs-on: ubuntu-latest needs: [test, security-scan] if: github.event_name == 'push' outputs: image: ${{ steps.image.outputs.image }} digest: ${{ steps.build.outputs.digest }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix={{branch}}- - name: Build and push Docker image id: build uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - name: Output image id: image run: | echo "image=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" >> $GITHUB_OUTPUT deploy-staging: name: Deploy to Staging runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' environment: staging steps: - name: Checkout code uses: actions/checkout@v4 - name: Deploy to staging run: | echo "Deploying to staging environment..." echo "Image: ${{ needs.build.outputs.image }}" # 这里添加实际的部署逻辑 # 例如: kubectl set image deployment/rust-api rust-api=${{ needs.build.outputs.image }} deploy-production: name: Deploy to Production runs-on: ubuntu-latest needs: [build, deploy-staging] if: startsWith(github.ref, 'refs/tags/v') environment: production steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup SSH uses: webfactory/ssh-agent@v0.7.0 with: ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }} - name: Deploy to production run: | ssh -o StrictHostKeyChecking=no ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} << 'EOF' cd /opt/rust-api # 备份当前数据库 docker-compose -f docker-compose.prod.yml exec -T rust-user-api \ sqlite3 /app/data/production.db ".backup /app/data/backup-$(date +%Y%m%d-%H%M%S).db" # 拉取最新镜像 docker pull ${{ needs.build.outputs.image }} # 更新docker-compose文件中的镜像标签 sed -i 's|image: .*|image: ${{ needs.build.outputs.image }}|' docker-compose.prod.yml # 重新部署 docker-compose -f docker-compose.prod.yml up -d # 等待服务启动 sleep 30 # 健康检查 if curl -f http://localhost/health; then echo "✅ 部署成功!" else echo "❌ 部署失败,开始回滚..." docker-compose -f docker-compose.prod.yml down # 这里可以添加回滚逻辑 exit 1 fi EOF - name: Notify deployment success if: success() run: | echo "🎉 生产环境部署成功!" echo "版本: ${{ github.ref_name }}" echo "镜像: ${{ needs.build.outputs.image }}" notify: name: Notify Results runs-on: ubuntu-latest needs: [test, security-scan, build, deploy-production] if: always() steps: - name: Notify on success if: ${{ needs.deploy-production.result == 'success' }} run: | echo "✅ 部署流水线执行成功" # 这里可以添加通知逻辑,如发送邮件、Slack消息等 - name: Notify on failure if: ${{ contains(needs.*.result, 'failure') }} run: | echo "❌ 部署流水线执行失败" # 这里可以添加失败通知逻辑