AI EngineeringZero to ProductionHome·About·What’s new·Contact
Kubernetes Orchestration · Part 1

Why orchestration

You can run one container with docker run. But production means many containers, across many machines, that must survive crashes, reboots, scaling, and rollouts — without you babysitting them. This lesson is the honest bridge from a single docker run to a cluster: the exact problems orchestration solves, the anatomy of a Kubernetes cluster, why a Pod is not the same thing as a container, and — just as important — when not to reach for Kubernetes at all.

⏱️ ~75 min☸️ Cluster concepts🎯 Beginner→Advanced
🌱 Start here — from one container to a fleetYou already know containers (the CD track). Kubernetes — k8s — is what runs them in production when one host and one docker run stop being enough. This lesson is concepts and reading; nothing here needs a cluster yet. From K2 onward the labs apply real YAML to a real cluster, so install minikube or kind locally now, or plan to use EKS in K5. Verify versions and API fields against the current Kubernetes docs — the project moves fast.

Learning objectives

  • Name the concrete production problems docker run leaves unsolved and that orchestration solves.
  • Describe the anatomy of a cluster: control plane (api-server, etcd, scheduler, controller-manager) and nodes (kubelet, container runtime, kube-proxy).
  • Explain the declarative model — you describe desired state, controllers reconcile toward it.
  • Distinguish a Pod from a container and say why the Pod is the smallest unit k8s schedules.
  • Decide honestly when not to use Kubernetes — the cases where it is the wrong tool.

1 · What `docker run` cannot do

Here's a night you might recognize. You shipped a container to a VM with docker run -d. It worked. Everyone was happy. Then at 3:17am the app hit an out-of-memory error and the process died — and because nothing was watching, it stayed dead until a customer emailed at 8am. You SSH in, run docker run again, and go back to bed. Two weeks later the whole VM reboots for a kernel patch and your container doesn't come back at all, because you never set it to start on boot. That drip of tiny 3am chores — restart it, move it, scale it, put it behind a load balancer — is the problem orchestration exists to erase.

Here's the mental shift. docker run is a one-shot command: it starts a container and then walks away. Nobody is left minding the store. What production actually wants is a standing promise — "keep this thing running, in this shape, no matter what breaks" — and a command that runs once can't make a promise that lasts forever. Think of the difference between lighting a candle and installing a thermostat. The candle (docker run) gives you light right now, but if a draft blows it out, it's out. The thermostat (an orchestrator) has a target and a loop that keeps checking reality against it — furnace kicks on when the room drifts cold, off when it's warm — with no one in the room. Orchestration is a thermostat for your containers.

The common beginner mistake here is assuming Docker's own flags are "close enough." --restart=always does bring a crashed container back — but only on the same host, and only if the Docker daemon itself is alive. The instant the machine dies, that flag dies with it, and everything it was restarting is simply gone. Docker gives you the pieces for one container on one box; orchestration gives you a system that spans many boxes and outlives any one of them. Read the table below as a list of promises you'd otherwise have to keep by hand, at 3am, forever.

A single docker run is perfect for one container on one machine. Production is not that. The moment you have real traffic, you need answers to questions Docker alone does not answer: what restarts a crashed container at 3am? What moves it when its host dies? How do ten replicas share one stable address? How do you roll out v2 without dropping requests, and roll back in seconds when it's bad? Orchestration is the standing machinery that answers all of these automatically.

bare docker run · one host one VM container ✗ died nobody watching stays dead till 3am host reboots → all gone orchestrator · a fleet desired: 3 replicas node 1 ✓ node 2 ✓ node 3 ✗ ✗ rescheduled ✓ always 3 running — no human A one-shot command vs a standing promise. On the left, one docker run on one host: when the container dies nothing brings it back, and a reboot loses everything. On the right, the orchestrator holds a target of 3 replicas and reschedules onto a healthy node the instant one dies.
🗺️ How to read this diagram

Compare the two halves split by the dashed line: the fragile single host on the left, the self-healing fleet on the right.

  • The left panel is one VM running one container with docker run. The red box is the crashed container; the red arrow points to "nobody watching" — the command already finished, so the container stays dead and a host reboot wipes it entirely.
  • The right panel starts from a purple desired state box ("3 replicas") that fans out to three nodes. Green boxes are healthy replicas; node 3's replica has failed (red).
  • The payoff is the bottom-right arrow: the orchestrator notices the gap and reschedules the lost replica onto a healthy node, so the count returns to 3 with no human involved.

In short: docker run gives you a container until something breaks; an orchestrator gives you a count of running replicas it defends across the whole fleet.

Production needWith bare `docker run`With an orchestrator
Restart on crash--restart flag, per host onlySelf-healing across the whole cluster
Host diesContainers on it are goneRescheduled onto healthy nodes
Scale to N replicasRun N commands, track them yourselfreplicas: N — one field
Stable address for N replicasWire up your own load balancerA Service gives one virtual IP + DNS
Zero-downtime deployManual, error-proneRolling update built in, with rollback
Config & secretsBake in or pass by handConfigMaps / Secrets, mounted at runtime
Orchestration in one sentenceAn orchestrator keeps a set of containers running in a desired configuration across a pool of machines — restarting, rescheduling, scaling, and updating them so you don't have to. Kubernetes is the de-facto standard, but the ideas (desired state, reconciliation, scheduling) are universal.

2 · The declarative model — desired vs actual state

Think about how you get a haircut. You don't stand behind the barber narrating every scissor stroke — "now move up two millimeters, now tilt the blade, now snip." You describe the result you want ("short on the sides, leave the top") and trust them to keep cutting until reality matches that description. If you come back in three weeks and it's grown out, you don't re-explain the whole procedure — you just say "same as last time," and they close the gap again. That is the entire philosophy of Kubernetes in one everyday act: you describe the end state, not the steps, and something else does the work of getting there and staying there.

This matters because it's the opposite of how most of us first learn to automate. The instinct is to write a script: "do this, then this, then this." That's imperative — a recipe of steps — and it has a fatal flaw in a world where things break: a script runs once, top to bottom, and then it's over. The moment reality drifts (a container dies, a node reboots), the script has no idea and no reason to care; it already finished. The declarative model flips this. You hand the cluster a description of the world you want — "3 replicas of this image on port 80" — and a controller compares that description to what's actually running, over and over, forever, taking action every time they disagree. You stop writing how and start writing what.

The common trap for newcomers is treating a Kubernetes manifest like a shell script — imagining kubectl apply "runs" the YAML the way bash runs commands. It doesn't. Applying a manifest doesn't execute anything; it records a wish in the cluster's database, and independent controllers then race to make that wish true. That's why you can apply the same file ten times and nothing bad happens — you're re-stating the same desired state, not re-running ten actions. Hold onto the phrase desired vs actual; every self-healing behavior in the rest of this track is just that gap being closed automatically.

This is the single most important idea in Kubernetes, and it's what separates it from a shell script. You do not tell the cluster "start this container, then that one." You declare the desired state — "I want 3 replicas of this image exposed on port 80" — and write it down as YAML. A set of controllers continuously compares desired state to actual state and takes whatever action closes the gap. Delete a Pod and the controller notices actual < desired and makes a new one. This loop is called reconciliation.

You write YAML api-server storesdesired state Controllerreconciles Actual statematches
🗺️ How to read this diagram

Read it left-to-right as a one-way pipeline, following the four arrows from what you do to what the cluster ends up doing.

  • The first box, "You write YAML," is the only human step — you describe the state you want, you don't issue commands.
  • The middle two boxes are the machinery: the purple api-server stores that desired state, then the amber controller reconciles — repeatedly comparing what's wanted against what's real.
  • The payoff is the green end box, "Actual state matches": the arrows all flow toward it because the controller keeps acting until reality equals the recorded wish.

In short: you record a wish and the api-server plus controllers do the work of making — and keeping — actual state equal to your declared desired state.

Why declarative winsBecause the controller runs forever, the system is self-healing by construction: any drift (a crash, a deleted Pod, a dead node) is just a new gap for the loop to close. Imperative scripts run once and then the world drifts away from them. Declarative state is the world the cluster is always pulling itself back toward.

3 · Cluster anatomy — control plane + nodes

Picture a busy restaurant. Out front there's a manager taking orders, writing them on tickets, and deciding which cook handles what; in back there's a line of cooks who actually make the food. You, the customer, never walk into the kitchen and start frying — you talk to the front, and the front drives the back. A Kubernetes cluster is organized exactly like this. The control plane is the front-of-house brain that takes your orders and decides what runs where; the worker nodes are the kitchen line that does the actual cooking. When people say "I can't reach the cluster," nine times out of ten they mean they can't reach the manager out front — the control plane — not that the cooks stopped working.

Understanding this split is what turns cluster debugging from guesswork into a checklist. Every component has one job, and when something misbehaves, knowing whose job it was tells you where to look. The manager (api-server) is the only one allowed to write in the reservation book (etcd) — so if two people try to change the same thing at once, the book stays consistent. The seating planner (scheduler) decides which table (node) a new party (Pod) goes to. The floor supervisors (controller-manager) keep checking that every table that should be occupied actually is, and re-seat parties when a table breaks. And on each table sits a waiter (kubelet) who takes instructions from the front and reports back whether the food actually arrived.

The mistake beginners make is picturing the control plane as a single magic box, so when something breaks they have no idea which piece failed or what the blast radius is. It's worth internalizing early that these are separate processes with separate failure modes — a fact Exercise 5 makes you reason about directly. If etcd (the reservation book) is lost, the cluster forgets everything it was supposed to be doing; if the scheduler stops, existing tables keep serving but no new parties get seated; if a single node's kubelet dies, only that one table goes quiet while the rest of the restaurant runs fine. You talk only to the control plane (via kubectl); it drives the nodes — so trace the diagram below left-to-right as the path your order actually takes.

A cluster is two kinds of machines. The control plane is the brain that decides what should run where; the worker nodes are the muscle that actually runs your containers. You talk only to the control plane (via kubectl); it drives the nodes.

kubectl / you api-server etcd scheduler +controllers kubelet on node
🗺️ How to read this diagram

Trace it strictly left-to-right along the arrows — this is the path a single request takes from your terminal into the cluster.

  • It starts at the blue kubectl / you box on the far left: you never touch the nodes directly, you only speak to the control plane.
  • The arrows then run through the control-plane pieces in order — the purple api-server (the one front door), which persists to etcd, and the scheduler + controllers that decide what runs where.
  • The payoff is the green box on the right, kubelet on node: the last hop, where the control plane's decision is handed to the node agent that actually starts the container.

In short: you talk only to the api-server, and its decisions flow down the chain to the kubelet that runs your work on a node.

ComponentLives onWhat it does
kube-apiserverControl planeThe front door. Every read/write goes through it; it validates and persists.
etcdControl planeThe cluster's database — the single source of truth for all state.
kube-schedulerControl planeDecides which node an unscheduled Pod should run on (fit, resources, constraints).
controller-managerControl planeRuns the reconciliation loops (Deployment, ReplicaSet, node controllers…).
kubeletEvery nodeThe node agent — starts/stops Pods and reports health back to the api-server.
container runtimeEvery nodeActually runs containers (containerd/CRI-O).
kube-proxyEvery nodePrograms the node's networking so Service virtual IPs route to Pods.

On a managed service like EKS (K5), AWS runs and secures the entire control plane for you — you only manage nodes. That's the main reason most teams use managed Kubernetes rather than running etcd themselves.

4 · Pods vs containers

You spend the whole containers track learning about containers — and then Kubernetes hands you a word you've never seen: Pod. Almost everyone's first reaction is quiet confusion: "Wait, I thought I was deploying containers. What's a Pod, and why do I suddenly have to care?" It feels like an unnecessary layer of jargon between you and the thing you already understand. It isn't — but the friction is real, so let's name it plainly and make it click before you ever write one.

Here's the analogy that makes it stick: a container is a single roommate, and a Pod is the apartment they live in. Usually one roommate lives alone — one Pod, one container — and the apartment is basically just a wrapper around that one person. But sometimes two roommates truly need to share the same apartment: same address (one IP), same phone line (localhost), same fridge (shared storage), and — crucially — they move in and move out together. That's a Pod with a main container and a sidecar: a log shipper or proxy that only makes sense living right next to the app and dying when it dies. Kubernetes schedules apartments, not individual roommates, because everything that must share an address and a lifecycle has to be placed as one unit.

Why bother with the wrapper at all, when 90% of the time it's just one container? Because the smallest thing the scheduler can place on a node needs a single, stable network identity and a single lifecycle — and "a container plus its inseparable helpers" is the honest unit of deployment, not the lone container. The mistake to avoid is reaching for multi-container Pods too eagerly: cramming your database and your API into one Pod because it's "convenient" is an anti-pattern, because they can no longer scale, restart, or move independently. The rule of thumb — one main container per Pod, add a sidecar only when it must share the app's fate — is worth tattooing on your brain now, before the YAML tempts you otherwise. Read the minimal Pod below with that lens: it's one apartment, one roommate.

Newcomers assume Kubernetes runs containers. It doesn't — directly. The smallest unit it schedules is a Pod: one or more containers that share a network namespace (same IP, same localhost) and can share storage. Usually a Pod is one app container; a second sidecar container (a log shipper, a proxy) is added only when it must live and die with the main one.

common: one Pod, one container Pod (the apartment) app container 1 IP · localhost · storage one roommate, alone sidecar: two share the Pod Pod (same apartment) app sidecar 1 IP · localhost · storage move in & out together scheduler places the Pod The Pod is the unit, not the container. Left: the usual case — one Pod wrapping one app container. Right: a Pod with a sidecar; both containers share one IP, localhost, and storage, and live and die together. The scheduler always places the Pod.
🗺️ How to read this diagram

Read the two outer boxes as apartments; the arrows at the bottom show what the scheduler actually acts on.

  • The left Pod is the 90% case: one green app container inside one Pod. The amber strip underneath is the shared identity — a single IP, one localhost, and shared storage.
  • The right Pod holds two green containers, an app and a sidecar (a log shipper or proxy). They sit in the same apartment, so they share that same amber strip and move in and out together.
  • The payoff is the purple box both arrows point into: the scheduler places the Pod as one unit onto a node — never a lone container — because everything sharing an address and a lifecycle must be placed together.

In short: A container is a roommate; a Pod is the apartment. Kubernetes schedules apartments, and a sidecar only joins when it must share the app's address and fate.

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
YAML · a minimal Pod (needs a cluster — minikube/kind or EKS)
pod.yamlapiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
    - name: app
      image: ghcr.io/example/web:1.0.0   # pin a version, never :latest
      ports:
        - containerPort: 8000
shell · apply and inspect it (needs a cluster)
run.shkubectl apply -f pod.yaml        # create/update from the manifest
kubectl get pods                 # is it Running?
kubectl describe pod web         # events, image, node, why it's Pending/CrashLooping
kubectl logs web                 # the container's stdout/stderr
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          12s
You almost never create bare PodsA raw Pod has no self-healing — delete it or lose its node and it's gone for good. In practice you create a Deployment (K2), which manages Pods for you via a ReplicaSet. The bare Pod above is only to make the unit concrete. Output shown is illustrative — verify field names against the current Kubernetes API docs, which do drift between versions.

5 · When NOT to use Kubernetes

Here's a failure mode that plays out in real companies every year. A two-person startup reads that "everyone serious runs Kubernetes," spins up a cluster for their single Flask API, and six months later has spent more engineering hours fighting cluster upgrades, networking quirks, and expiring certificates than they ever spent building the actual product. The app was never the problem — the infrastructure they didn't need became a second full-time job neither of them signed up for. Nobody warned them, because it's rarely fashionable to say "you don't need this." So this section says it plainly: Kubernetes is often the wrong first choice, and knowing that is a mark of experience, not ignorance.

The honest framing is that Kubernetes is a power tool with a real running cost, and like any power tool, using it for a job that a screwdriver would do is not impressive — it's a hazard. A cluster doesn't just sit there; someone has to own it. That means patching security holes, running version upgrades that can break things, managing RBAC, watching costs, and being on call for the cluster itself — a layer of pager duty entirely separate from your application. That ownership is the true price of Kubernetes, and it's almost always paid in headcount, not dollars of compute. If no one on the team is that owner, the cluster doesn't stay still — it quietly rots into an unpatched, misconfigured liability, which is genuinely worse than the simple VM you were trying to outgrow.

The most useful instinct to build is to flip the default: don't ask "why not Kubernetes?" — ask "do I actually have the problems from section 1?" Kubernetes earns its complexity only when you're running many services across many machines and you have a team to own the platform. Miss those conditions and a managed host (a PaaS, serverless, or managed containers like ECS/Fargate or Cloud Run) ships the exact same container with a fraction of the operational burden — and, because you containerized anyway, migrating to Kubernetes later is writing manifests, not rewriting the app. That's the quiet superpower: the decision is reversible, so choosing "not yet" costs you almost nothing. The table below is your decision aid — for each situation, notice it fails at least one of the many-services / many-machines / team-to-run-it tests.

Kubernetes is powerful and expensive in complexity. It is the wrong first choice more often than the internet admits. Reach for something simpler when:

ask three questions — all must be YES many services? many machines? team to own it? all three YES? yes any no Kubernetes fits complexity buys leverage managed host instead Fargate · Cloud Run · Fly.io Kubernetes is a gate, not a default. Only when many services, many machines, and a team to own the cluster are all true does k8s earn its complexity. Miss any one and a managed host ships the same container for far less operational burden.
🗺️ How to read this diagram

Read it top-to-bottom: three yes/no tests feed one gate, and the gate routes you to one of two outcomes.

  • The top row is the three questions that decide the call: do you have many services, many machines, and a team to own the cluster?
  • The purple gate in the middle is an AND — it only opens if all three answers are yes. The solid green-labelled arrow is that path; the dashed grey "any no" arrow is the far more common one.
  • The two outcomes are the payoff: green "Kubernetes fits" (complexity now buys leverage) versus amber "managed host instead" — a PaaS or serverless that runs the exact same container with a fraction of the ops burden.

In short: Don't ask "why not Kubernetes?" — ask the three questions. Unless every answer is yes, a managed host is the better first choice, and migrating later is just writing manifests.

SituationWhy k8s is overkillReach for instead
A single container, low trafficYou'd run a control plane to babysit one appA PaaS: Fly.io, Render, App Runner, ECS
A small team, no platform engineerk8s needs someone to own it full-timeManaged containers / serverless
Bursty, event-driven, scale-to-zeroIdle nodes cost moneyLambda / Cloud Run / Fargate tasks
A static site or simple APIEnormous machinery for little benefitA CDN / a managed app host
You just want to ship this weekThe learning curve is realWhatever gets it live; migrate later
The most common Kubernetes mistakeAdopting it before you have the scale or the team to justify it. k8s pays off when you run many services across many machines and need portability, self-healing, and a common platform. For one app and a two-person team, it is usually a tax, not a tool. Use it when the problems in section 1 are your problems.

✓ Checkpoint — you can move on when you can…

  • Name three production problems docker run alone doesn't solve.
  • Explain the reconciliation loop in one sentence (desired vs actual state).
  • Label the control-plane components and say what etcd and the scheduler each do.
  • Explain why a Pod — not a container — is the unit Kubernetes schedules.
  • Give two concrete situations where you'd deliberately not use Kubernetes.
✓ Knowledge check

You delete a Pod that was created directly with kubectl apply -f pod.yaml (a bare Pod, not owned by a Deployment). What happens, and why is this different from deleting a Pod managed by a Deployment?

Show answer
The bare Pod stays deleted — nothing recreates it, because no controller owns it and is watching for the gap between desired and actual state. A Deployment, by contrast, declares "I want N replicas"; its ReplicaSet controller sees actual (N-1) < desired (N) and immediately schedules a replacement. This is exactly why you deploy workloads via Deployments rather than bare Pods: self-healing comes from a controller running the reconciliation loop, not from the Pod itself.
✓ Knowledge check

A startup with one Flask API and two engineers asks whether to launch on Kubernetes. What's the honest answer?

Show answer
Almost certainly no — not yet. One service and a two-person team hit none of the problems k8s solves (many services, many machines, self-healing across a fleet), but pay its full complexity cost: someone must own the cluster, upgrades, networking, and security. A managed container host (App Runner, Cloud Run, Render, Fly.io, or ECS/Fargate) ships the same container with far less operational burden. Revisit Kubernetes when they have multiple services, a platform owner, and concrete needs for portability or fleet-wide operations.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Justify orchestration to a skepticBeginner

Context: Before you learn the YAML, you should be able to defend why the cluster exists at all — the reflex a lead expects from you in a design review.

Your task: Write a short, concrete answer to "we already have docker run on a VM — why add Kubernetes?" grounded in real failure modes, not buzzwords.

Requirements:

  • Name at least three production problems bare docker run leaves unsolved
  • For each, state what an orchestrator does instead
  • End with one honest caveat: a case where k8s would be the wrong call

💡 Hint: Anchor each point to a 3am failure: a crash, a dead host, a bad deploy.

Show solution

The pitch. Bare docker run is fine until production stress arrives, and then it leaves gaps an orchestrator fills automatically:

  • Crash at 3am → a bare container needs --restart and only recovers on that one host; Kubernetes self-heals by rescheduling failed Pods anywhere in the cluster.
  • Host dies → everything on it is lost; the scheduler reschedules those Pods onto healthy nodes.
  • Bad deploy → manual stop/start drops requests; a Deployment does a rolling update with an instant rollback.
  • Ten replicas need one address → you'd hand-roll a load balancer; a Service gives a stable virtual IP and DNS name.

The honest caveat: for a single low-traffic app and a two-person team, this is all cost and little benefit — a PaaS or serverless host is the right call. Kubernetes earns its complexity only when you run many services across many machines.

Exercise 2 · Trace a `kubectl apply` end to endIntermediate

Context: Understanding the request path demystifies every later debugging session.

Your task: Describe, step by step, what happens inside the cluster from the moment you run kubectl apply -f pod.yaml until the container is actually running.

Requirements:

  • Follow the request through the api-server and etcd
  • Say where the scheduling decision is made
  • Say which component actually starts the container on the node

💡 Hint: Every write goes through the api-server; nothing talks to etcd directly except it.

Show solution

The path, component by component:

  1. kubectl sends the manifest to the kube-apiserver (the only front door), which authenticates, validates, and writes the desired state to etcd.
  2. The Pod now exists in etcd but is unscheduled (no node assigned). The kube-scheduler watches for such Pods, picks a node that fits (resources, constraints), and writes that assignment back through the api-server.
  3. The kubelet on the chosen node sees a Pod bound to it, tells the container runtime (containerd) to pull the image and start the container, then reports status back.
  4. kube-proxy programs node networking so any Service in front of the Pod can route to it.

The mental model: you write desired state → api-server persists it → controllers and the scheduler reconcile → kubelet makes it real. Every debugging step later (describe, logs, events) is just reading one stage of this pipeline.

Exercise 3 · Explain reconciliation with a concrete driftAdvanced

Context: The reconciliation loop is the heart of k8s; you should be able to demonstrate it, not just define it.

Your task: Explain what happens when a node running one of a Deployment's 3 replicas is abruptly powered off, tracing the loop back to 3 healthy replicas.

Requirements:

  • Identify which controller notices the gap and how
  • Explain the role of node health / heartbeats
  • State what the end state looks like and roughly how fast

💡 Hint: Two loops interact here: node health detection and the ReplicaSet's replica count.

Show solution

Setup: a Deployment declares replicas: 3; its ReplicaSet has 3 Pods, one per node. A node is powered off hard.

  1. The dead node's kubelet stops sending heartbeats. The node controller waits a grace period, then marks the node NotReady and eventually evicts its Pods (deleting them from desired-state's point of view).
  2. The ReplicaSet controller now sees actual (2 running) < desired (3). It creates a new Pod to close the gap.
  3. That new Pod is unscheduled, so the scheduler places it on a surviving healthy node; its kubelet starts the container.
  4. End state: 3 running replicas again, no human involved. Timing depends on the node eviction timeouts (tens of seconds to a few minutes) — verify the current default grace/eviction settings against the Kubernetes docs.

The lesson: self-healing is not magic — it's two reconciliation loops (node health and replica count) each independently pulling actual state back toward desired state.

Exercise 4 · Decide: k8s or not, for four systemsExpert

Context: The expert skill is knowing when NOT to use the tool you're learning.

Your task: Given four representative systems, decide for each whether Kubernetes is justified, and name the alternative when it isn't.

Requirements:

  • System A: a marketing static site
  • System B: a monthly batch job that runs 20 minutes then exits
  • System C: a platform of 15 microservices for 40 engineers
  • System D: a bursty webhook handler, idle most of the day

💡 Hint: Score each on: many services? many machines? need self-healing/portability? bursty?

Show solution

System A — static site → no. A CDN or managed static host is cheaper, faster, and needs no cluster. k8s adds nothing.

System B — monthly batch → no (mostly). A scheduled serverless job (Lambda, Cloud Run job, or a Fargate task) matches the run-then-exit shape without paying for idle nodes. Only put it on k8s if a cluster already exists and a CronJob is convenient.

System C — 15 services, 40 engineers → yes. This is exactly k8s's sweet spot: many services across many machines, a shared platform, self-healing, and a team large enough to own the cluster. The complexity now buys real leverage.

System D — bursty webhook, idle → probably no. Scale-to-zero serverless (Lambda / Cloud Run) avoids paying for idle capacity; on k8s you'd carry baseline nodes or add KEDA/knative to fake scale-to-zero. Use k8s only if it's already your platform.

The rule: Kubernetes earns its keep on many services × many machines × a team to run it. Miss those and a simpler host wins.

Exercise 5 · Draw the cluster and label the failure domainsProfessional

Context: A platform engineer must be able to sketch the cluster and reason about what breaks when a given piece fails.

Your task: Produce a labeled diagram of a cluster (control plane + 3 nodes) and, for each component, state the blast radius if it fails.

Requirements:

  • Include api-server, etcd, scheduler, controller-manager, and per-node kubelet/runtime/proxy
  • For each, describe what still works and what breaks if it's down
  • Note which components a managed service (EKS) takes off your plate

💡 Hint: Ask for each: if this dies, can running Pods still serve traffic? Can new ones be created?

Show solution

Failure-domain analysis:

  • api-server down → no new changes (no apply, no scheduling of new work), but existing Pods keep running and serving traffic since kubelets act on already-persisted state. The cluster is frozen, not dead.
  • etcd down/lost → the most serious: it's the source of truth. Without a backup, cluster state is unrecoverable. Running Pods may limp on, but the cluster can't be managed. Back up etcd.
  • scheduler down → running Pods fine; new Pods stay Pending (unassigned) until it returns.
  • controller-manager down → reconciliation stops: crashed Pods aren't replaced, rollouts stall. Existing steady-state keeps serving.
  • one node's kubelet down → that node's Pods are eventually rescheduled elsewhere; the rest of the cluster is unaffected.

Managed value: on EKS, AWS runs and replicates the api-server and etcd across AZs and handles their backups/upgrades — you inherit a resilient control plane and only own the nodes. That offload is the main reason to pay for managed Kubernetes.

Exercise 6 · Write the one-page 'do we adopt Kubernetes?' decision memoIndustry scenario

Context: Representative scenario: a Series-B company with 6 services and growing traffic asks platform engineering for a recommendation on adopting Kubernetes. Leadership wants a one-pager, not a religious war.

Your task: Write a decision memo that recommends for or against adopting Kubernetes now, with explicit criteria, costs, and a migration path.

Requirements:

  • State the decision up front, then the criteria behind it
  • Quantify the ongoing cost: who owns the cluster, what breaks if no one does
  • Include a 'revisit if' trigger list so the decision isn't permanent
  • Name the interim option and how you'd migrate to k8s later without a rewrite

💡 Hint: Frame it as reversible: containerize now (portable), choose the runtime as a separate, revisitable decision.

Show solution

Recommendation: not yet — containerize now, defer the cluster. Ship the 6 services as containers on a managed host (ECS/Fargate or Cloud Run) today; adopt Kubernetes when the triggers below fire. Rationale, in one page:

Criteria we scored. (1) Number of services: 6 — meaningful but not yet fleet-scale. (2) Team: no dedicated platform owner — the decisive factor. (3) Portability need: low today. (4) Self-healing/scaling: a managed host already provides both. On these, k8s's benefits are largely already met, while its costs are not yet justified.

The real cost of adopting now. Kubernetes needs an owner: upgrades, CVE patching, networking, RBAC, cost control, and on-call for the cluster itself. Without a named owner it rots into an unpatched, misconfigured liability — the worst of both worlds. That headcount is the true price, not the compute.

Revisit if any of these become true: we cross ~10–15 services; we hire/allocate a platform engineer; we need multi-cloud or on-prem portability; a managed host's limits (custom networking, GPUs, operators) start blocking us; or spend on managed containers exceeds what a cluster would cost with an owner.

Migration path (why this is reversible). Because every service is already a container with a Dockerfile and externalized config/secrets, moving to Kubernetes later is writing manifests — not a rewrite. We lose nothing by waiting, and we avoid paying the cluster tax before it buys us anything.

© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in