0%
Containers and Kubernetes: From cgroups to Operators
What a Container Actually Is
Working with Docker
Kubernetes Architecture
Scheduling and Resources
Networking and Storage
Extending Kubernetes
Pods and the Pod Lifecycle
A pod is not a container and not a small virtual machine; it is a set of containers sharing a specific list of kernel namespaces, and every property that makes pods useful or awkward follows from exactly which namespaces are shared.
The namespaces that are shared and the ones that are not
The sharing list is short, deliberate and worth memorising.
Containers in a pod share the network namespace, which means one address, one set of ports and a shared loopback interface. They share the inter-process communication namespace, so shared memory segments and semaphores work between them. They share the host name namespace, so they agree on a host name. They optionally share the process namespace, which is off by default.
They do not share the mount namespace, so each has its own filesystem view, which is why sharing files requires an explicit volume mounted into both. They do not share the user namespace unless it is configured. And each has its own control group leaf, so limits are per container rather than per pod.
The practical reading of that list: two containers in a pod can talk over the loopback interface with no configuration, and cannot see each other's files without one.
The sandbox and the paused process
The shared namespaces have to belong to something, and that something is an extra container nobody writes.
The node agent creates a sandbox first: a container running a tiny process that does nothing but hold the namespaces open, conventionally sleeping forever after reaping children. Every other container in the pod joins that sandbox's namespaces. The address belongs to the sandbox, not to any application container.
This explains behaviour that is otherwise puzzling. Restarting an application container keeps the pod's address, because the sandbox was not restarted. Losing the sandbox means losing the address and restarting every container in the pod. And a pod stuck with a sandbox creation failure shows no container errors at all, because no application container was ever attempted.
Atomic scheduling and what it commits you to
A pod is scheduled as a unit, which is the strongest statement in the model and the one with the most consequences.
Every container in a pod runs on one node, at one time, and the node must satisfy the sum of their requests. There is no partial placement: if the node cannot fit all of them, the pod does not run. And they share a fate, since deleting the pod removes all of them.
So the decision to put two things in one pod is a decision that they scale together, fail together, are upgraded together and are placed together. That is right for a process and its local helper and wrong for two services that merely talk to each other, which is the most common misuse. The question that settles it is whether you would ever want different replica counts for the two, and if the answer is yes they belong in separate pods.
Pods are nearly immutable, and why
Almost nothing in a running pod can be changed, which is a design choice rather than a limitation.
The fields that can be updated are few: the image of a container, the active deadline, tolerations by addition only, and in recent versions resource requests and limits for containers that support in-place resizing. Everything else, including most of the specification, is rejected on update.
The reason is that a pod's placement was decided from its specification, so changing the specification would invalidate the decision. Rather than re-evaluating placement, the model treats a pod as a disposable instance of a template and expects changes to be made by creating a new pod. Every workload controller exists to make that replacement convenient, which is why the right mental model is that you never edit pods, you replace them.
What the pod object actually carries
Reading the object once with attention explains a lot of later behaviour.
The specification carries the containers with their images, commands, resources, volume mounts, probes and environment; the volumes; the scheduling constraints; the service account; the security context; and the termination grace period. The status carries the phase, the conditions, the host and pod addresses, the per-container states with restart counts, and the quality of service class the system computed.
Two fields repay attention. The node name, which is empty until the scheduler writes it and whose appearance is the moment scheduling completed. And the computed quality of service class, which is derived rather than set and determines eviction order, which is covered in its own lesson.
The pause between creation and running
The gap between a pod existing and a pod running has several named stages, and knowing them makes diagnosis faster.
The object is created and admitted. The scheduler selects a node and writes the binding. The node agent on that node observes the pod, sets up volumes, pulls images if needed, creates the sandbox, runs init containers in order, then starts the application containers. Each of those can fail with a distinct symptom, which is the subject of the third section.
The useful consequence is that a pod's delay can be attributed by asking which stage it is in rather than by guessing. A pod with no node name is a scheduling problem. One with a node name and no container statuses is a node agent, volume or image problem. One with containers running and not ready is an application problem.
Process namespace sharing, and when to use it
One optional sharing setting is worth knowing because it solves a specific debugging problem.
With process namespace sharing enabled, every container in the pod sees the others' processes, and each container's filesystem becomes reachable through the process filesystem at a path derived from its process identifier. That is how a debug container reads a file from an application container that has no shell.
The costs are real, which is why it is off by default. Containers can signal each other's processes, the isolation between them weakens, and the first process in each container is no longer process one, which changes how signals are delivered and breaks images that assume they are the init process. Enabling it for a production pod to make debugging convenient is a trade most teams should decline, and the debug container with a share requested at attach time is the better route.
The user namespace, briefly
The remaining namespace is the one that changes the security picture most, and it is newer.
With user namespace support, a container's root user maps to an unprivileged user on the host, so a process that believes it is root has no privilege outside its namespace. That turns a container escape from a host compromise into a much smaller problem, and it is the single strongest isolation improvement available without a different runtime.
The practical caveats are that it needs support in the runtime and the kernel, that file ownership on volumes has to account for the mapping, and that it is not yet the default. It is worth knowing as the direction of travel and worth testing, rather than assumed present.
The one pod you will write by hand
Almost all pods come from controllers, and the exception is worth naming.
A debugging pod, created directly to run a tool in the cluster's network with a particular service account, is the legitimate case for writing a pod object: it has no desired-state semantics, nothing should recreate it, and it should be deleted when the task is done. Everything else, including anything that should survive a node failure, belongs behind a controller.
The anti-pattern is a bare pod running something important. Nothing recreates it after a node failure, nothing replaces it during a drain other than deleting it, and nothing records what it was supposed to be. It survives until the first node replacement and then quietly does not.
A strong answer defines a pod by the namespaces it shares, network, inter-process communication and host name, with mount namespaces deliberately separate, and explains that the sandbox holds those namespaces and the address, which is why a container restart preserves the address. It then derives the co-location decision from atomic scheduling: containers in a pod scale, fail, upgrade and are placed together, so the test for combining them is whether you would ever want different replica counts.