CD - Deploy Production #157
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CD - Deploy Production | |
| on: | |
| workflow_run: | |
| workflows: ["CI - Build, Test & Push"] | |
| types: [completed] | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| image_tag: | |
| description: 'Image tag cần deploy' | |
| required: false | |
| default: 'latest' | |
| force_restart: | |
| description: 'Force down toàn bộ stack trước khi deploy' | |
| required: false | |
| type: boolean | |
| default: false | |
| concurrency: | |
| group: deploy-production | |
| cancel-in-progress: false | |
| env: | |
| APP_DIR: /home/bdc_web/codespace/bdc_deploy | |
| jobs: | |
| gate: | |
| name: 🔍 Kiểm tra điều kiện | |
| runs-on: ubuntu-latest | |
| outputs: | |
| ok: ${{ steps.check.outputs.ok }} | |
| tag: ${{ steps.check.outputs.tag }} | |
| steps: | |
| - name: Evaluate | |
| id: check | |
| run: | | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| echo "ok=true" >> $GITHUB_OUTPUT | |
| echo "tag=${{ github.event.inputs.image_tag || 'latest' }}" >> $GITHUB_OUTPUT | |
| echo "✅ Manual trigger" | |
| elif [[ "${{ github.event.workflow_run.conclusion }}" == "success" ]]; then | |
| echo "ok=true" >> $GITHUB_OUTPUT | |
| echo "tag=latest" >> $GITHUB_OUTPUT | |
| echo "✅ CI passed" | |
| else | |
| echo "ok=false" >> $GITHUB_OUTPUT | |
| echo "tag=latest" >> $GITHUB_OUTPUT | |
| echo "⏭️ CI không pass (${{ github.event.workflow_run.conclusion }}) - skip" | |
| fi | |
| deploy: | |
| name: 🚀 Deploy Production | |
| runs-on: [self-hosted, linux, production, deploy] | |
| needs: gate | |
| if: needs.gate.outputs.ok == 'true' | |
| environment: | |
| name: production | |
| url: https://bdc.hpcc.vn | |
| steps: | |
| - name: Checkout deployment configuration only | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| clean: true | |
| sparse-checkout: | | |
| server | |
| - name: Synchronize configuration files | |
| run: | | |
| mkdir -p ${{ env.APP_DIR }} | |
| rsync -av --exclude='.env' ./server/ ${{ env.APP_DIR }}/ | |
| - name: Cleanup runner workspace code | |
| run: | | |
| rm -rf * .* || true | |
| - name: Force stop stack | |
| if: ${{ github.event.inputs.force_restart == 'true' }} | |
| run: | | |
| cd ${{ env.APP_DIR }} | |
| echo "🔴 Force restart - dừng toàn bộ stack..." | |
| docker compose -f docker-compose.serverless.yml down --remove-orphans --timeout 30 | |
| echo "✅ Đã dừng" | |
| - name: Deploy | |
| run: | | |
| cd ${{ env.APP_DIR }} | |
| bash deploy.sh | |
| - name: Health check | |
| run: | | |
| echo "⏳ Chờ services ổn định (15s)..." | |
| sleep 15 | |
| FAILED=0 | |
| _check() { | |
| if curl -sf --max-time 10 "$1" > /dev/null 2>&1; then | |
| echo "✅ $2" | |
| else | |
| echo "❌ $2 ($1)" | |
| FAILED=1 | |
| fi | |
| } | |
| _check "http://localhost:3000/api/health" "Frontend" | |
| _check "http://localhost:8080/actuator/health" "auth-and-management-service" | |
| _check "http://localhost:8081/health" "lms-service" | |
| if [[ $FAILED -eq 1 ]]; then | |
| echo "" | |
| echo "Container status:" | |
| docker compose -f ${{ env.APP_DIR }}/docker-compose.serverless.yml ps | |
| exit 1 | |
| fi | |
| echo "✅ Tất cả healthy!" | |
| - name: Docker logout | |
| if: always() | |
| run: docker logout || true | |
| - name: Summary | |
| if: always() | |
| run: | | |
| STATUS="${{ job.status }}" | |
| [[ "$STATUS" == "success" ]] && ICON="✅" || ICON="❌" | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| ## ${ICON} Deploy ${STATUS} | |
| | | | | |
| |---|---| | |
| | **URL** | https://bdc.hpcc.vn | | |
| | **Tag** | \`${{ needs.gate.outputs.tag }}\` | | |
| | **Commit** | \`${{ github.sha }}\` | | |
| | **Time** | $(date '+%Y-%m-%d %H:%M:%S %Z') | | |
| \`\`\` | |
| $(docker compose -f ${{ env.APP_DIR }}/docker-compose.serverless.yml ps 2>&1 || true) | |
| \`\`\` | |
| EOF |