Build a multi-environment delivery pipeline
Continues from the last build: You have immutable per-commit artifacts, but a deploy is still a single one-shot apply to one environment with no path to production.
Last rung gave it immutable images tagged by git short SHA, so any commit is now a reusable, reproducible artifact.
What you'll build
You will have a single GitHub Actions delivery pipeline that takes one image:sha and promotes it through dev, staging, and prod as ordered, dependent stages running on the platform team's in-network self-hosted runner. Each stage deploys the existing Helm release with a per-environment values file, publishes its environment URL, and runs a post-deploy smoke check that fails the stage if the API is unhealthy. Production is protected by a GitHub Environment with required reviewers, so the same artifact that passed staging only reaches prod after an explicit human approval, giving it a real, auditable path to production.
See how we teach, before you sign up
You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:
name: deliver
on:
push:
branches: [main]
env:
IMAGE: registry.internal/beacon
SHA: ${{ github.sha }}
jobs:
deploy:
runs-on: [self-hosted, deploy-runner]
steps:
- uses: actions/checkout@v4
- name: configure kube access
run: echo "$KUBECONFIG_DATA" > kubeconfig
env:
KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DEV }}
- name: deploy with helm
run: |
helm upgrade --install beacon deploy/chart \
--set image.tag=${SHORT_SHA} \
--values deploy/values-dev.yaml
env:
SHORT_SHA: ${{ github.sha }}Reading this file
on: push: branches: [main]Every merge to main triggers delivery. You keep this trigger but fan it into a promotion chain.runs-on: [self-hosted, deploy-runner]The job runs on the platform team's in-network runner; GitHub-hosted runners cannot resolve *.beacon.internal.--set image.tag=${SHORT_SHA}image.tag is the promotion handle. The same SHA flows through every stage unchanged.--values deploy/values-dev.yamlHard-codes dev. Per-environment values is exactly what the pipeline must parameterize.
The starting point: one job that deploys a single environment with copy-pasted intent. Note runs-on is the platform team's self-hosted runner label, because the cluster and the *.beacon.internal hostnames are only reachable from inside the private network. You will replace this with an ordered dev -> staging -> prod pipeline.
That's 1 of 9 explained code blocks in this single project.
The build, milestone by milestone
- 1
Define the three environments as config, not copy-paste
4 guided stepsPromotion only works if dev, staging, and prod differ by configuration alone. The moment an environment needs a different chart or a different image, you no longer have a promotion pipeline, you have three separate deploys drifting apart.
- 2
Add the production overlay as its own file
4 guided stepsEach overlay must be its own file so a single helm upgrade can be pointed at exactly one of them with --values. Jamming two overlays into one file with a YAML document marker produces a malformed multi-document file that helm will not accept as a values file.
- 3
Split the one-shot deploy into a reusable per-environment job
4 guided stepsIf each environment is hand-written, the dev deploy and the prod deploy slowly diverge and a fix applied to one never reaches the other. One parameterized deploy-and-smoke unit guarantees every environment is shipped the identical way.
- 4
Chain dev -> staging -> prod as ordered, dependent stages
4 guided stepsOrdering is what makes it a promotion pipeline rather than three parallel deploys. needs encodes the rule that you cannot reach a later environment until every earlier one is healthy, which is the whole safety guarantee of staged delivery.
- 5
Gate production behind a GitHub Environment with required reviewers
4 guided stepsAutomated promotion is powerful and dangerous; the last hop to prod should require a deliberate human decision with an audit trail. GitHub Environments give you that gate, the reviewer record, and the environment URL in one place, without writing custom approval logic.
- 6
Make every stage report its URL and prove the same SHA shipped end to end
4 guided stepsA delivery pipeline is also a record. When the on-call asks which SHA is live, the answer should come from the pipeline's own output, not from someone's memory. Surfacing the URL and SHA per stage turns the pipeline into the source of truth.
What's inside when you start
You'll walk away with
This is portfolio-grade. Build it free.
Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.
Start building