Project 5 of 12 · project brief
Deploy the Complete App to Kubernetes
The Project 3 stack as Kubernetes manifests: Deployments, StatefulSets, Services, Ingress, ConfigMaps, Secrets, probes, resources, and autoscaling.
The scenario
Compose runs on one machine. ShopLite now needs self-healing, rolling updates, and scaling across nodes. Your brief: run the whole application on a local Kubernetes cluster (kind or k3d) with production-style manifests, so moving to EKS later is just a change of cluster.
Before you start
- Kubernetes course
Workloads, services, config, storage, scheduling, debugging.
- Stateful · Running stateful workloads
StatefulSets and PVCs for Postgres, Redis, and Kafka.
Stack
Target architecture
Deliverables and requirements
You will hand in
- A
k8s/folder of manifests (or Kustomize base), one directory per component - Probes, resource requests/limits, PDBs, and an HPA for the API
- Config in ConfigMaps, credentials in Secrets (not in Git: created from a sealed/secret manager or a local script)
- A troubleshooting log: at least three problems you hit and how you diagnosed them
Functional
- The whole app works through one Ingress host (e.g. shop.local)
- Killing any API pod causes no failed requests (readiness + multiple replicas)
- Database data survives pod deletion
Non-functional
- Every container has requests/limits and readiness/liveness probes
- API scales on CPU with an HPA
- NetworkPolicy: only the API may reach Postgres and Redis
Milestones
- 1
Cluster and stateful services
Done when: Postgres, Redis, and Kafka running as StatefulSets with persistent volumes.
- Create a 3-node kind cluster with an ingress-ready control plane
- Postgres StatefulSet + headless Service + PVC template; init credentials from a Secret
- Redis and Kafka (or the Strimzi operator for Kafka, Stateful course Unit 2.3)
Prove it works
terminal$ kubectl -n shoplite get sts,pvc── expected output ──NAME READY AGEstatefulset.apps/postgres 1/1 3mstatefulset.apps/redis 1/1 3m...persistentvolumeclaim/data-postgres-0 Bound ... - 2
API, worker, and frontend
Done when: Stateless services as Deployments with config, probes, and resources.
- ConfigMap for non-secret config; Secret for DB password
- Readiness on
/actuator/health/readiness, liveness on/actuator/health/liveness - Requests/limits sized from observed usage
- Services for each
Stuck? Hints
- Liveness should never depend on the database: if Postgres is down, restarting every API pod makes it worse.
Prove it works
terminal$ kubectl -n shoplite rollout status deploy/api && kubectl -n shoplite get endpoints api── expected output ──deployment "api" successfully rolled outNAME ENDPOINTS AGEapi 10.244.1.7:8080,10.244.2.5:8080,10.244.3.4:8080 2m - 3
Ingress, scaling, and resilience
Done when: External access, autoscaling, and disruption safety.
- Install an ingress controller (or Gateway API implementation) and route
/and/api - Install metrics-server; HPA on the API at 70% CPU
- PDB
minAvailable: 2for the API; run a load test and watch it scale (Stateful course, k6)
Prove it works
terminal$ kubectl -n shoplite get hpa api -w── expected output ──NAME REFERENCE TARGETS MINPODS MAXPODS REPLICASapi Deployment/api cpu: 142%/70% 3 10 3api Deployment/api cpu: 88%/70% 3 10 6 - Install an ingress controller (or Gateway API implementation) and route
- 4
Network policy and a zero-downtime rollout
Done when: Least-privilege networking and a rolling update with no errors.
- Default-deny ingress in the namespace; allow ingress→frontend/api, api→postgres/redis/kafka
- Change the API image tag and roll out while a load test runs; confirm zero 5xx
- Practise
kubectl rollout undo
Prove it works
terminal$ kubectl -n shoplite run tmp --rm -it --image=busybox:1.37 -- nc -zv -w 2 postgres 5432── expected output ──nc: postgres (10.96.44.12:5432): Connection timed out# blocked: only pods labelled app=api may connect (good)
Would you run this in production?
- ☐Probes separated correctly (readiness gates traffic; liveness only for deadlocks)
- ☐Requests/limits on everything; PDBs on multi-replica services
- ☐Secrets not committed; RBAC least privilege; pods non-root
- ☐NetworkPolicies default-deny
- ☐Graceful shutdown (
preStop+terminationGracePeriodSeconds) so rollouts don't drop requests
Stretch goals
- Replace Ingress with Gateway API (Platform course, Mission 0.2)
- Use the CloudNativePG operator for Postgres with automated backups
- Add topology spread constraints and simulate a node failure
Show it off
Résumé bullet
Migrated a 6-service application to Kubernetes with StatefulSets for data services, health probes, HPA autoscaling, PDBs, and default-deny network policies; achieved zero-error rolling deployments under load.
Demo script
- Delete an API pod during a load test: zero errors
- Show the HPA scaling out
- Show a NetworkPolicy blocking an unauthorised pod
Interview questions about this project
Readiness vs liveness probes?
How do you achieve zero-downtime deployments on Kubernetes?