Skip to content

CD - Deploy Production #157

CD - Deploy Production

CD - Deploy Production #157

Workflow file for this run

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