Every workload ends up as pods; understanding them explains IPs, restarts, logs and sidecars.
A pod is the smallest thing Kubernetes schedules. It wraps one or more containers that:
- share one IP address and port space (they reach each other on
localhost), - can share volumes,
- always land on the same node and live and die together.
Most pods have one main container. Extra containers are for tightly coupled helpers: init containers run to completion before the app starts (wait for a database, run migrations), and sidecar containers (init containers with restartPolicy: Always) run alongside it for things like log shipping or proxies.
Pods are ephemeral. Each gets a new IP when recreated, and a pod is never moved: if its node dies, a controller creates a new pod elsewhere. That is why you almost never create bare pods; you create a Deployment, Job or StatefulSet that manages them.
Key container fields: image, command/args (override the image's ENTRYPOINT/CMD), ports (documentation only), env, resources, probes.
A pod's status.phase is Pending, Running, Succeeded, Failed or Unknown; the STATUS column of kubectl get pods also shows reasons like ContainerCreating or CrashLoopBackOff. restartPolicy (Always, OnFailure, Never) decides whether the kubelet restarts exited containers in place.
Example
apiVersion: v1
kind: Pod
metadata:
name: hello
labels: {app: hello}
spec:
initContainers:
- name: wait-db
image: busybox:1.37
command: ["sh", "-c", "until nc -z db 5432; do sleep 2; done"]
containers:
- name: app
image: python:3.13-slim
command: ["python", "-m", "http.server", "8000"]
ports:
- containerPort: 8000
# kubectl apply -f pod.yaml
# kubectl get pod hello # Init:0/1 until a "db" service answers, then RunningRemember
- Containers in a pod share IP, localhost and volumes
- Pods are disposable: new pod, new IP, never moved
- Use controllers (Deployment, Job...) rather than bare pods
Watch out for
- Putting two independent services in one pod so they can talk on localhost: they then can't scale or deploy separately.