Module 8: Capstone Andes Cargo On Kubernetes

8. Final project: `andes-cargo-k8s/` as the capstone deliverable

Description

This project closes the entire guide with the same discipline standard that closed every previous module: it adds no new concept, it gathers everything that already exists into one defensible deliverable. The andes-cargo-k8s/ repository — plus gatekeeper/, kyverno/, kind-config.yaml, and Module 6's scanning script — is, today, eleven real files that ran against a real cluster, verified one last time against andes-cargo-cluster to write this project. This lesson's checklist is the piece you can bring to an interview and defend line by line: what actually ran, what stayed representative, and why each decision was the right one.

Connection to the module

Every previous lesson in this module built one piece of this final synthesis: the architecture map (lesson 2), the change that passes (lesson 3), the change the gate stops (lesson 4), the honesty about EKS (lesson 5), the continuity correction (lesson 6), and the map toward the rest of the ecosystem (lesson 7). This project gathers all six into one deliverable, and ends this guide.


The complete repository, verified today

andes-cargo-k8s/ — ten manifests, synced by ArgoCD

cd andes-cargo-k8s && ls
git log --oneline

What to expect (literal, executed — your commit history grows depending on how many lessons of this guide you completed; the minimum is Modules 5 and 8's seven commits):

application.yaml
configmap.yaml
deployment.yaml
hpa.yaml
ingress.yaml
namespace.yaml
networkpolicy-allow-ingress-nginx.yaml
networkpolicy-default-deny.yaml
secret.yaml
service.yaml

dcdd4b3 Revert "Temporarily remove resource limits from andes-cargo-status-api to debug OOM"
229cd7b Temporarily remove resource limits from andes-cargo-status-api to debug OOM
d0b98c6 Add tier=backend label to the andes-cargo-status-api pod template
db09bbe Ignore spec.replicas on the Deployment: the HorizontalPodAutoscaler owns it, not Git
cd0b5ca Scale andes-cargo-status-api from 3 to 5 replicas
820515f Add ArgoCD Application pointing at this same repository
45b14f6 Initial GitOps source: namespace, deployment, service, config, hpa, ingress, networkpolicy (inherited from M1-M4)

Seven commits, and none of them is a disguised kubectl apply — each one is a real change, with its own history: the initial load inherited from M1-M4, ArgoCD's self-referential Application (M5), a real business-driven scale-up (M5), the HPA/GitOps tension fix (M5), and this same module's two commits — one that passed the gate, one the gate stopped and its revert.

gatekeeper/, kyverno/, kind-config.yaml — the guardrail infrastructure, outside the synced repository

ls gatekeeper/ kyverno/
cat kind-config.yaml

What to expect:

gatekeeper/:
constraint-andes-cargo-required-resources.yaml
constraint-template-required-resources.yaml

kyverno/:
policy-andes-cargo-require-resources.yaml

# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: andes-cargo-cluster
nodes:
  - role: control-plane
  - role: worker
  - role: worker

These three files don't live inside andes-cargo-k8s/, and that separation is intentional, explained since Module 6: a Gatekeeper ConstraintTemplate/Constraint and a Kyverno ClusterPolicy are the cluster's own infrastructure — they get applied once with direct kubectl apply, they don't change with every andes-cargo-status-api git push — exactly like kind-config.yaml describes the cluster's shape, not the content running inside it. Mixing them into the same repository ArgoCD syncs would blur two different layers of responsibility.

scripts/scan-and-load.sh — Module 6's image gate

cat scripts/scan-and-load.sh

What to expect (the same script from Module 6, lesson 8, with no change):

#!/usr/bin/env bash
# scan-and-load.sh — trivy image gate before kind load docker-image
# Usage: ./scan-and-load.sh <image:tag>
set -euo pipefail

IMAGE="$1"
CLUSTER="andes-cargo-cluster"

echo "==> scanning ${IMAGE} for CRITICAL vulnerabilities before loading into ${CLUSTER}"

if trivy image --exit-code 1 --severity CRITICAL --quiet "${IMAGE}"; then
  echo "==> gate PASSED — no CRITICAL findings, loading ${IMAGE} into ${CLUSTER}"
  kind load docker-image "${IMAGE}" --name "${CLUSTER}"
  echo "==> ${IMAGE} loaded"
else
  echo "==> gate FAILED — ${IMAGE} has CRITICAL findings, NOT loaded into ${CLUSTER}"
  exit 1
fi

Eleven files in total — ten synced manifests, two Gatekeeper pieces, one Kyverno piece, kind-config.yaml, and this script — are this guide's complete deliverable.


The portfolio checklist: what really ran, verified one last time

kind get clusters
kubectl get nodes
kubectl get application -n argocd
kubectl get k8srequiredresources
kubectl get clusterpolicy
kubectl get pods -n andes-cargo -l app=andes-cargo-status-api
curl -i -s --max-time 8 --resolve andes-cargo.local:80:127.0.0.1 http://andes-cargo.local/health

What to expect (literal, executed — this guide's complete final audit, in one block):

andes-cargo-cluster

NAME                                STATUS   ROLES           AGE    VERSION
andes-cargo-cluster-control-plane   Ready    control-plane   3h5m   v1.36.1
andes-cargo-cluster-worker          Ready    <none>          3h5m   v1.36.1
andes-cargo-cluster-worker2         Ready    <none>          3h5m   v1.36.1

NAME                     SYNC STATUS   HEALTH STATUS
andes-cargo-status-api   Synced        Healthy

NAME                                    ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
andes-cargo-must-have-resource-limits   deny                 0

NAME                                  ADMISSION   BACKGROUND   READY   AGE   MESSAGE
andes-cargo-require-resource-limits   true        true         True    62m   Ready

NAME                                      READY   STATUS    RESTARTS   AGE
andes-cargo-status-api-669755d655-np5mt   1/1     Running   0          12m
andes-cargo-status-api-669755d655-qhgwx   1/1     Running   0          12m

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 51

{"service":"andes-cargo-status-api","status":"ok"}

A healthy three-node cluster; a synced, healthy ArgoCD Application; both admission-control engines active with no violations; the production Pods responding to real traffic. This is eleven weeks of content's final state, confirmed with real commands, not a promise.


The honesty checklist: EXECUTED versus REPRESENTATIVE, module by module

ModulePieceStatusEvidence
1kind + kubectl, the cluster, the loaded imageExecutedkind get clusters, crictl images on all three nodes (M1.7/M1.8)
2Pod, Deployment, ReplicaSet, ServiceExecutedkubectl get all -n andes-cargo (M2.8)
3ConfigMap, Secret, three probes, HorizontalPodAutoscalerExecutedInduced and observed readiness/liveness failure; HPA scaling under real load (M3.6/M3.8)
4ingress-nginx, Ingress, two NetworkPolicyExecutedReal curl via Ingress; traffic blocked/allowed with NetworkPolicy (M4.8)
5Gitea, ArgoCD, pull-based GitOpsExecutedgit push with no kubectl apply, convergence measured with real timestamps (M5.8)
6Gatekeeper, Kyverno, trivy imageExecutedReal rejection with a literal message from both engines; image gate failing against the real image (M6.8)
7Managed control plane, node groups, IRSA, ALB Controller, node autoscalingRepresentativeExact cost reason declared for each piece (M7.1-M7.8, this module's M8.5)
8Change that passes the gate, change the gate stopsExecutedThis entire guide — M8.3/M8.4, with the real finding about Kyverno's autogen

Six of eight modules, executed end to end against a real cluster. One, representative, with the exact reason declared for each piece. One — this one — integrates both.


How to defend this deliverable in an interview

Three questions any technical interviewer would ask facing this repository, with the exact answer this project already built:

"How do I know this isn't just YAML you copied from a tutorial?"andes-cargo-k8s/'s git log history has seven real commits, with messages describing business decisions (scaling replicas, fixing a tension between GitOps and autoscaling, reverting a dangerous change) — not a single "initial setup" commit. And this module's lesson 4's finding (Kyverno catching a Deployment Gatekeeper didn't cover) is, literally, impossible to get by copying a tutorial: it's the kind of behavior that only shows up when running two real policy engines, together, against a real case.

"What would you do differently on a real EKS cluster?" — The answer is complete in this module's lesson 5, and in Module 7, lesson 8: five of andes-cargo-k8s/'s ten manifests wouldn't change a single line; the other five change in specific, nameable fields (image, serviceAccountName, one ConfigMap key, ingressClassName, and one NetworkPolicy's selector type) — never "everything would be different."

"What didn't you test?" — The honest answer, with no evasion, is in this module's lesson 5: the managed control plane, real node groups, node autoscaling, IRSA/EKS Pod Identity, and the AWS Load Balancer Controller — each with the exact cost reason, not a generality.


Analogy: the work folder, closed and sealed

If every module in this guide was a station in lesson 1's automated factory, this project is the folder an auditor seals at the end of a complete inspection: it contains no unverified promise, no "this should work" — every page has a signature, a timestamp, and the exact command that produced the result. An interviewer who opens this folder doesn't find a pretty blueprint of a factory that never got built — they find the record of a factory that ran, with two real documented incidents (Module 5's HPA/GitOps tension, this module's Gatekeeper/Kyverno asymmetry) and their resolution, exactly the way a real platform team's file would look after a busy week.


Common mistakes

Presenting this deliverable without the git log history (omitting the strongest evidence). What happens: someone, showing andes-cargo-k8s/ as a portfolio piece, shares only the files' final state, with no commit history. How to spot it: if the version of the repository you show others is a folder with no .git/, or a git log with a single "initial commit." How to fix it: the complete history, with its seven real commits and their messages, is exactly the evidence that answers the previous section's first question — without it, the repository looks just as generic as any copied tutorial.

Not being able to explain the autogen finding without rereading lesson 4 (incomplete interview preparation). What happens: someone memorizes that "Gatekeeper and Kyverno are different" without being able to explain the specific technical reason (Gatekeeper's match.kinds versus Kyverno's background: true/autogen). How to spot it: if, when trying to explain lesson 4's finding to a colleague, your explanation stays at "sometimes one catches things the other doesn't." How to fix it: review lesson 4 until you can explain, unaided, exactly why Gatekeeper didn't evaluate the Deployment (its Constraint never declared Deployment in match.kinds) and why Kyverno did (its background: true rule automatically generated an equivalent rule, with the autogen- prefix, for Pod controllers).

Treating "6 of 8 modules executed" as a weakness to hide (unnecessary defensive framing). What happens: someone, presenting this deliverable, avoids mentioning Module 7 is representative, hoping no one asks. How to spot it: if your plan facing "did this run on real EKS?" is to change the subject. How to fix it: honesty about what's representative and why — with exact, not generic, reasons — is itself a signal of professional maturity a technical interviewer values more than a vague claim of "yes, everything ran in production." This lesson's table exists exactly to answer that question with confidence, not to avoid it.


Exercises

Exercise 1 — Rebuild the eleven-file tree from memory. Without going back to this lesson, list the eleven files that make up this guide's complete deliverable, grouped into their four categories (synced manifests, Gatekeeper, Kyverno, cluster infrastructure/script).

See solution

Synced by ArgoCD (10): namespace.yaml, deployment.yaml, service.yaml, configmap.yaml, secret.yaml, hpa.yaml, ingress.yaml, networkpolicy-default-deny.yaml, networkpolicy-allow-ingress-nginx.yaml, application.yaml. Gatekeeper (2): constraint-template-required-resources.yaml, constraint-andes-cargo-required-resources.yaml. Kyverno (1): policy-andes-cargo-require-resources.yaml. Cluster infrastructure and automation (2, outside the previous categories): kind-config.yaml, scripts/scan-and-load.sh. Total: ten plus four = fourteen if you count each individual piece — but, grouping gatekeeper/, kyverno/, kind-config.yaml, and scripts/ as "the pieces outside the synced repository," the complete deliverable is eleven files of real content.

Exercise 2 — Practice the answer to the three interview questions, out loud. Without looking at the "How to defend this deliverable" section, answer out loud, in your own words, the section's three questions: how do you know it's not a copied tutorial?, what would you change on real EKS?, what didn't you test?

See solution

There's no single correct answer — the real test is whether your answer, without looking at the text, includes specific evidence (the git log history with real business messages, the autogen finding as something that doesn't show up in generic tutorials, the table of five files that change versus five that don't when migrating to EKS, and the list of five representative pieces with their exact cost reason). If your answer to any of the three questions was vague or generic, go back to the corresponding lesson (4, 5, or Module 7, lesson 8) before considering this guide finished.

Exercise 3 — Design your own honest extension of this deliverable. Based on this module's lesson 7, pick one of the three gaps (Kubernetes FinOps, cluster SRE, GPU/EKS) and describe, in two or three sentences, what the first concrete file you'd add to andes-cargo-k8s/ would be if you decided to close that gap on your own.

See solution

A reasonable answer, for the SRE gap: "I'd add a poddisruptionbudget.yaml, with minAvailable: 1 over the andes-cargo-status-api Deployment — the object no lesson in this guide built, and that a real SRE exercise (like the one sre-and-incident-response-guide describes) would identify as the first missing guardrail before any planned maintenance operation on the cluster's nodes." Any answer that names a concrete file, with a specific field and a reason connected to the chosen discipline, shows lesson 7 got understood as a real work map, not as a list of guide names.


Summary and next step

This project closed the entire guide with its final deliverable: andes-cargo-k8s/ (ten manifests, seven real commits), gatekeeper//kyverno/ (the runtime guardrails), kind-config.yaml (the cluster's shape), and scripts/scan-and-load.sh (the image gate) — eleven pieces of real content, verified one last time against a healthy andes-cargo-cluster, with Application: Synced/Healthy, both policy engines active with no violations, and andes-cargo-status-api responding to real traffic. The module-by-module honesty table leaves this guide's final balance in one place: six of eight modules executed end to end, one representative with an exact reason, and this capstone integrating both with two real unplanned findings (Module 5's HPA/GitOps tension, this module's Gatekeeper/Kyverno asymmetry).

andes-cargo-status-api — the component aws-serverless-and-containers-guide left "documented, never executed" on ECS — ends this guide actually running, on a real Kubernetes cluster, with real pull-based GitOps and real admission control on top. That's, in one sentence, the complete promise this guide made since its Module 1, lesson 1, and that this final project confirms with evidence, not with a claim.

There is no next lesson. This is kubernetes-and-eks-in-production-guide's last lesson. The map forward — Kubernetes FinOps, cluster SRE, GenAI/GPU over EKS — stayed in this same module's lesson 7, with the real guides that already exist to continue.

Resources

  1. Kubernetes — Production Environment — official reference on the production considerations this entire guide, with kind as the lab, prepared to transfer with no translation to a real cluster.
  2. Argo CD — Best Practices — official GitOps practices, most already applied in andes-cargo-k8s/ throughout this guide.
  3. kubernetes-and-eks-in-production-guide (NIEVA), Modules 1-8 — the complete source for every piece of this final deliverable.
  4. aws-serverless-and-containers-guide (NIEVA), Module 8 — the exact point in the ecosystem where andes-cargo-status-api stayed "documented, never executed," and that this entire guide closed with real evidence.