Skip to content
CAMPUX Cloud Bootcamp Phase Four · Class Twenty-Seven
Phase Four — Operate, Secure & AI
Reading 20 min · Drills 4 · Part A of VII
AKS: Zero to Production
Class Twenty-Seven · Part A

AKS fundamentals

The tutorials throw a dozen new nouns at you in the first hour and never say which ones matter; this part introduces them in the order the cluster actually uses them, each made concrete by something you can watch happen.

§1

Cluster and node pools — where your containers actually land

The hub gave you the two halves: the free control plane Azure runs, and the node pool of virtual machines you pay for. Now look closer at the half that is yours. A node pool is a group of identical VMs, managed underneath as an Azure virtual machine scale set, that all run the same size and image. A cluster has at least one system node pool — it hosts the essential add-ons AKS needs to function, the DNS and metrics pods you saw in kube-system — and usually one or more user node pools for your workloads. Separating them is not ceremony: it keeps a runaway application from starving the cluster's own plumbing.

Every node runs a container runtime — on AKS that runtime is containerd, not Docker; Docker-the-daemon was removed from Kubernetes years ago, though the images you built in Class Twenty-Six run identically, because the image format is a shared standard.1 You will rarely think about nodes individually. You size a pool, set how many nodes it has (or let the autoscaler decide, in §27b), and the scheduler spreads work across them. When you need more room, you add nodes or a pool; when a node dies, its pods are rescheduled onto survivors. The unit of thought is the pool, not the machine.

Node pool
A set of identically-sized VMs in a scale set that run your containers. System pools host the cluster's own add-ons; user pools host your workloads. You manage the pool; the scheduler manages which node runs what.
§2

kubectl — the three verbs that are most of the job

kubectl is how you talk to the API server, and beneath its long list of subcommands sits the habit from the hub: declare, observe, and read the gap. Apply submits desired state — kubectl apply -f app.yaml hands the cluster a document and says "make this true." Get asks what exists right now — kubectl get pods — and describe asks the deeper question, "and why is it in that state?" — kubectl describe pod web-7c9, which prints the events that explain a stuck pod better than any search engine.

Learn those three before any others and you can operate a cluster; the rest — logs, exec, delete, scale — are conveniences layered on top. The reason to prefer apply -f with a file over imperative one-liners is the same reason you write infrastructure as code in Phase Three: the file is the source of truth, it lives in Git, and re-applying it is safe. Clicking and typing commands leaves no record of intent; a YAML file is the intent, written down.

Declare it, observe it, read the gap. That is the loop.

§3

Pods, ReplicaSets, Deployments — a chain of promises

A pod is the smallest thing Kubernetes runs: one container, usually, plus its share of network and storage. Pods are deliberately disposable — they get a random name, they can die, and you are not meant to grow attached. You almost never create a pod directly. Instead you create a Deployment, which is a standing instruction — "keep N healthy copies of this pod running, from this image" — and the Deployment creates a ReplicaSet, whose one job is to hold the replica count steady. Delete a pod and the ReplicaSet notices the shortfall and makes another. That is the healing you watched in the lab, and now you can name every actor in it.

The chain earns its length when you ship a new version. Update the image in the Deployment and it does not tear everything down; it creates a new ReplicaSet, scales it up while scaling the old one down, and — if the new pods never become healthy — stops, leaving the old ones serving. That is a rolling update, and it is why you deploy through a Deployment rather than by hand: the safe, gradual, reversible rollout is built into the object. A Service sits in front of the pods so callers have one stable address while the pods behind it churn.

Fig. 1 · The chain — a Deployment keeps a ReplicaSet keeping pods, a Service in front
A Deployment manages a ReplicaSet that keeps three pods; a Service fronts them with one stable address. Deployment web · replicas: 3 ReplicaSet holds the count pod · web-a1 pod · web-b2 pod · web-c3 Service one stable address delete one, the ReplicaSet makes another
Read it left to right: the Deployment is your intent, the ReplicaSet is the machinery that defends the count, the pods are the disposable workers, and the Service is the one address callers use so they never need to know a pod's name. When you ship a new image, a second ReplicaSet appears beside this one and traffic shifts across — the rolling update, drawn.
§4

Services — a stable name in front of moving pods

Pods come and go and their addresses change, so nothing should ever talk to a pod directly. A Service is a stable name and virtual address that load-balances across whichever pods currently match its label selector. There are three kinds you will meet. A ClusterIP Service is reachable only inside the cluster — the default, and correct for one microservice calling another. A NodePort opens a port on every node — rarely what you want directly. A LoadBalancer Service asks Azure for a public load balancer and IP, putting the app on the internet — the honest but heavy way to expose one app.

The catch is that a LoadBalancer per app means an Azure load balancer per app, which is why real clusters put a single ingress controller in front of many Services and route by hostname and path — the subject of §27c. For now, hold the layering: pods run the code, a Service gives them a steady address, and something above the Service decides who from outside may reach it. Every request into your cluster travels down that stack, and being able to name each layer is how you debug "the app is up but I can't reach it" without flailing.

§5

Namespaces — walls inside one cluster

A namespace is a soft partition of one cluster: a way to group related objects and keep names, quotas, and access separate. AKS ships with a few — kube-system for the cluster's own machinery, default where your things land if you do not say otherwise — and you add your own, typically one per team or environment. Two teams can each have a web Deployment without collision, because a name is only unique within a namespace. Resource quotas and, in §27e, access rules attach to namespaces, so they are the natural seam along which you divide a shared cluster.

Reach for a namespace when you want a boundary without a whole new cluster; reach for a new cluster when the boundary must be hard — a different security posture, a different upgrade cadence, a blast radius you refuse to share. Getting that judgement right is a recurring senior decision: too many clusters and you drown in operations, too few and one team's mistake becomes everyone's outage. Namespaces are the cheap middle, and knowing when they are enough is worth as much as knowing how to make one.

Case File · Campux Retail

The partner integration gets its first Deployment

one namespace, one Deployment, one Service — the smallest thing that is real

The partner-integration cluster from the hub is now running, and you resist the urge to fill it. The API gateway the contract requires goes into its own namespace, partner-gw, as a Deployment with two replicas — enough that a node reboot during an upgrade never drops the integration to zero. A ClusterIP Service fronts it for the internal services that call it; the public entry point will come with the ingress controller in §27c. That is the entire footprint: one namespace, one Deployment, one Service.

It looks almost too small, and that is the point. Every object in the cluster is one you must operate, and the case file's whole thesis is that the cluster should be exactly the size of the contract that justified it. When a colleague asks why the internal dashboard is not "also on the cluster while we have it," the answer is the reconciliation loop's cousin: each thing you add is a promise the team now keeps forever. The partner integration is a promise the contract made you make. The dashboard is not.

On the job

Reading a cluster you did not build

You · Cloud Engineer · first day on a team that runs AKS

You inherit a cluster and a pager. Before you change anything you read it: kubectl get namespaces to see how it is divided, get deployments -A to see what is meant to run, get pods -A to see what actually is, and describe on anything not matching. In twenty minutes you have a map — namespaces as neighbourhoods, Deployments as intent, pods as reality — because you learned the nouns in the order the cluster uses them.

Class Twenty-Seven · Part A

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored.

Drill 01Recall
You want three copies of an app running, and you want a deleted copy to come back automatically. Which object do you create?
Marked

B. A Deployment is a standing statement of intent — "three healthy copies should exist" — and it creates a ReplicaSet whose entire job is to defend that count, recreating any pod that dies. A creates three pods with no one watching them: kill one and it stays dead, because a bare pod has no controller behind it. C confuses the address layer with the running layer — a Service routes to pods but never creates or heals them. D creates a boundary, not a workload; a namespace with no Deployment in it runs nothing. The tell in the question is "come back automatically": only a controller-backed object heals, and the Deployment is the one you reach for.

Drill 02Recall
Another service inside the same cluster needs to call your app. Which Service type is the right default?
Marked

A. Internal callers need a stable in-cluster address and nothing more, which is exactly ClusterIP — the default, and the least-exposed choice. B puts a public load balancer and internet IP in front of a service that has no business being public: it costs money and widens your attack surface "just in case," which is how internal tools end up indexed by scanners. C opens a port on every node, a blunt instrument you rarely want directly. D is the cardinal sin the whole Service concept exists to prevent — pod IPs change every time a pod is replaced, so a caller wired to one will break the first time the reconciliation loop does its job. Never talk to a pod; talk to a Service.

Drill 03Select three
Which three statements about AKS fundamentals are true?
Marked

containerd, the Deployment-to-ReplicaSet chain, and the system pool. The two rejects are common beginner misreadings. Names are unique only within a namespace — that is half the reason namespaces exist, and assuming global uniqueness is how you write a script that clobbers another team's object. And apply does not "start and forget"; it records desired state that a controller defends indefinitely — the opposite of fire-and-forget, and the single idea this whole track rests on. The images from Class Twenty-Six still run under containerd because the image format is a shared standard, so nothing you learned about building images is wasted.

Drill 04Spot the error
A junior posts this note in the team channel. One sentence shows a fundamental misunderstanding that will cause an outage. Which?
# note: how our web app runs on the cluster
1.  The Deployment keeps three pods running.
2.  Other services reach it through its ClusterIP Service.
3.  Our config script talks straight to the pods by their
    IP addresses, which we hardcode after deploy.
4.  If a pod dies, the ReplicaSet makes a new one.
Marked

Line three. It is the one sentence that contradicts every other line in the note. Lines one and four correctly describe pods as disposable and self-healing — which means their IPs change constantly, by design. Hardcoding those IPs wires the config script to addresses that are guaranteed to become stale the first time the reconciliation loop replaces a pod, and then the integration fails at 2am for no visible reason while every dashboard shows the app "healthy." The fix is already sitting in line two: talk to the ClusterIP Service, whose whole purpose is to be the stable address in front of the moving pods.

The other lines are correct and healthy. A Deployment does set and maintain the replica count (A is wrong). A ClusterIP Service load-balances across matching pods — that is exactly what it does (B is wrong). And a ReplicaSet absolutely recreates pods to hold the count (D is wrong). The lesson generalises past Kubernetes: whenever a design pins itself to an identifier the platform treats as ephemeral, you have written a bug with a delayed fuse.

Situation 01Write before you reveal
A teammate runs kubectl get pods, sees a pod named web-6f8d-x2k9, and asks in chat: "Why does our app pod have a random name? Shouldn't it be called just 'web' so we can rely on it?" Explain — in a way that teaches the model, not just the fact.
The random name is not a cosmetic quirk. It is the disposability of pods, made visible.
Reasoning

The random suffix is the point, not a nuisance. Start by reframing the wish. Wanting a pod called "web" you can "rely on" is wanting a pet — a specific, named animal you care for. Kubernetes deliberately makes pods cattle: interchangeable, disposable, stamped with a random suffix precisely so nobody builds a dependency on one particular pod. The Deployment creates them, the ReplicaSet replaces them, and each new one gets a new suffix because it is genuinely a new pod, not the old one revived.

Then point at the thing they should actually rely on. The stable name they want already exists — it is the Service. "web" as a dependable address is web the Service, which stays put while the pods behind it churn. So the answer to "shouldn't it be called web?" is: the reliable "web" is one layer up, and that separation is a feature — it is what lets the cluster replace a sick pod without anything that depends on it noticing.

Close by connecting it to something they have already seen. Remind them of the lab: delete a pod, a new one appears with a different suffix, and the app keeps serving. If pods had fixed names you would either be blocked from healing (the name is taken) or fooled into thinking the same pod recovered when it was actually replaced. The random name is Kubernetes being honest with you about what just happened. Teaching the model — pets versus cattle, pod versus Service — inoculates them against a dozen future mistakes, which a bare "it's just how it works" would not.

Situation 02Write before you reveal
Your team shares one AKS cluster. A new project arrives and someone asks: "Do we give this project its own namespace in our cluster, or stand up a whole new cluster for it?" How do you decide, out loud?
The question is really about how hard the boundary needs to be, and who pays for softness.
Reasoning

Name the axis before you answer: how hard must the wall be? A namespace is a soft boundary inside one cluster — separate names, quotas, and access rules, but a shared control plane, shared nodes, and a shared upgrade cadence. A separate cluster is a hard boundary: its own everything, its own blast radius. The decision is not about size or taste; it is about how much isolation the project genuinely requires, and every degree of hardness you buy, you also pay to operate.

Then walk the deciding questions. Does the project need a different security posture, compliance scope, or set of people who must never see the others' workloads? Must it upgrade or fail on a schedule the shared cluster cannot follow? Would its worst-case failure — a runaway that eats every node — be unacceptable to inflict on the existing tenants? If several answers are yes, the wall must be hard: new cluster. If they are all no, a namespace gives you separation for a fraction of the operational cost, and standing up a second cluster would just double your upgrade-and-patch burden to solve a problem you do not have.

Close on the standing bias, and its limit. Default to the namespace, because clusters are expensive to operate and a fleet of half-used ones is how a small team drowns. But say the limit out loud so you are not dogmatic: the moment a hard requirement appears — a regulator, a hostile-tenant risk, an incompatible lifecycle — the namespace stops being enough and you split. "Soft by default, hard when a requirement forces it" is the same shape as the whole track's rule about AKS itself, and saying it that way shows you are reasoning from a principle, not a preference.

Examination record · first attempt
0/4
Class 27a · Complete
Retain this much

Five things worth carrying out of Part A

  1. A node pool is a set of identical VMs in a scale set; system pools host the cluster's own add-ons, user pools host your workloads. Nodes run containerd, and your Class 26 images run on it unchanged.
  2. kubectl is three verbs first: apply (declare desired state), get (observe), describe (why it disagrees). Prefer apply -f with a file in Git over imperative one-liners.
  3. The chain: a Deployment keeps a ReplicaSet keeping pods. Delete a pod and the ReplicaSet makes another. Update the image and it rolls out a new ReplicaSet gradually and reversibly.
  4. Never talk to a pod. A Service is the stable address in front of moving pods — ClusterIP inside, LoadBalancer for public (heavy; ingress does it better in §27c).
  5. A namespace is a soft wall inside one cluster; names are unique only within it. Namespace by default, new cluster only when the boundary must be hard.
Notes
  1. Docker being "removed" from Kubernetes confuses people, so here is the honest version: Kubernetes dropped the dockershim, the shim that let it drive the Docker daemon as a runtime, and now uses containerd (or CRI-O) directly. Docker the tool for building images is entirely unaffected, and the images it produces follow the OCI standard that containerd also runs. Nothing you learned about building images changed; only the daemon that runs them on the node did, and that daemon was never something you touched on AKS.
  2. The pets-versus-cattle framing is older than Kubernetes and worth carrying past it: a pet is a server you name, patch, and nurse back to health; cattle are numbered, interchangeable, and replaced rather than repaired. Kubernetes makes pods cattle on purpose, which is what allows healing and rolling updates to work at all — but note the limit, because §27d is about the workloads that legitimately need an identity and durable disk, and pretending everything is cattle is its own mistake.