Pods Best Practices
This is a working checklist for shipping production-grade Pods on Kubernetes 1.36.2. It distills the section's guidance into grouped, actionable practices for platform engineers and tech leads.
How to Use This List
Treat each group as a review gate for a Pod template before it reaches production.
Do not chase every item at once. Fix the high-leverage ones first: resources, probes, and security context.
Apply these to the Pod template inside a controller (Deployment, StatefulSet, Job), not to bare Pods.
Pair the list with your admission policy so the important rules are enforced, not just documented.
A - Workload Shape
Never run bare Pods in production. Use a Deployment, StatefulSet, DaemonSet, or Job so failed Pods are recreated and rollouts are managed.
Keep one main container per Pod. Add a second container only when it must share the Pod's network or storage. Unrelated services belong in separate Deployments.
Use native sidecars for helpers. On 1.28+, declare proxies and log shippers as init containers with restartPolicy: Always to get startup and shutdown ordering.
Run enough replicas to survive one node loss. Two replicas on one node is not real redundancy. Spread across nodes and zones.
B - Resources & Scheduling
Always set requests. A Pod with no requests is BestEffort and first to be evicted. Size requests from real usage, not guesses.
Set memory limits close to observed peak. Over-memory is OOM-killed, so give headroom but keep the limit tight and predictable.
Be deliberate about CPU limits. CPU over-limit is throttled, not killed. Many teams omit CPU limits to avoid latency spikes and rely on requests plus autoscaling.
Use topology spread and anti-affinity. Spread replicas across nodes and zones so a single failure domain cannot take the whole service down.
Right-size init and sidecar requests. They add to the Pod's scheduled total and can make Pods Pending if oversized.
C - Health & Traffic
Give every serving Pod a readiness probe. Readiness controls endpoint membership; without it, traffic hits Pods that are not ready.
Make readiness reflect real ability to serve. Include the dependencies the Pod needs to handle a request, but distinguish "temporarily not ready" from "never ready."
Keep liveness probes shallow. A liveness probe that checks a database restarts healthy Pods during a downstream blip. Check only the local process.
Add a startup probe for slow boots. Give slow starters a generous startup budget, then hand off to a tight liveness probe instead of a large fixed delay.
Handle SIGTERM and drain gracefully. Stop taking new work, finish in-flight requests, and exit within terminationGracePeriodSeconds.
D - Security Posture
Run as non-root. Set runAsNonRoot: true and a real non-root UID; build images with a USER directive.
Apply the restricted Pod Security Standard. Set allowPrivilegeEscalation: false, seccompProfile.type: RuntimeDefault, and drop all capabilities.
Use a read-only root filesystem. Set readOnlyRootFilesystem: true and mount an emptyDir for the few writable paths the app needs.
Pin images by digest and scan them. Prefer @sha256: references over mutable tags, and gate on Trivy or Grype scans plus cosign signature verification.
Never put secrets in env literals. Use secretKeyRef or mounted Secret volumes so credentials are not baked into the manifest.
E - Availability & Operations
Add a PodDisruptionBudget to availability-sensitive workloads. Use minAvailable or maxUnavailable so drains and autoscaler scale-down keep a safe replica count.
Leave headroom in the PDB. A budget equal to the replica count blocks node drains. Keep at least one Pod evictable.
Remember PDBs only cover voluntary disruptions. They do not protect against node crashes; replication and spreading do.
Label Pods consistently. Stable labels power Services, controllers, PDBs, and NetworkPolicies, so keep a clear labeling convention.
Default-deny network traffic. Start from a deny-all NetworkPolicy and open only the flows the Pod needs.
When You Are Done
Confirm the Pod template sets requests, at least a readiness probe, and a restricted securityContext.
Verify replicas are spread across failure domains and, for critical services, guarded by a PDB.
Run the manifest through your admission controller or kubectl --dry-run=server and a policy check before merging.
Spot-check a live Pod with kubectl describe for events, restart counts, and QoS class.
FAQs
What are the three highest-leverage practices? Set resource requests, add a meaningful readiness probe, and apply a restricted security context. These prevent most production incidents.
Should I set CPU limits? Not always. Requests handle scheduling and fair sharing. Skip CPU limits to avoid throttling, or set them for hard multi-tenant isolation.
Why must readiness reflect dependencies but liveness must not? Readiness drains traffic when the Pod cannot serve; liveness restarts the Pod. Checking dependencies in liveness causes mass restarts during outages.
Do I need a PDB for every workload? Only for replicated, availability-sensitive ones. Single-replica or best-effort jobs usually should not have a PDB, to avoid blocking maintenance.
How do I enforce these, not just document them? Use Pod Security admission (restricted) plus a policy engine so required fields and security settings are rejected when missing.
Related
- What a Pod Represents
- Container Spec
- Liveness, Readiness & Startup Probes
- Requests & Limits
- Pod Disruption Budgets
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).