Module 2: Pods Deployments And Services
2. What a Pod is, and why you rarely create one directly
Description
A Pod is the smallest unit Kubernetes knows how to schedule — not a container, a Pod. The distinction seems technical until you understand it well: a Pod is a wrapper around one or more containers that share two things no container shares with another by default — a network and, optionally, storage. This lesson installs that concept in depth, so that by lesson 4 (where you create your first real Pod) you know exactly what you're creating and why.
Connection to the module
This lesson and lesson 4 (hands-on) are a single unit split in two: here you understand the concept, there you confirm it with your own hands. Everything you build for the rest of this module — lesson 3's Deployment, lesson 6's Service — exists to manage or expose Pods, never to replace them: a Deployment doesn't replace a Pod, it creates and supervises Pods.
What a Pod is, exactly
Kubernetes' official definition is precise and worth quoting in full: a Pod is "the smallest deployable unit of computing that you can create and manage in Kubernetes," and contains "one or more containers, with shared storage and network resources, and a specification for how to run the containers" — the full definition is in the official documentation (see Resources). Three words in that definition deserve immediate attention:
- "One or more" containers. Most Pods you're going to see in this guide — including
andes-cargo-status-api— have exactly one container. But Kubernetes allows more than one inside the same Pod, for a specific use case: an auxiliary container (called a sidecar) that adds a function to the main container without touching its code — for example, a process that exports metrics or syncs files. This guide doesn't build any multi-container Pod (out of scope, see "Common mistakes"), but you need to know the possibility exists so it doesn't surprise you elsewhere. - "Shared... network resources." All containers inside the same Pod share the same IP address and the same port space — they talk to each other over
localhost, exactly as if they were different processes on the same machine. This is the underlying technical reason the sidecar pattern works: the auxiliary container can reach the main container with no additional network configuration. - "Smallest deployable unit." You can't ask Kubernetes to schedule "half a Pod" or "a container with no Pod around it" — everything that runs on a Kubernetes cluster runs inside some Pod, no exceptions. When you declare a
Deploymentwithreplicas: 3(lesson 3), what thatDeploymentends up creating, underneath, are three Pods — never "three loose containers."
Why a Pod is almost never created directly
Here's this lesson's central point, and the one that gives it its name: in a real production cluster, almost no one declares a Pod object by hand. The reason is simple and you're going to confirm it with evidence in lesson 4: a Pod, on its own, has no self-healing mechanism whatsoever. If the node it runs on fails, or if someone deletes it, or if the process inside crashes in a way not even a restart fixes, no one replaces it. A loose Pod is exactly as fragile as the lone docker run container this module's lesson 1 described — Kubernetes adds it its own IP and a standard way to describe it, but it doesn't add, on its own, any supervision.
What does add supervision is a higher-level controller — almost always a Deployment (lesson 3) — that creates Pods from a template, and replaces them if one disappears. The relationship is one of composition, not replacement: a Deployment isn't "a better Pod," it's a separate object that manages Pod objects.
WHO CREATES WHAT (real object hierarchy)
Deployment ← you declare this (lesson 3, lesson 5)
│
│ creates and manages
▼
ReplicaSet ← Kubernetes creates this for you (lesson 3)
│
│ creates and manages
▼
Pod, Pod, Pod... ← what finally runs (this lesson, lesson 4)
│
│ contains
▼
Container(s) ← what you already knew from Docker
So why do this lesson — and lesson 4 — teach you to create a loose Pod, if "almost no one does it" in production? For the same reason a driving course teaches you manual transmission, even if you end up using automatic your whole career: understanding the simplest piece, with no management layer on top, is what lets you understand exactly what each layer you actually will use adds. Lesson 4 lets you see, with your own hands, that a deleted Pod disappears forever — the exact contrast lesson 5 (the real Deployment) is going to confirm in the opposite direction.
When creating a loose Pod does make sense
Not never — there are legitimate cases, though none is "running a production service":
- Quick debugging, when you need a temporary container inside the cluster to test something (for example,
curlagainst aServicefrom inside the cluster's network, a pattern you're going to use in lesson 7 of this same module). - One-off jobs that run to completion and don't need to restart (though, in practice, even those cases are usually better modeled with a
Jobobject, which Kubernetes offers specifically for this and which is out of this guide's scope). - Learning, exactly what you're going to do in lesson 4 — the only way to clearly see what a loose Pod is missing is to have one really running, with nothing else around it.
andes-cargo-status-api, this guide's real service, is never declared as a loose Pod — from lesson 5 onward, it always lives inside a Deployment. That's the decision this entire lesson justifies.
A Pod's minimal anatomy
Before lesson 4, it's worth looking at the general shape of a Pod manifest, without running it yet — you're going to recognize it immediately when you get there:
apiVersion: v1
kind: Pod
metadata:
name: <pod-name>
labels:
app: <label>
spec:
containers:
- name: <container-name>
image: <image:tag>
ports:
- containerPort: <port>
Four fields deserve a note before moving on:
apiVersion: v1— Kubernetes' oldest and most stable objects (Pod, Service, Namespace, ConfigMap, Secret) live in the "core" API group, identified simply asv1. You're going to see different groups —apps/v1forDeployment, in lesson 3 — as objects get more recent or more specialized.kind: Pod— the samekindfield you already saw inkind-config.yamlin Module 1, now with a different value. It tellskube-apiserverwhat type of object this document describes.metadata.labels— an arbitrary key-value pair that "sticks a label" on the object. It's not decorative: it's the exact mechanism aServiceis going to use in lessons 6 and 7 to know which Pods it should route traffic to — without a matching label, aServicehas no way to find its Pods.spec.containers— a list, not a single value, precisely because a Pod allows more than one container (though, in this guide, you're always going to declare exactly one).
Analogy: the individual office, not the building
Picking back up the introductory module's analogy: if a Deployment is the building's thermostat and a Service is the switchboard, a Pod is the individual office — it has everything it needs to function inside (the container, its own network address, any storage it shares with another container in the same Pod), but it doesn't decide on its own when it's occupied, when it's vacated, or what happens if someone closes it without notice. Those decisions are made by the building — the Deployment — not the office. An office with no administration department behind it (a loose Pod) can stay empty forever if someone leaves, with no one noticing or fixing it — exactly what you're going to confirm in lesson 4.
Deep dive: a Pod's lifecycle
A Pod goes through a sequence of phases, visible in the STATUS column of kubectl get pods (you're going to see it for real in lesson 4):
Pending— the object already exists inetcd, but at least one of its containers hasn't started yet (for example, while the image is downloading).Running— the Pod was assigned to a node, and all its containers started (though not necessarily "ready" to receive traffic — that's a separate distinction,readiness, which you go deeper on in Module 3).Succeeded— all containers in the Pod finished successfully, and won't restart. Uncommon for an HTTP service likeandes-cargo-status-api, designed to run indefinitely; more common for one-off jobs.Failed— at least one container ended with an error code, and the Pod isn't going to be retried (according to itsrestartPolicy).Unknown— the Pod's state couldn't be determined, typically because the node it lives on stopped responding.
An important detail you're going to confirm in lesson 4: when you delete a Pod with kubectl delete pod, it doesn't go through any of these "error" phases — it simply stops existing. There's no fifth "Deleted" state you see in kubectl get pods, because the object is no longer there to report any state.
Common mistakes
Thinking "container" and "Pod" are interchangeable synonyms (conceptual, the most widespread mistake in any Kubernetes introduction). What happens: someone uses "I spun up a container" and "I spun up a Pod" as if they were the same phrase, and that confusion becomes a real problem when they try to understand why a Pod can have more than one container inside it. Why it happens: in the vast majority of practical cases — including every example in this guide — a Pod contains exactly one container, so the distinction seems unnecessary until a case with two shows up. How to spot it: if you struggle to explain why two containers inside the same Pod share the same IP, while two different Pods never share it. How to fix it: a Pod is the wrapper; a container is what goes inside. You can have a Pod with one container (this guide's case) or with several (sidecar pattern, out of scope here) — but never a container "without" a Pod in Kubernetes.
Expecting Kubernetes to automatically replace a loose Pod, because "that's what Kubernetes does" (conceptual, the exact one this lesson exists to prevent). What happens: someone creates a Pod directly (no Deployment), deletes it by accident or loses it to a node failure, and expects to see a new Pod appear on its own — as they remember happening in some tutorial that used a Deployment without them noticing the difference. Why it happens: Kubernetes' "self-healing" reputation is real, but it's a property of controllers (Deployment, ReplicaSet, among others), not of kube-apiserver in general or of an individual Pod. How to spot it: if you deleted a Pod with kubectl delete pod and kubectl get pods still shows the empty result several minutes later, that's exactly the correct behavior for a loose Pod — not a bug. How to fix it: lesson 4 shows you this behavior with your own hands, on purpose, so the distinction is installed before lesson 5.
Assuming a multi-container Pod is the normal way to run an application with several pieces (conceptual, a common misunderstanding for anyone coming from Docker Compose). What happens: someone used to docker-compose.yml, where each service (for example, an API and a database) is a separate container within the same file, assumes the Kubernetes equivalent is putting both containers inside the same Pod. Why it happens: the visual parallel between "several services in one file" (Compose) and "several containers in a Pod" is tempting, but wrong. How to spot it: if you're about to put two independent services — each with its own lifecycle, its own need to scale separately — inside the same Pod. How to fix it: the correct pattern in Kubernetes is one Pod (and, above it, one Deployment) per independent service — andes-cargo-status-api is going to have its own, and if this guide had a second service, it would have its own too, communicating over the network via Service (lesson 6), not sharing the same Pod. Multi-container in the same Pod is reserved for the sidecar pattern, where the auxiliary container exists specifically to support the main one, not to be an independent service.
Exercises
Exercise 1 — Explain the hierarchy without looking at the diagram. Without going back to the "Why a Pod is almost never created directly" section, draw (in text, with arrows) the complete hierarchy from Deployment down to Container, and explain in one sentence what each level does.
See solution
Deployment (what you declare) → creates and manages → ReplicaSet (Kubernetes creates it automatically, keeps the replica count) → creates and manages → Pod (the minimum schedulable unit, what finally runs) → contains → Container(s) (the real process, the same piece you already knew from Docker). Each level exclusively manages the level immediately below it — a Deployment never touches a container directly, it always goes through a ReplicaSet and a Pod.
Exercise 2 — Diagnose a real case. A coworker accidentally deletes a Pod that was running inside a Deployment with replicas: 3. What would you expect to see in kubectl get pods thirty seconds later? And what if that same Pod had been created directly, with no Deployment behind it?
See solution
With a Deployment in the mix: thirty seconds later, kubectl get pods should show three Pods again — the deleted one disappears, and the Deployment's ReplicaSet creates a new one (with a different name, a new hash suffix) to get back to the three declared replicas. With no Deployment behind it (a loose Pod): kubectl get pods would show, thirty seconds later, exactly the same thing it showed right after the deletion — nothing, because there's no controller supervising that specific Pod.
Exercise 3 — Identify the correct field. Looking at this lesson's "A Pod's minimal anatomy," which manifest field would you use so that a future Service (lesson 6) can find this Pod among several others? Justify your answer with what you learned about that field.
See solution
metadata.labels — a Service doesn't find Pods by their name (which, on top of that, includes a randomly generated suffix when the Pod comes from a Deployment), but by the labels that match its own selector. A Pod without the correct label, even if it's running perfectly, is invisible to any Service looking for a different label — exactly the mechanism you develop in depth in lessons 6 and 7 of this module.
Summary and next step
In this lesson you understood what a Pod is, exactly: Kubernetes' smallest deployable unit, a wrapper around one or more containers that share network and, optionally, storage — and, above all, you understood why one is almost never created directly in production: a loose Pod has no self-healing mechanism whatsoever, that property gets added by a higher-level controller. You saw the complete hierarchy (Deployment → ReplicaSet → Pod → container(s)), a Pod manifest's minimal anatomy, and its lifecycle's phases.
Before moving on you should be able to: explain the difference between a container and a Pod without using them as synonyms; predict what happens (and what doesn't) when a loose Pod is deleted versus one managed by a Deployment; and recognize a Pod manifest's four main fields.
Next lesson: Deployments, ReplicaSets, and the declarative control loop. That's where the piece that solves exactly what a loose Pod doesn't solve comes in — who decides how many offices should be occupied, and who quietly acts, with no one asking, when reality doesn't match that decision.
Resources
- Kubernetes — Pods — the complete official reference, including the definition quoted in this lesson.
- Kubernetes — Pod Lifecycle — a Pod's lifecycle phases, developed in this lesson's deep-dive section.
- Kubernetes — Init Containers — official reference on multi-container patterns inside a Pod, mentioned by contrast in this lesson (out of this guide's scope).