Pods — the basic unit of Kubernetes
Here's a surprise for a lot of people: Kubernetes never schedules a container on its own. It schedules pods. A pod is the atom of the cluster — small, cheap, and meant to be thrown away.
What a pod actually is
A pod is a bundle of one or more containers that share a few things:
- An IP address — every pod gets its own private cluster IP.
- A network namespace — all containers in the pod see each other on
localhost. - Storage volumes — mounted into any container in the pod.
- A lifecycle — the pod's containers start together, stop together, and get rescheduled together.
Nearly every pod you meet holds exactly one container. You reach for a multi-container pod when you've got a tightly-coupled sidecar — a logging agent, a service-mesh proxy, an init helper that needs to live and die on the same lifecycle as the main app.
Every pod gets its own IP
If you remember one networking fact about Kubernetes, make it this one:
- Every pod has a unique cluster-wide IP.
- Any pod can reach any other pod's IP directly — no NAT.
- Pods on the same node reach each other without going through the host's public interface.
So pod-to-pod networking feels a lot like old-school VMs sitting on one flat network. Containers inside the same pod chat over localhost; when one pod talks to another, that traffic rides the cluster network — a CNI overlay like Calico or Cilium.
The trouble with pods that keep vanishing
Pods are cattle, not pets. They die, get rescheduled, and get recreated constantly — every deploy, every scale-down, every node failure, every update. And each time one comes back, it comes back with a brand-new IP. So you can't hardcode a pod's IP anywhere and expect it to hold.
When one pod suddenly can't talk to another after a deploy or a restart, nine times out of ten someone pinned a pod IP somewhere — a config file, an env var, a hardcoded address. That IP is gone the moment the pod was recreated. The fix is never to chase the new IP; it's to point that connection at a Service name instead, which stays put no matter how often the pods behind it churn.
And that's exactly the gap the next topic — Services — was built to fill.
A minimal pod manifest
apiVersion: v1
kind: Pod
metadata:
name: hello
labels:
app: hello
spec:
containers:
- name: web
image: ghcr.io/example/hello:1.0
ports:
- containerPort: 8080
In real life you'll almost never hand-create a pod like this. You wrap it in a Deployment, StatefulSet, DaemonSet, or Job, and that wrapper quietly brings your pods back whenever they die.
Try it yourself
kubectl run tmp --image=busybox --rm -it --restart=Never -- sh
# See pod IPs
kubectl get pods -o wide
# Exec into a pod
kubectl exec -it <pod> -- sh
# Reach another pod by its cluster IP
wget -qO- 10.244.2.9:8080
Key takeaways
- A pod is Kubernetes' scheduling unit — usually one container, sometimes with sidecars.
- Containers in a pod share IP, ports, network namespace, and volumes.
- Every pod has a unique cluster IP; any pod can reach any other pod's IP.
- Pod IPs are ephemeral — never hardcode them; wrap pods behind Services.