We are still cooking the magic in the way!
Project: Deploy an App to Kubernetes
Project: Deploy an App to Kubernetes
Theory becomes engineering only when you can ship something to a cluster, watch it roll out, verify it serves traffic, and recover gracefully when something goes wrong. This capstone lesson walks through the full lifecycle of a production-grade deployment: writing a Namespace, a Deployment manifest, and a Service — then performing a rolling update and an emergency rollback. Every step mirrors what platform engineers at large-scale companies do dozens of times a day.
Step 1 — Carve Out a Namespace
Every real application lives in its own Namespace so that resource quotas, RBAC policies, and network policies can be scoped cleanly without bleeding into other teams' workloads. Create a dedicated Namespace for your project before writing any other resource.
env and team are used later by NetworkPolicy selectors, cost-allocation tools, and monitoring dashboards. Adding them retroactively causes silent policy gaps.Step 2 — Write the Deployment Manifest
A production Deployment requires more than a container image and a replica count. It needs resource requests and limits so the scheduler can bin-pack correctly and the kernel OOM killer does not arbitrarily terminate your pod. It needs a readinessProbe so that Kubernetes does not route traffic to an instance that has started but is not yet warm. It needs a livenessProbe so that a deadlocked process is restarted automatically. And it needs a RollingUpdate strategy tuned to guarantee zero-downtime deploys.
requests and limits. As a starting point, set limits at 2x the measured requests, then tune after load testing.Step 3 — Expose the App with a Service
A Service gives your pods a stable virtual IP and DNS name regardless of which node they land on or how many times they restart. For internal microservices use ClusterIP (the default). For an entry point that a load balancer can reach, use LoadBalancer or combine ClusterIP with an Ingress controller. Here we use ClusterIP — a real cluster would place an Ingress or an external load balancer in front.
Step 4 — Perform a Rolling Update
When your CI pipeline pushes a new image tag, update the Deployment. Because maxUnavailable: 0, Kubernetes will spin up the new pod first (maxSurge: 1) and only terminate an old one after the new pod passes its readiness probe. Traffic never drops to zero.
spec.revisionHistoryLimit, default 10). This is what makes rollback instant — the old ReplicaSet still exists and just needs to be scaled back up. Do not set revisionHistoryLimit: 0 in production or you will lose rollback capability entirely.Step 5 — Emergency Rollback
A bad release gets into production. Metrics spike. The on-call engineer needs to revert in under two minutes. The following command sequence is the exact playbook used at hyperscale companies during an active incident.
kubectl annotate deployment/webapp kubernetes.io/change-cause="deploy v1.1.0 — fix login bug" -n webapp. This fills the CHANGE-CAUSE column in rollout history, making incident timelines and postmortems much easier to reconstruct.Production Checklist Before You Ship
Before any real team ships a Deployment to production, they verify the following:
- Resource requests and limits are set — both CPU and memory on every container.
- Readiness and liveness probes are configured — pointing at fast, dependency-aware health endpoints.
- The rolling update strategy guarantees zero downtime —
maxUnavailable: 0and at leastmaxSurge: 1. - The image tag is pinned to an immutable digest or semantic version — never
:latestin production. - Secrets are not stored in environment variables as plaintext — use Kubernetes Secrets or an external vault.
- The Namespace has a ResourceQuota — so one team cannot starve the whole cluster.
- PodDisruptionBudget (PDB) is defined — so node drains during upgrades respect your availability SLA.
The manifests in this lesson are deliberately minimal for clarity. In real infrastructure, a Helm chart or Kustomize overlay would layer in the remaining fields automatically.