Thuta Learning
AdvancedDevOps & Toolsbeginner

Deployment Strategies: Rolling, Blue-Green, Canary

What you'll walk away with

  • Explain the core ideas behind Deployment Strategies: Rolling, Blue-Green, Canary
  • Read the diagram and trace how the pipeline flows and what gates each stage
  • Read the workflow file and predict which jobs run, in what order, and what gates them

Build the mental model

Rolling, blue-green and canary are three answers to one question: while the new version is going out, what does live traffic see?

A rolling deploy replaces instances a few at a time. Old and new run side by side for the length of the rollout, so both must tolerate each other — and, critically, both must tolerate the same database schema. It needs no extra capacity beyond a little headroom, which is why it is the default almost everywhere, but a bad version reaches users gradually rather than not at all, and rolling back means another full rollout in reverse.

Blue-green runs two complete environments. Green sits idle, you deploy to it, you exercise it against real infrastructure with no real users, then you flip the router. The cutover is near-instant and so is the undo — flip back. You pay for that with roughly double the production footprint during the release, and with the awkwardness of in-flight requests and cold caches on the side you just switched to.

Canary sends a small slice of real traffic — one per cent, then ten, then fifty — to the new version and watches error rate and latency between steps. It catches the problems only real users produce, at the cost of a traffic-splitting layer and, more demanding, agreed metrics and thresholds that decide promote-or-abort. Without that analysis a canary is just a slow rolling deploy with extra steps.

Zero downtime is not a property of any of these. It requires backward-compatible requests, drained connections, and health checks that genuinely reflect readiness rather than process liveness. And the truly hard part is rarely the application. Two versions share one database, so the schema must satisfy both at once — which is why migrations, not deploy mechanics, are what sink most releases.

text
TRAFFIC DISTRIBUTION OVER TIME
------------------------------
TIME ------------------------------------------------------->

ROLLING
  old  #########  ######  ###    #
  new             ##      ####   ######   #########
  both versions live at once; one schema must serve both

BLUE-GREEN
  blue  ###########################|
  green                            |###################
                          switch --+  (instant, reversible)
  cost: two full environments during the release

CANARY
  old  ##########   #######   #####   ###
  new  #            ##        #####   #########
       1%           10%       50%     100%
       |            |         |
       +-- check error rate / latency, then promote or abort

HARD PART (all three): the database both versions share

Connect it to a real scenario

This workflow expresses canary as explicit steps. The canary job shifts ten per cent of traffic to the new image and then evaluates error rate over a window. The load-bearing detail is that `check-error-rate.sh` must exit non-zero when the threshold is breached — that failure is what drives every subsequent decision. A script that merely prints a metric for a human to read turns your canary into a dashboard.

The promote job carries `needs: canary`, so it only runs when the canary held. The rollback job carries `if: failure()`, so a breached threshold sends traffic straight back to the stable version without anybody typing a command. That is what makes the pattern useful under pressure: the undo path is already written down and already tested by every release, rather than being recalled from memory during an incident.

To model blue-green instead, set the weight to 100 in one step and drop the observation window — which shows that blue-green is really a canary with a single step and no analysis phase. Before you rely on either, verify the assumption underneath all of it: run two versions against your real database at the same time and confirm the older one still works after the newer one has written a row.

Try the working example

yaml
name: Canary Release
on:
  workflow_dispatch:
    inputs:
      image_tag:
        description: Immutable image tag to release
        required: true
        type: string
permissions:
  contents: read
  id-token: write
jobs:
  canary:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
          aws-region: ap-southeast-1
      - name: Send 10 percent of traffic to the new version
        run: ./scripts/set-traffic-weight.sh ${{ inputs.image_tag }} 10
      - name: Fail if error rate breaches the threshold
        run: ./scripts/check-error-rate.sh --window 10m --max-error-rate 0.01
  promote:
    needs: canary
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
          aws-region: ap-southeast-1
      - name: Send all traffic to the new version
        run: ./scripts/set-traffic-weight.sh ${{ inputs.image_tag }} 100
  rollback:
    needs: canary
    if: failure()
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
          aws-region: ap-southeast-1
      - name: Send all traffic back to the stable version
        run: ./scripts/set-traffic-weight.sh ${{ inputs.image_tag }} 0
You should see
Starting the workflow manually with an image tag runs the canary job: it shifts ten per cent of traffic to the new version and then evaluates the error rate. If that check passes, promote runs and moves all traffic across, and the rollback job is skipped. If the check exits non-zero, promote is skipped because its `needs` dependency failed, while the rollback job — guarded by `if: failure()` — runs and returns the traffic weight to zero, leaving the stable version serving everything. All three jobs declare the production environment, so any protection rule you configured there gates the canary step first, before any traffic moves.

5-minute try-it

Extend this into a multi-step canary: three sequential jobs at one, ten and fifty per cent, each wired with `needs:` and each followed by its own error-rate check. Confirm the rollback job still triggers no matter which step fails — you may need to widen its `needs:` list. Then, on paper, take the most recent migration your application shipped and answer honestly whether the previous version could keep serving traffic against that schema. If the answer is no, you cannot safely use any of these three strategies yet.

One important caution

Allowing two application versions to run side by side while migrating the schema for only the new one — both rolling and canary break in the middle

Judging a canary by elapsed time rather than by traffic volume: at low request rates, ten minutes may carry too few requests for a real regression to show up at all

Google Cloud Architecture: Application deployment and testing strategiesCI/CD with GitHub Actions

Easy traps

  • Allowing two application versions to run side by side while migrating the schema for only the new one — both rolling and canary break in the middle
  • Judging a canary by elapsed time rather than by traffic volume: at low request rates, ten minutes may carry too few requests for a real regression to show up at all
  • Validate a workflow on a branch or test repository before pointing it at a production deployment.

Exercise

Extend this into a multi-step canary: three sequential jobs at one, ten and fifty per cent, each wired with `needs:` and each followed by its own error-rate check. Confirm the rollback job still triggers no matter which step fails — you may need to widen its `needs:` list. Then, on paper, take the most recent migration your application shipped and answer honestly whether the previous version could keep serving traffic against that schema. If the answer is no, you cannot safely use any of these three strategies yet.

You'll know it worked when: Starting the workflow manually with an image tag runs the canary job: it shifts ten per cent of traffic to the new version and then evaluates the error rate. If that check passes, promote runs and moves all traffic across, and the rollback job is skipped. If the check exits non-zero, promote is skipped because its `needs` dependency failed, while the rollback job — guarded by `if: failure()` — runs and returns the traffic weight to zero, leaving the stable version serving everything. All three jobs declare the production environment, so any protection rule you configured there gates the canary step first, before any traffic moves.

Deployment Strategies: Rolling, Blue-Green, Canary | Thuta Learning