Zebra Continuous Delivery
The continuous-delivery pipeline deploys every commit merged to main to the stage environment and every published release to prod, on Google Cloud Platform. PR-triggered work uses the dev environment.
Topology: one zonal MIG per (environment, branch, network, zone)
The pipeline targets two GCP environments. Each network in each environment deploys to three zonal Managed Instance Groups (MIGs) in us-east1 zones b, c, and d. Each zonal MIG holds one Zebra instance with one stateful cache disk and one static IP.
| Trigger | Environment label | GCP project | MIGs per network | MIG name | Stateful disk |
|---|---|---|---|---|---|
release | prod | zfnd-prod-zebra | 3 (one per zone) | zebrad-${network}-${zone-letter} | zebrad-cache-${network}-${zone-letter} |
push to main | stage | zfnd-dev-zebra | 3 (one per zone) | zebrad-main-${network}-${zone-letter} | zebrad-cache-main-${network}-${zone-letter} |
workflow_dispatch | dev or prod | selected by env | 1 (user-chosen zone) | zebrad-${branch}-${network}-${zone-letter} | zebrad-cache-${branch}-${network}-${zone-letter} |
ADR 0006 records the rationale; the runbook covers day-to-day procedures.
Update mechanics
Each push and each release fans out to six deploy-nodes jobs (2 networks × 3 zones). A workflow_dispatch is a single job (user picks the zone). Every job runs the same flow for its zonal MIG:
- Build a new instance template with the commit’s container image.
- Ensure the zonal stateful disk exists. On first deploy, create it from the latest matching cache image. On subsequent deploys, attach the existing disk.
- If the zonal MIG exists, run
rolling-action start-update --max-unavailable=1. True per-zone rolling: this zone’s MIG replaces its instance while the other two zones keep serving. The stateful disk persists across the replace. - If the zonal MIG does not exist, create it with
--size=1and apply the stateful policy. - Assign the static IP (push and release only; workflow_dispatch uses ephemeral). Zone-to-IP mapping is deterministic: zone
b→ primary, zonec→ secondary, zoned→ tertiary.
Cache images come from zfnd-ci-integration-tests-gcp.yml’s create-state-image job. Image names encode branch, commit, state-DB version, network, and timestamp. One image per network seeds all three zones. Lookup priority in gcp-get-cached-disks.sh: current branch, then main, then any branch; most recent first.
Deploy success has two channels: deploy-nodes reports infrastructure, verify-nodes reports application health. See the runbook for details.
Triggers
The workflow runs on:
- a
pushtomainthat touches Rust code, dependencies, Docker files, or the workflow itself - a published
release - a
workflow_dispatchfrom any branch (dispatcher picksnetwork,zone, andenvironment)
Pull requests run only the Docker-configuration tests; they do not deploy.
For implementation details, see the deploy workflow.