Run kubectl run nginx --image=nginx:1.27 and Kubernetes creates exactly one Pod named nginx. Delete it with kubectl delete pod nginx and it is gone for good — nothing notices, nothing replaces it. A Pod is the smallest deployable unit in Kubernetes: one or more containers that share a network namespace and a set of volumes, scheduled together onto a single node.
That single Pod is a dead end in production. If the container inside it crashes, the kubelet restarts the container in place. If the node reboots, or someone deletes the Pod, nothing recreates it. A bare Pod has no memory of the fact that it is supposed to exist.
What a Deployment adds on top of a Pod
A Deployment is a Kubernetes object that says how many copies of a Pod should exist and how to roll out changes to them. You stop managing Pods directly and describe the desired state instead; a control loop keeps making that state true. It is the same reconciliation model behind everything else in Kubernetes.
| |
| |
| |
Three Pods, not one, and none of them are named web-app. That naming pattern (web-app-7d9f8c7b86-4kxqz) is the first sign that something else is managing them.
replicas: 3 is the same instruction you give with docker compose up --scale web=3 in Docker Compose. The difference is that here a controller keeps enforcing the number long after the command exits.
How a Deployment actually creates Pods: the ReplicaSet in between
A Deployment does not create Pods directly. It creates a ReplicaSet, and the ReplicaSet creates the Pods. You can see the whole chain:
| |
| |
The ReplicaSet’s name is the Deployment’s name plus a hash of the Pod template (7d9f8c7b86); each Pod’s name is the ReplicaSet’s name plus a random suffix. kubectl describe pod web-app-7d9f8c7b86-4kxqz shows the relationship directly, in the Controlled By field: ReplicaSet/web-app-7d9f8c7b86.
Delete one of those Pods and the count drops to 2. Within seconds a replacement appears. That is the ReplicaSet noticing the gap and creating a new Pod from the same template, not the Deployment acting directly. The ReplicaSet does the watching. The Deployment exists for the one thing a ReplicaSet cannot do on its own: replace a Pod template gradually instead of all at once.
What a rollout does to the ReplicaSets
Change the image and apply it:
| |
| |
Behind that status line, the Deployment created a second ReplicaSet for the new Pod template and scaled it up while scaling the old one down. With the default RollingUpdate strategy on 3 replicas, that works out to one Pod at a time:
| |
| |
The old ReplicaSet is not deleted. It stays at zero replicas, keeping the previous Pod template on record. That is what makes rollback fast:
| |
Kubernetes scales the old ReplicaSet back up and the new one down — no rebuild, no re-pull of an old image if it is still cached on the node. kubectl rollout history deployment/web-app --revision=1 still shows exactly which image that revision ran.
When a bare Pod is the right call
A bare Pod is not a mistake in every context, only in most of them:
- A one-off diagnostic container you will delete in five minutes:
kubectl run debug --image=busybox -it --rm -- sh. - A Job or CronJob, which creates Pods through its own controller because the work has to run to completion rather than stay up.
- Inspecting or learning the Pod spec itself, before wrapping it in something that manages it.
Anything meant to stay running through a crash, a node failure or an update goes through a Deployment. Or a StatefulSet, for Pods that need a stable identity and their own storage — a different problem, and a different object. Write the Deployment manifest by default and drop to a bare Pod only for the three cases above.
Pod, ReplicaSet, and Deployment side by side
| Pod | ReplicaSet | Deployment | |
|---|---|---|---|
| What it manages | Containers | Pods | ReplicaSets |
| Replaces a deleted instance | No | Yes | Yes, via its ReplicaSet |
| Scales to N replicas | No | Yes | Yes |
| Rolling updates | No | No | Yes |
| Rollback to a previous version | No | No | Yes |
| You create it directly | Rarely | Almost never | Normally |
Check whether your own Pods have a Deployment behind them
Run this against whatever is already in your cluster:
| |
If only Pod rows come back, those are bare Pods. That is the gap to close before the next node drain takes the app down with them.