Deploy
Deployment strategy choice is risk management: how quickly can you ship, and how cheaply can you revert? The classic options are recreate (downtime), rolling, blue/green, and canary. Pick one, learn its failure modes, and commit to instrumentation so the metric that triggers rollback is automatic, not human.
GitHub Actions canary deploy with metric-based rollback
EXAMPLE
# .github/workflows/canary-deploy.yml
name: canary-deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
env:
AWS_REGION: ap-southeast-2
CLUSTER: shop-prod
SERVICE: api
jobs:
build-and-push:
runs-on: ubuntu-latest
outputs:
image: ${{ steps.meta.outputs.image }}
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with: { role-to-assume: ${{ secrets.DEPLOY_ROLE_ARN }}, aws-region: ${{ env.AWS_REGION }} }
- uses: aws-actions/amazon-ecr-login@v2
- id: meta
run: echo "image=${{ secrets.ECR_REPO }}:${{ github.sha }}" >> "$GITHUB_OUTPUT"
- run: docker build -t ${{ steps.meta.outputs.image }} . && docker push ${{ steps.meta.outputs.image }}
canary:
needs: build-and-push
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with: { role-to-assume: ${{ secrets.DEPLOY_ROLE_ARN }}, aws-region: ${{ env.AWS_REGION }} }
# 1) Deploy 10% canary
- name: Start 10% canary
run: scripts/deploy.sh canary --image ${{ needs.build-and-push.outputs.image }} --pct 10
# 2) Watch error rate and p95 latency for 5 minutes
- name: Bake & monitor
id: monitor
run: scripts/check-health.sh --window 5m --error-rate-max 1 --p95-ms-max 800
# 3) Promote in steps if healthy
- name: Promote 25%
if: steps.monitor.outcome == 'success'
run: scripts/deploy.sh canary --pct 25 && scripts/check-health.sh --window 5m
- name: Promote 50%
if: steps.monitor.outcome == 'success'
run: scripts/deploy.sh canary --pct 50 && scripts/check-health.sh --window 5m
- name: Promote 100%
if: steps.monitor.outcome == 'success'
run: scripts/deploy.sh promote
# 4) Automatic rollback on failure
- name: Roll back
if: failure()
run: scripts/deploy.sh rollback && scripts/notify.sh slack --channel deploys --status failure
# scripts/check-health.sh (sketch)
# Query CloudWatch / Prometheus for the canary task set's
# 5xx rate, p95 latency, business KPI (orders/min). Exit non-zero
# if any threshold breaches. Each promotion step calls this.
# Alternative strategies, picked by risk:
# - rolling: safe + cheap default for stateless services
# - blue/green: full duplicate stack, instant rollback via traffic swap
# - canary: least blast radius, requires good metrics + automated checks
# - recreate: acceptable for batch / nightly only — no production traffic
Why it matters
The strategy is only as good as the metric. A canary that promotes after \"the job didnt fail\" is theatre — a canary that promotes only when error rate, latency, and a business KPI all stay within bounds is real risk control. Wire the metrics first; the workflow second.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
- name: Deploy
run: |
ssh deploy@${{ secrets.HOST }} 'docker pull me/app:${{ github.sha }} && \
docker run -d --restart=always --name app me/app:${{ github.sha }}'
Try it Yourself »
Discussion
Loading…