Module 2: Pods Deployments And Services

1. Introduction: from a container to a managed workload

Description

Module 1 left you with a real, healthy cluster, with the andes-cargo-status-api:latest image available in the internal containerd of its three nodes — and no Pod running yet. That's exactly where what docker run alone can give you ends, and where this module begins: the first time, in this entire guide, that a Kubernetes object actually runs Andes Cargo's service. You're going to build, in order, the three primitives that support absolutely everything else that appears in the six modules that follow — Ingress, NetworkPolicy, ArgoCD, Gatekeeper, down to what's specific to EKS — because none of those pieces make sense without a Pod running behind them.

Connection to the module

This module has a deliberate progression, from simplest to closest to production: first you understand what a Pod is and why almost no one creates one loose (lessons 2 and 4); then you understand why, in practice, almost everyone uses a Deployment instead (lessons 3 and 5); and finally you resolve the problem that neither a Pod nor a Deployment solves on its own — how you talk to a group of Pods that come and go without the address you point at ever changing — with a Service (lessons 6 and 7). Lesson 8, the project, brings all three pieces together into a single system: andes-cargo-status-api running with several replicas, exposed by a Service with a stable name, surviving you deleting a Pod on purpose.


What docker run is missing that Kubernetes resolves

You already ran andes-cargo-status-api with docker run in aws-serverless-and-containers-guide (Module 6). It worked — the container started, responded to curl, all fine. This module's question is a different one: what happens after? Four scenarios, each with docker run alone's real answer versus Kubernetes':

Scenariodocker run aloneKubernetes (what this module builds)
The process inside the container dies (unhandled exception, OOMKilled)The container stops. No one restarts it unless you added --restart=always by hand, and no one audits whether that flag is on every docker run in your fleetThe node's kubelet detects the crashed container and restarts it according to the Pod's restartPolicy — always, by default. With no one asking in the moment
You need three instances running at the same time, not oneYou run docker run three times by hand, with three different names, and keep track yourself of which ones are still aliveYou declare replicas: 3 once; a controller inside the cluster keeps that exact number, always, with no one checking by hand
One of those three instances goes downSomeone (a person, an external script) has to notice the crash and run docker run againThe same controller that maintains the replica count notices the gap between "3 desired" and "2 running," and creates a fourth one with no one intervening — this is, literally, lesson 3's entire topic
You need a single stable address to talk to whichever of those three instances, without caring which one respondsYou build your own mechanism — an external load balancer, a list of IPs you maintain by hand, something — because every container has its own IP, and that IP changes every time it's recreatedA Service gives you a name and an address that never change, even though the Pods behind it rotate constantly — the whole topic of lessons 6 and 7

None of the columns on the right are magic. Each one is a controller running inside the cluster itself, constantly comparing "what you declared" against "what really exists," and acting only when there's a gap — the same pattern, no exceptions, you're going to see over and over for the rest of this guide (GitOps with ArgoCD in Module 5 is exactly this same pattern, applied to an entire Git repository instead of a replica count).


This module's map: the 8 lessons

#LessonWhat you build
1Introduction (this one)What docker run is missing, the module's map
2What a Pod is, and why almost no one creates one looseThe concept: Kubernetes' minimum schedulable unit
3Deployments: ReplicaSets and the declarative control loopThe concept: desired vs. imperative state, who reconciles
4Hands-on: your first PodExecuted: kubectl run/kubectl apply -f pod.yaml, describe, delete
5Hands-on: andes-cargo-status-api's DeploymentExecuted: the real Deployment running, a Pod deleted and replaced on its own
6Services: ClusterIP, NodePort, and stable addressesThe concept: the ephemeral-IP problem, Service types
7Hands-on: exposing status-api-serviceExecuted: port-forward, real curl /health against the Service
8Project: andes-cargo-status-api with N replicasExecuted: 3 replicas, load balancing confirmed, a Pod replaced on its own

This module's analogy: an office building, not a loose desk

You're going to see this same analogy develop across the upcoming lessons, so it's worth laying it out from the start. Think of docker run as renting a loose desk in a coworking space with no management whatsoever: if you leave, no one notices the desk is now empty; if you need three desks, you rent them yourself, one at a time; and if someone asks "where do I sit you today?", the answer changes every time you move desks.

A real office building, by contrast, has systems that solve exactly those three problems with no one operating them by hand: a thermostat that keeps the building's temperature in the range someone configured once, with no one having to adjust it every time a door opens and closes — that's a Deployment (lesson 3); and a switchboard with a fixed extension number, that routes the call to whoever is available behind that extension at that moment, with no need for the caller to know who's answering today — that's a Service (lesson 6). A Pod, in this same analogy, is the individual office itself: it has everything it needs inside (desk, chair, network line), but it's the building — not the office — that decides when it gets reassigned or vacated.

              FROM A LOOSE DESK TO A MANAGED BUILDING

  docker run (M1 and earlier)          This module: real Kubernetes

  ┌─────────────────┐                  ┌──────────────────────────────────┐
  │  a container       │                  │  Deployment (the thermostat)         │
  │  with no supervision │       ──▶       │    always keeps N Pods                │
  │  IP that changes      │                  │  ┌────┐ ┌────┐ ┌────┐              │
  │  every time it's        │                  │  │Pod │ │Pod │ │Pod │  (offices)    │
  │  recreated                │                  │  └────┘ └────┘ └────┘              │
  └─────────────────┘                  │         │       │       │            │
                                          │         └───────┴───────┘            │
                                          │                 │                    │
                                          │   Service (the switchboard)          │
                                          │   an address that never changes      │
                                          └──────────────────────────────────┘

Common mistakes

Assuming this module is going to repeat what was already done with docker run in aws-serverless-and-containers-guide (expectation). What happens: someone arrives expecting this module to re-explain containers, image layers, or docker build, and is surprised that lesson 2 jumps straight into Kubernetes vocabulary without that review. Why it happens: it's natural to assume "running a container on Kubernetes" starts where "running a container with Docker" left off. How to spot it: if at any point in this module you ask yourself "wait, didn't I already see this?", the answer is no — Kubernetes doesn't replace Docker, it coordinates containers that Docker (or, more precisely, containerd, the low-level engine kind uses inside each node) already knows how to run. How to fix it: if the vocabulary of images/layers/docker build feels rusty, docker-essentials-guide remains the reference — this module doesn't repeat it.

Thinking a Deployment is "a Pod with more steps" (conceptual, the central mistake lesson 3 corrects in depth). What happens: someone treats the Deployment as an alternative way to create a single Pod, instead of understanding it's an entirely different type of object — a controller that manages Pods, not a Pod itself. How to spot it: if you expect kubectl get pods to show an object with exactly the same name as your Deployment, with no additional suffix. How to fix it: lesson 5 of this module shows you, with real evidence, that a Deployment never shows up in kubectl get pods — only the Pods that Deployment created underneath, through an intermediate ReplicaSet, show up there.

Skipping lesson 4 (the loose Pod) for seeming "the simplest step, no need to practice it" (workflow). What happens: someone goes straight to lesson 5 (andes-cargo-status-api's real Deployment), without going through lesson 4, and misses this module's only chance to see, with their own hands, the difference in behavior between a loose Pod (which no one replaces if you delete it) and a Pod managed by a Deployment (which does get replaced on its own). Why it happens: a loose Pod feels like "the practice version," not the exercise that actually matters. How to spot it: if in lesson 5 you're surprised the deleted Pod gets replaced on its own, that's a sign you skipped lesson 4's comparison. How to fix it: lesson 4 exists exactly to install that expectation before seeing it confirmed in lesson 5 — don't skip it, even though it seems like this module's least interesting step.


Exercises

Exercise 1 — Fill in the table from memory. Without looking back at the "What docker run is missing that Kubernetes resolves" section, write the four scenarios from that table and, for each one, in one sentence, which Kubernetes object resolves it.

See solution
  1. The process dies inside the container → kubelet restarts it according to the Pod's restartPolicy.
  2. You need several instances running at once → a Deployment with replicas: N keeps that number.
  3. One of those instances goes down → the same Deployment controller (through its ReplicaSet) notices the gap and creates a new one.
  4. You need a stable address to talk to the group → a Service gives a name and an address that never change.

If you reconstructed all four without looking, you've already installed the underlying reason this module exists.

Exercise 2 — Extend the building analogy. With this lesson's analogy (office building, thermostat, switchboard), predict: if a Deployment is the thermostat and a Service is the switchboard, what would, in this same analogy, the ReplicaSet that lesson 3 is going to introduce as an intermediate piece between the two, be?

See solution

A reasonable answer: the ReplicaSet would be the maintenance technician the thermostat (Deployment) actually instructs to open or close offices — the thermostat decides how many offices should be occupied based on the desired temperature, but it's an intermediate layer that carries out that decision office by office. Lesson 3 develops this relationship with technical precision: you almost never interact with the ReplicaSet directly, the same way you almost never talk directly to the maintenance technician — you talk to the thermostat, and the rest happens on its own.

Exercise 3 — Predict the order of appearance. Based on this lesson's map of the 8 lessons, predict: why do you think this module teaches the loose Pod first (lessons 2 and 4), before the Deployment (lessons 3 and 5), instead of going straight to the Deployment, which is what you'll actually use in production?

See solution

Because understanding what a Pod is — the minimum unit, with no controller behind it — is the prerequisite for understanding exactly what a Deployment adds on top. If you started straight with the Deployment, you'd have no way to distinguish "Kubernetes in general does this" from "the Deployment's controller specifically does this" — lesson 4 (loose Pod, no one replaces it) and lesson 5 (managed Pod, it does get replaced) are designed, on purpose, so you see that contrast with your own hands, not just read about it.


Summary and next step

In this lesson you saw, with a concrete table, the four real problems docker run alone doesn't solve and a Kubernetes cluster does: automatic restart, keeping a replica count, replacing ones that crash, and giving a stable address to a group of Pods that keeps changing underneath. You got this module's complete map of 8 lessons, and the analogy that's going to accompany them: a managed office building, with a thermostat (Deployment) and a switchboard (Service), instead of a loose desk with no supervision whatsoever.

Before moving on you should be able to: explain, in your own words, the underlying difference between docker run and a Deployment; name the three primitives this module builds, in the order they appear; and anticipate why lesson 4 (loose Pod) comes before lesson 5 (managed Pod).

Next lesson: what a Pod is, and why almost no one creates one loose. That's where this module's first real piece begins — Kubernetes' minimum schedulable unit, the individual office in this lesson's analogy.

Resources

  1. Kubernetes — Workloads — the official gateway to Pods, Deployments, and ReplicaSets, this whole module's central reference.
  2. Kubernetes — Pods — official reference for the minimum schedulable unit, lesson 2's topic.
  3. aws-serverless-and-containers-guide (NIEVA), Module 7 — the ECS model this guide constantly uses as a point of comparison with Kubernetes.