Extended Lab B - Ship a change
Extended Lab B - Ship a change
Infochallenge optional / after the course
Prerequisite: Extended Lab A finished and still running. You also need: a GitHub account and a personal access token.
Goal: change one line of C#, and follow it all the way into the running
cluster without ever typing kubectl apply.
Starting point: Extended Lab A finished, with the app running from
ghcr.io/ecaha/... and outbound internet from support01 and the cluster nodes.
This lab changes a running system. There is nothing here that stands on its own - do Extended Lab A first.
The pipeline you are building:
you edit source
│ git push
▼
GitHub Actions ──build──▶ ghcr.io/<you>/kubequiz-api:<tag>
│ ▲
│ commits the new tag into │ pulled by the kubelet
│ gitops/base/kustomization.yaml │
▼ │
git repository ◀──watches── Argo CD ──applies──▶ your cluster
Nothing in the cluster needs a GitHub credential, and nothing in GitHub needs a kubeconfig. Argo CD pulls. Keep that in mind when you get to Stage 5.
Check your work: ./labs/verify.sh b2, or ./labs/verify.sh b for all of it.
Stage 1 - Your own images
Task. Fork this repository, let its pipeline run, and end up with two container images in your own GitHub Container Registry that the cluster is allowed to pull anonymously.
Done when
- your fork’s
build-and-publishworkflow has a green run ghcr.io/<you>/kubequiz-apiandghcr.io/<you>/kubequiz-webexist as public packages- both are tagged
latestand with a dated tag like20260806-a1b2c3d
Check: none - this stage lives on GitHub. Stage 2 proves it worked.
Think about it. The workflow authenticates to GHCR with
secrets.GITHUB_TOKEN, which you never created. Where did it come from, how
long is it valid, and what can it do? permissions: at the top of the job is
the answer.
Stage 2 - Run your build
Task. Make the cluster run your images instead of your instructor’s.
Change it in git, not with kubectl set image.
Done when
kubectl get deploy kubequiz-api -o jsonpath='{..image}'contains your GitHub username- both Deployments are Ready and the site still works in your browser
- the change is committed and pushed
Check: ./labs/verify.sh b2
Stage 3 - Hand the cluster to Argo CD
Task. Install Argo CD, reach its UI from your laptop’s browser through the
relay and Gateway you already have, and give it ownership of the kubequiz
namespace from gitops/overlays/lab with automated sync and self-healing.
Done when
kubectl -n argocd get app kubequizreportsSyncedandHealthy- the UI opens at
http://argocd.k8s.lab:30080and you are logged in kubectl scale deploy/kubequiz-api --replicas=7is reverted within a minute, and the Argo CD UI shows why
Check: ./labs/verify.sh b3
Think about it. Your kubectl scale was undone within seconds. Is that
helpful or infuriating? Both answers are defensible - what makes the difference
is whether the cluster or the repository is meant to be the source of truth,
and whether everyone on the team agrees which it is.
Stage 4 - The whole loop
Task. Put your own name into the running application by editing source code
and pushing it. You may not use kubectl apply, kubectl set image, or the
Argo CD Sync button - the pipeline does all of it.
Two strings to change, one in each image, so that you prove both halves of the pipeline:
src/KubeQuiz.Api/Program.cs→ theAboutconstantsrc/KubeQuiz.Web/wwwroot/index.html→ the<title>
Done when
curl -H 'Host: kubequiz.k8s.lab' http://192.168.56.101:30080/api/aboutreturns your text- the browser tab title shows your text
/api/whoamireports aversionequal to the new image tag, notdev- the running image tag matches the tag your workflow just published
- you did the whole thing with
git pushand waiting
Check: ./labs/verify.sh b4
Time it. From git push to the new text being live. Most of that number is
one specific step - which, and what would you do about it in a real project?
Stage 5 - Break it, then get out of it
Task. Ship something broken, watch what Kubernetes does with it, and recover - using git, not kubectl.
Do both:
- A bad image. Commit an image tag that does not exist in the registry.
- A bad application. Make the API fail its readiness probe on startup - for
example, point
PGHOSTat a database that is not there.
Done when
- for each case you can answer: was the site still up? - and say why
- you can name the ReplicaSet that is stuck and quote the event that explains it
- both are fixed by a
git revertthat Argo CD picks up on its own kubectl rollout history deploy/kubequiz-apishows the whole story
Check: ./labs/verify.sh b5
Think about it. The bad image never took the site down. The bad configuration might have, depending on your probes. Which of the two would your monitoring have told you about, and how long would the other have sat there unnoticed?
Stage 6 - Optional: make the pipeline mean something
Pick any of these and implement it:
- Fail the build on HIGH or CRITICAL findings (
exit-code: '1'on the Trivy step). Then fix or justify what it finds. - Protect
mainso changes have to arrive by pull request, and confirm the CI-committed tag bump still works. - Add a real test project and make the build fail without it passing. Note that
the workflow currently ends the test step with
|| true- find it, and decide whether that is honest. - Give the
db-initJob an Argo CDPreSynchook (it already has one) and prove the ordering by making it fail.
Finished
./labs/verify.sh b
You changed a line of C# and it reached three PostgreSQL replicas’ worth of running application without you touching the cluster once. That is the whole argument for GitOps, and you have now done it rather than been told about it.