Kubernetes for Application Developers: What You Actually Need to Know#
Kubernetes has a reputation for endless complexity, and the reputation is deserved if you try to learn all of it. But most application developers do not operate clusters. They deploy services onto them. For that job, a small set of concepts covers almost everything — and getting those few right prevents most production problems.
The core objects#
- Pod: one or more containers that run together. Pods are disposable; Kubernetes creates and kills them freely.
- Deployment: declares how many replicas of a pod should run and how to roll out new versions.
- Service: a stable network name and address in front of a changing set of pods.
- ConfigMap and Secret: configuration and credentials injected into pods.
- Ingress (or Gateway): routes external HTTP traffic to services.
If you understand these five, you can read and write most application manifests.
A production-ready deployment#
Here is a deployment with the settings that matter most, which are exactly the ones beginners leave out:
1apiVersion: apps/v12kind: Deployment3metadata:4 name: api5spec:6 replicas: 37 selector:8 matchLabels: { app: api }9 template:10 metadata:11 labels: { app: api }12 spec:13 containers:14 - name: api15 image: registry.example.com/api:1.42.016 ports:17 - containerPort: 500018 resources:19 requests: { cpu: 250m, memory: 256Mi }20 limits: { memory: 512Mi }21 readinessProbe:22 httpGet: { path: /health/ready, port: 5000 }23 periodSeconds: 524 livenessProbe:25 httpGet: { path: /health/live, port: 5000 }26 initialDelaySeconds: 2027 periodSeconds: 1028 envFrom:29 - secretRef: { name: api-secrets }
Resource requests and limits#
Requests tell the scheduler how much CPU and memory your pod needs; it uses them to decide where pods fit. Limits cap what a container can use.
- Set requests based on measured usage, not guesses. Too low and nodes become overloaded; too high and you waste money.
- Set a memory limit. A container that exceeds it is killed (
OOMKilled), which is better than a memory leak taking down the whole node. - Be cautious with CPU limits. Exceeding them causes throttling, which shows up as mysterious latency spikes. Many teams set CPU requests but no CPU limit.
Readiness vs liveness probes#
These two are often confused, and getting them wrong causes outages.
- Readiness: "Can this pod receive traffic right now?" If it fails, the pod is removed from the service, but not restarted. Use it during startup and when a critical dependency is temporarily unavailable.
- Liveness: "Is this process stuck beyond recovery?" If it fails, Kubernetes restarts the container.
Never make the liveness probe depend on external services like the database. If the database has a brief hiccup, every pod fails liveness at once and gets restarted together — turning a small problem into a full outage. Liveness should only check that the process itself is responsive.
Graceful shutdown#
During a rollout or scale-down, Kubernetes sends SIGTERM and waits (30 seconds by default) before force-killing the pod. Your application must use that time:
- Stop accepting new connections and fail the readiness probe.
- Finish in-flight requests and jobs.
- Close database and queue connections cleanly.
- Exit.
1process.on("SIGTERM", async () => {2 isShuttingDown = true; // readiness now returns 5033 await new Promise((r) => setTimeout(r, 5_000)); // let load balancers notice4 await server.close();5 await db.destroy();6 process.exit(0);7});
Without this, every deploy drops a few requests — the kind of bug that is invisible in testing and constant in production.
Configuration and secrets#
Keep configuration out of images, so the same image runs in every environment. Inject it through ConfigMaps and Secrets. Note that native Kubernetes Secrets are only base64 encoded, not encrypted by default; in production, back them with a proper secret manager and restrict who can read them.
Rollouts and rollbacks#
Deployments roll out gradually by default, replacing pods a few at a time and waiting for each to become ready. That only works if your readiness probe is meaningful. If a rollout goes wrong:
1kubectl rollout status deployment/api2kubectl rollout undo deployment/api
Always deploy immutable, versioned image tags (api:1.42.0), never latest, so a rollback actually returns to the previous code.
Debugging basics#
The commands that solve most problems:
1kubectl get pods -l app=api # status and restarts2kubectl describe pod <name> # events: scheduling, probes, OOM kills3kubectl logs <name> --previous # logs from the crashed container4kubectl top pods # actual CPU and memory usage
describe and --previous logs answer the classic question "why does my pod keep restarting?" nine times out of ten.
Conclusion#
You do not need to master Kubernetes to deploy well on it. Set honest resource requests and a memory limit, separate readiness from liveness and keep liveness independent of dependencies, handle SIGTERM gracefully, keep configuration out of images, and use immutable tags. Those habits prevent most of the incidents developers cause on Kubernetes.