Kubernetes Pod Design Practice
Kubernetes Pod Design Practice covers best practices for structuring pods to ensure reliability, scalability, and efficient resource use in Kubernetes.
Kubernetes Pod Design Practice is the body of conventions and structural decisions engineers apply when composing a Pod's containers, volumes, and lifecycle hooks so that the resulting workload is resilient, observable, and easy to operate. These practices address how many containers belong in a Pod, how those containers should communicate, how configuration and secrets should be injected, and how the Pod should behave during startup, failure, and shutdown.
Single-Container Versus Multi-Container Pods
The Single-Responsibility Default
The prevailing practice is to keep one primary application process per Pod, mirroring the single-responsibility principle at the deployment unit level. This keeps scaling, resource accounting, and restart semantics simple, since the ReplicaSet scales the Pod as a whole rather than an internal mix of unrelated processes.
Justified Multi-Container Patterns
Multiple containers in one Pod are appropriate only when the containers share fate and must run co-located on the same node, communicating over localhost or a shared filesystem:
- Sidecar: a helper container that extends or monitors the main container, such as a log shipper or service mesh proxy.
- Ambassador: a proxy container that simplifies network access to external services for the main container.
- Adapter: a container that normalizes the main container's output into a common format for monitoring or logging systems.
apiVersion: v1
kind: Pod
metadata:
name: pod-design-example
spec:
containers:
- name: app
image: registry.example.com/app:1.0.0
- name: log-shipper
image: registry.example.com/log-shipper:1.0.0
volumeMounts:
- name: logs
mountPath: /var/log/app
volumes:
- name: logs
emptyDir: {}
Init Containers for Preconditions
Sequencing Setup Work
Init containers run to completion, in order, before any application container starts. Good practice reserves them for one-time setup work — database schema checks, configuration templating, dependency wait-loops — rather than long-running logic, since they cannot serve traffic and block Pod readiness until finished.
spec:
initContainers:
- name: wait-for-db
image: registry.example.com/netcat:1.0
command: ["sh", "-c", "until nc -z db-service 5432; do sleep 2; done"]
Probes as a Design Requirement
Distinguishing Liveness From Readiness
Sound practice defines liveness and readiness probes with distinct semantics rather than reusing the same endpoint: liveness should detect unrecoverable deadlock, and readiness should detect temporary inability to serve traffic (such as during cache warm-up), since conflating the two causes unnecessary restarts for conditions that would have resolved on their own.
containers:
- name: app
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 15
failureThreshold: 3
Graceful Shutdown Design
terminationGracePeriodSeconds and preStop
Because Kubernetes sends SIGTERM and then waits before force-killing with SIGKILL, good design sets terminationGracePeriodSeconds to comfortably exceed the application's shutdown time and, where the runtime cannot handle SIGTERM cleanly, uses a preStop hook to trigger connection draining first.
spec:
terminationGracePeriodSeconds: 45
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10 && /app/drain.sh"]
Resource Declarations and Immutability
Always Declare Requests
Omitting resource requests places a Pod in the BestEffort QoS class, making it the first candidate for eviction under node pressure. Design practice treats explicit CPU and memory requests as mandatory, sized from observed usage rather than guessed defaults.
Treat the PodSpec as Immutable
Most fields of a running Pod's spec cannot be modified in place; established practice is to change the owning controller's Pod template and let the controller perform a rolling replacement, rather than attempting to patch fields directly on live Pods.
Pod Design Decision Flow
Applying this decision consistently keeps Pods small, independently scalable, and easy to reason about, which is the underlying goal of nearly every convention within Kubernetes Pod Design Practice.