spec:
initContainers:
- name: init-db
image: busybox:1.36
command: ["sh", "-c", "until nc -z db 5432; do sleep 2; done"]
containers:
- name: app
image: node:20-alpine
resources:
requests: { cpu: "250m", memory: "64Mi" }
limits: { cpu: "500m", memory: "128Mi" }
Requests and limits
| Request | Limit | |
|---|---|---|
| Meaning | The amount of resources guaranteed | The maximum ceiling |
| Scheduler | Used to pick a node; total requests never exceed node capacity | Ignored when scheduling |
| When exceeded | — | CPU: throttled; memory: container OOMKilled |
Units: CPU in cores, 250m = 0.25 core; memory in bytes, 64Mi = 64 mebibytes (not 64M = 64 megabytes).
If the request is larger than what any node has free, the pod stays Pending with an Insufficient cpu/memory event.
Init containers
flowchart LR I1["init-db<br/>(finished)"] --> I2["init-config<br/>(finished)"] --> A["app<br/>(starts)"]
Init containers run one after another, each must finish successfully before the next starts; the main containers only start after every init container is done, like a class constructor. Use them to wait for dependencies, prepare files or migrate a DB. A failing init container leaves the pod in Init:Error / Init:CrashLoopBackOff.
| Command | Meaning |
|---|---|
kubectl top pod -n dev |
Actual CPU/memory use (needs metrics-server) |
kubectl logs web -c init-db -n dev |
Logs of the init-db init container |
kubectl describe pod web -n dev |
Init container states, OOMKilled reasons |
Quality of Service classes
Kubernetes puts every pod in a QoS class based on its requests and limits:
| Class | Rule | Evicted |
|---|---|---|
| Guaranteed | Every container has CPU and memory requests equal to limits | Last |
| Burstable | At least one request or limit set, but not Guaranteed | Middle |
| BestEffort | No requests or limits at all | First |
kubectl get pod web -o jsonpath='{.status.qosClass}' shows it. Important workloads should be Guaranteed or at least Burstable with realistic requests.
Setting values in practice
- Base requests on observed usage (
kubectl top, Prometheus) rather than guesses; requests that are too high waste nodes, too low cause noisy neighbours. - Always set a memory limit: memory cannot be throttled, so a leak without a limit can push the whole node into pressure.
- CPU limits are debated: they prevent one pod hogging a node but can throttle latency-sensitive apps even when spare CPU exists. Many teams set CPU requests and leave CPU limits generous.
ephemeral-storagerequests and limits cover writable layers, logs, andemptyDir, preventing one pod from filling the node disk.- Special hardware appears as extended resources, for example
nvidia.com/gpu: 1.
The Vertical Pod Autoscaler can recommend or apply request values automatically based on history.
Native sidecars
An init container with restartPolicy: Always becomes a sidecar: it starts before the main containers like other init containers, but keeps running alongside them and stops after them. This fixes the old problem of Jobs never finishing because a sidecar proxy kept running.
initContainers:
- name: log-shipper
image: fluent/fluent-bit:3.0
restartPolicy: Always
Other init container uses
Rendering configuration from a template, downloading a model or static files into a shared emptyDir, setting file permissions on a volume, and registering with an external system are all good jobs for init containers, keeping the main image focused on the application.