Release pathBoth paths proven

One commit to the edge.

My lab proves canary gates and promotion, but the page a visitor can open was released without them. This is how I put the same gate in front of both: one commit, two delivery setups, one rule.

Architecture

Two setups, one job that holds the gate and the Cloudflare API token.

Swipe the drawing to see GitHub and the Cloudflare edge. →

Two setups, one job that holds the gate and the Cloudflare API token.A commit to the demo app starts both setups. A push to main runs the tests in GitHub Actions. It does not deploy: when the lab is down, I dispatch the edge release by hand from main. Self managed: the lab tests, builds and pushes an image, then Kargo promotes it to dev, then to staging behind a 5 % mesh canary with analysis. Only verified freight reaches the Kargo prod step. When I promote it, the step calls the GitHub API to start the same edge release with that version. The lab holds a GitHub token limited to that, never the Cloudflare API token. The Actions job uploads the new version next to the previous one at a small share, measures it, then promotes it or rolls it back. The status page shows visitors the running version, its share and the last gate result.My Kubernetes lab · kind on a laptopGitHubCloudflare edge · free planGit eventpush: testsimagefreightverifiedworkflow_dispatchdeploy + gateservesopenArgo Events + Workflowstest, build without Docker socket, pushRegistry in the labimage runs the Worker code on workerdKargo: dev, then stagingdev: one pod. staging: Rollouts canary at 5 % onLinkerd, SLI analysis in PrometheusKargo prod stepverified freight only, promoted by handGitHub tokenactions: write, one repositoryCommit to demo-appone repository, one WorkerActions: demo-app.ymlpush: tests only. Dispatch:release through the gateCloudflare API tokenonly hereWorkerprevious version + new version at10 %Status pageversion, share, last gate resultVisitorsdemo.infrabio.dev123456

Drawn by me, not a screenshot. Every line in it ran in a recorded run, and the red dots replay one release on each path. Both paths end in the same GitHub Actions job, so the gate is written once and the Cloudflare API token never enters the cluster.

  1. 1A commit to the demo app starts both setups.
  2. 2A push to main runs the tests in GitHub Actions. It does not deploy: when the lab is down, I dispatch the edge release by hand from main.
  3. 3Self managed: the lab tests, builds and pushes an image, then Kargo promotes it to dev, then to staging behind a 5 % mesh canary with analysis.
  4. 4Only verified freight reaches the Kargo prod step. When I promote it, the step calls the GitHub API to start the same edge release with that version. The lab holds a GitHub token limited to that, never the Cloudflare API token.
  5. 5The Actions job uploads the new version next to the previous one at a small share, measures it, then promotes it or rolls it back.
  6. 6The status page shows visitors the running version, its share and the last gate result.
Problem

The gates I proved never touched the one thing a visitor can open.

In the lab, a release goes through Argo Rollouts canaries, an SLI analysis on the service mesh and Kargo promotion, and a bad version rolls back by itself. But the lab ran a sample image, and its CI only validated manifests.

The public demo is my own Cloudflare Worker. GitHub Actions tested it, then a script sent it to the edge at a typed share of traffic. Nothing measured the new version before everyone got it.

Approach

Two delivery setups, one gate.

Cloud setup: a push to main only runs the tests. The edge release is a dispatch of the same workflow, which uploads the new version next to the old one at a small share of traffic, measures it, then promotes it or rolls it back. Dispatched by hand from main, it needs no lab: the fallback when the lab is down.

Self managed setup: Argo Workflows tests, builds and pushes the image inside the lab. Kargo promotes it through dev and staging under Rollouts and the mesh analysis, and only verified freight reaches the prod step, which dispatches the same edge release. The Cloudflare API token stays in GitHub.

The rule is the same on both paths: promote when the measured success ratio of the new version is at or above target, roll back otherwise, and no data means no promotion.

The gate

One rule, written once, used by both setups.

  1. 01

    The new version gets 10 % of traffic. The previous version keeps the rest.

  2. 02

    The job sends a fixed number of requests and counts only the answers of the new version.

  3. 03

    It compares the success ratio of the new version with the target, the same target as the lab analysis.

  • No data

    No promotion. The previous version keeps all traffic.

  • Below target

    Roll back. All traffic returns to the previous version.

  • At or above target

    Promote. The new version takes all traffic.

Each stepP12 → P14

The state of each step. Numbers appear when the run that measures them exists.

Both paths ran end to end, the self managed one on my existing lab, not a fresh rebuild.

Self managed

In my Kubernetes lab, with Argo Workflows and Kargo.

  1. P13Proven

    Commit to the demo app

    A Git event starts the lab pipeline. Sent by hand for now: no public webhook.

  2. P13Proven

    Argo Workflows: test, build, push

    A failing test stopped the push: no image. Rootless BuildKit, no Docker socket.

    2 min 33 s from event to image

  3. P13Proven

    Registry in the lab

    The image runs the same code as the edge, on workerd.

  4. P14Proven

    Kargo freight

    Kargo turns the new image in the lab registry into freight, a release candidate.

  5. P14Proven

    dev: first deploy

    One pod, no analysis. Freight that runs here moves on to staging.

  6. P14Proven

    staging: mesh canary at 5 %

    Argo Rollouts sends 5 % of traffic to the new version through Linkerd, and the SLI analysis measures it. A version returning 500 measured 0 and was aborted.

    6 min 15 s from event to verified in staging

  7. P14Proven

    Kargo prod step

    I promote by hand, and only verified freight. The aborted version was refused: "Freight is not available to this Stage". The step dispatches the edge release with that version.

    1 min 35 s from promotion to 100 % at the edge

Cloud

GitHub Actions only, no lab needed. The fallback when the lab is down.

  1. P12Proven

    Commit to the demo app

    A push to main starts the workflow.

  2. P12Proven

    GitHub Actions: test

    Type check and tests. A push to main stops here.

  3. P12Proven

    Dispatch by hand from main

    Releases the head of main to the edge, through the same gate.

Both paths

  1. P12Proven

    Edge: canary, gate, promote or roll back

    The new version takes 10 % of traffic. The gate measures it and decides.

    49 of 49 good: promoted in 10 s · 0 of 50 good: rolled back in 9 s

  2. P12Proven

    Status page

    Shows the running version, its share of traffic and the last gate result.

From the runs

Two broken versions, stopped by the gate.

Rendered from the recorded output of the runs, not screen recordings: the GitHub Actions log of the edge run and the runbook record of the lab run. Every value shown comes from those records.

At the edge: a version returning 500, rolled back in 9 s
In the lab: the same fault, stopped in staging and refused for prod
Numbers

Measured, or not shown.

One commit from a push event in my lab to 100 % at the edge, not counting my approval
7 min 50 sOne commit from a push event in my lab to 100 % at the edge, not counting my approval
From a push event to the staging canary aborting a version returning 500. Kargo then refused it for prod
4 min 4 sFrom a push event to the staging canary aborting a version returning 500. Kargo then refused it for prod
A version returning 500 rolled back at the edge: 0 of 50 good, 10 % of traffic exposed
9 sA version returning 500 rolled back at the edge: 0 of 50 good, 10 % of traffic exposed
A good version promoted to all traffic: 49 of 49 good
10 sA good version promoted to all traffic: 49 of 49 good

The edge runs went through GitHub Actions from main against the live Worker, with no manual step. The lab run started from a push event sent by hand, and I approved the prod promotion; that wait is not counted. The refusal of the broken version was a server side dry run, so nothing was dispatched.

Scope
  • In the lab, the demo app runs on workerd in a container with local storage. That is the same code, not the Cloudflare edge.
  • A release through the self managed path needs my laptop lab to be up. When it is down, I dispatch the same edge release by hand.
  • Lab times start from a push event sent by hand: the lab is not reachable from the internet. They come from my existing lab, not a fresh rebuild.
  • No Cloudflare API token is in the cluster. The prod step holds only a GitHub token limited to Actions on one repository.
  • The gate measures its own requests, pinned to the new version, not visitor traffic.
  • The demo runs on the Cloudflare free plan, so the gate adds no storage writes.
Live on the demo