CoursesKubernetes fundamentalsPods, a little deeper

Pods, a little deeper

What is really inside a pod.

Beginner10 min · lesson 6 of 24
In plain terms
A pod is a lunchbox holding one main container (and sometimes a small helper) that share the same little space. It’s the smallest thing Kubernetes hands out — or throws away.

You started a pod in the last lesson. Now let's slow down and look at what a pod really is, because every other Kubernetes idea sits on top of it.

Start with a shipping container. It packs everything a product needs into one box, so the same box moves onto a truck, a ship, or a train without anyone repacking it. A software container does that for a program: it bundles your app together with the exact files and settings it needs, so the app runs the same way on any machine. A pod is the small crate Kubernetes puts that container into before handing it to a machine to run.

What's actually inside a pod

A pod is one or more containers that run together on the same node and share a single network address. A node is just one machine in your cluster, and a cluster is the whole set of machines Kubernetes has to run your apps on. A node can be a physical computer or a virtual one. Most pods hold exactly one container, which is your app. A few hold two, when the second container is a small helper that has to sit right next to the app, like one that collects the app's logs and ships them off.

The containers in a pod are like roommates sharing one small apartment. They live behind the same front door, which is a single IP address (the numeric address computers use to find each other on a network). Because they share it, they can talk to each other over localhost, a shortcut that means 'the same machine I'm on', instead of routing a message across the network. They can share storage too, the way roommates share a fridge.

Here's the part beginners often miss. The pod, not the container inside it, is the smallest unit Kubernetes manages. When Kubernetes decides where to run something, moves it, or counts how many copies exist, it works in whole pods. So a pod is really a group of containers that live and die together, sharing an address and sometimes some files.

Below is a complete pod written as YAML. YAML is a plain-text format for describing settings that people can read without much effort. Save it as pod.yaml:

pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello
labels:
app: hello
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80

Read it top to bottom. apiVersion and kind together tell Kubernetes 'this is a Pod'. metadata.name gives the pod a name you'll use to refer to it. The label just under it, app: hello, is a sticker you can search for later. spec is the actual request: run one container named web from the nginx image. An image is a ready-made package a container is built from, and nginx is a popular free web server. The last line says the container listens on port 80, a numbered doorway where a program waits for incoming requests.

Send it to the cluster with apply, which means 'make the cluster match this file':

Terminal
kubectl apply -f pod.yaml
Output
pod/hello created

Check on it:

Terminal
kubectl get pods
Output
NAME READY STATUS RESTARTS AGE
hello 1/1 Running 0 12s

Add -o wide to see which node it landed on and the IP address it was given:

Terminal
kubectl get pod hello -o wide
Output
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello 1/1 Running 0 30s 10.244.1.7 worker-1 <none> <none>

When a pod keeps crashing

Not every pod turns Running. Sometimes the container starts, runs into a problem, and quits within seconds. Here's a pod built to fail on purpose, so you can see what that looks like before it happens to a real app. Save it as crasher.yaml:

crasher.yaml
apiVersion: v1
kind: Pod
metadata:
name: crasher
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo starting; sleep 2; echo 'config missing, giving up'; exit 1"]

The container prints a line, waits two seconds, complains that some config is missing, then exits with code 1, the number a program uses to say 'I failed'. Apply it:

Terminal
kubectl apply -f crasher.yaml
Output
pod/crasher created

Give it a minute for a few restarts to pile up, then list your pods:

Terminal
kubectl get pods
Output
NAME READY STATUS RESTARTS AGE
crasher 0/1 CrashLoopBackOff 3 (38s ago) 2m

Three columns tell the whole story. READY says 0/1: none of the pod's one container is up. RESTARTS is climbing, and the (38s ago) means the last restart was moments ago, so something keeps dying. STATUS is CrashLoopBackOff: Kubernetes is restarting the container, but waiting a little longer before each attempt (backing off) so a broken pod can't hammer the node at full speed. It is not stuck; it is looping.

To learn why it quit, read its logs. The container that failed has already been swept away and replaced by the one now waiting to start, so ask for the previous one with --previous:

Terminal
kubectl logs crasher --previous
Output
starting
config missing, giving up

There it is, printed by the container just before it died. Real apps crash for real reasons too: a missing environment variable, a database they can't reach, a typo in the start command. When the logs aren't enough on their own, kubectl describe pod crasher adds the events Kubernetes recorded, including every restart and, if the image name itself is wrong, an ImagePullBackOff instead of a crash.

Clean up the crasher before moving on:

Terminal
kubectl delete pod crasher
Output
pod "crasher" deleted

Pods come and go

The most important thing to know about pods is that they're ephemeral, which just means short-lived and replaceable. A pod gets an IP address when it starts and loses it when it stops. Kubernetes never picks a running pod up and carries it to another machine. If a pod needs to run somewhere else, say its node just died, Kubernetes deletes the old pod and creates a brand-new one in its place, with a brand-new IP.

There's a common way to describe this: pods are cattle, not pets. You give a pet a name and take it to the vet; on a farm, you replace what breaks and move on. Kubernetes keeps your app healthy by replacing pods, not by nursing any single one. That's also why you rarely create pods by hand. Normally a controller does it for you. A controller is a background helper that watches your pods and keeps reality matching what you asked for, so when a pod disappears it starts a replacement automatically. Deployments and ReplicaSets are controllers, and they're next.

You can feel the disposability for yourself. Delete the pod you made by hand:

Terminal
kubectl delete pod hello
Output
pod "hello" deleted

Now list the pods again:

Terminal
kubectl get pods
Output
No resources found in default namespace.

Nothing came back. You created that pod directly, so no controller was watching it, and Kubernetes had no standing instruction to keep one running. That's exactly the difference a controller makes, and it's the reason you'll almost never run a bare pod in real life.

A pod's short life
1You apply pod.yamlkubectl asks the cluster to…2Kubernetes placesitthe pod lands on a node and is…3The pod runsyour nginx container serves…4The node fails oryou delete itthe pod and its IP are gone…5A controller makesa new onea brand-new pod with a…

A Pod is the scheduling unit: one or more containers that share network namespace and volumes, always scheduled together on one node. Sidecars exist because of that shared fate — a log shipper next to an app shares localhost and can mount the same volume.

Pods are mortal. Controllers recreate them. Prefer designing apps that tolerate replacement: store state outside the container filesystem, use readiness probes before taking traffic, and do not rely on a stable Pod name or IP.

In an incident, kubectl get pods -o wide tells you which node hosts the problem. That is how you decide whether to drain a node or chase an app bug instead of versus treating every CrashLoop as a cluster failure.

Try this

Inspect a running Pod's IP, node, and container list. Exec into it to confirm shared network namespace basics.

terminal
$ kubectl run p1 --image=nginx:1.27 --restart=Never
pod/p1 created
$ kubectl get pod p1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE
p1 1/1 Running 0 6s 10.244.1.21 kind-worker
$ kubectl get pod p1 -o jsonpath='{.spec.containers[*].name}{"\n"}{.status.podIP}{"\n"}'
web
10.244.1.21
$ kubectl exec p1 -- nginx -v
nginx version: nginx/1.27.0
$ kubectl delete pod p1
pod "p1" deleted

Takeaway

Pods co-locate containers with a shared network and fate, but Pods themselves are disposable. Design for replacement, and use -o wide plus describe when you need to know which node and IP are in play.

Don't wire anything to a pod's IP
A pod's IP address only lasts as long as that exact pod. The moment the pod is replaced, and it will be, the address changes and whatever you pointed at it breaks. This is the problem Services solve: a Service gives you one stable address that always forwards to whatever pods are currently alive. Reach your workloads through a Service, never through a raw pod IP.
Quick check
01A pod running your app dies when its node fails, and Kubernetes brings the app back on a healthy node. What happens to the IP address?
Incorrect — No. Kubernetes doesn't move a pod or its address. The old pod is gone, and its IP went with it.
Correct — The old pod is deleted and a brand-new one is created with its own new IP. That's exactly why you never rely on a pod's IP.
Incorrect — No. The old pod isn't coming back. Its IP is released the moment it's deleted.
02A pod holds two containers: your app and a small helper that ships the app's logs. How do those two containers communicate with each other?
Correct — containers in one pod are like roommates behind the same front door; they share one IP address and reach each other over localhost.
Incorrect — a Service gives a stable address for reaching pods from outside; containers inside the same pod already share an address and do not need one.
Incorrect — the containers in a pod share one IP address rather than getting separate ones; that shared address is the whole point.
Incorrect — they are deliberately placed close together, sharing a network address and often shared storage.
03kubectl get pods shows crasher at 0/1 CrashLoopBackOff with RESTARTS climbing. You want to read what the container printed just before it last died. Which command gives you that?
Incorrect — -o wide adds node and IP-address columns but shows nothing the container printed.
Incorrect — the failed container was already swept away and replaced by the one now waiting to start, so this may show nothing useful.
Correct — the crashed container has been replaced, and --previous pulls the logs from that prior instance, where the failure message was printed.
Incorrect — deleting throws away the evidence; you want to read the previous container's logs, not restart the loop.

Related