Pods

Pods

The smallest schedulable unit. Not a container - an environment for one or more containers.

graph TB subgraph pod [Pod - one IP, one network namespace] C1[container: app] C2[container: sidecar] V[(shared volume)] C1 --- V C2 --- V end

Containers in a Pod share the IP address, ports, IPC and volumes, and always run on the same node. They talk over localhost. This is the --network container: mode from Docker, made into a first-class object.

Minimal manifest

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80
      resources:
        requests: { cpu: "50m", memory: "64Mi" }
        limits:   { cpu: "200m", memory: "128Mi" }

Requests decide where the Pod is scheduled - the scheduler subtracts them from the node’s allocatable capacity. Limits decide what happens under pressure: CPU over the limit is throttled, memory over the limit is an OOM kill. A Pod without requests is a scheduling gamble.

Lifecycle

Pending -> Running -> Succeeded / Failed, plus CrashLoopBackOff when a container keeps dying. restartPolicy defaults to Always.

Pending means the scheduler has not placed it (no capacity, unbound PVC, a taint). ContainerCreating means it is placed and the kubelet is working - image pull, volume mount.

Init containers and sidecars

spec:
  initContainers:
    - name: wait-for-db
      image: busybox
      command: ["sh", "-c", "until nc -z db 5432; do sleep 2; done"]

Init containers run to completion, in order, before the app containers start. That is how you express “do not start until the database answers”.

In practice

You rarely create bare Pods. A bare Pod is never rescheduled when its node dies - use a Deployment. Bare Pods are for debugging and one-shot tasks.

kubectl run tmp --image busybox --restart=Never -it --rm -- sh

References