Cluster and node pools — where your containers actually land
The hub gave you two parts: the Azure-managed control plane and the billable node VMs that run pods. A node pool groups VMs with the same size and operating-system image. Every AKS cluster needs a system node pool for essential add-ons, including DNS. A production cluster commonly adds a user node pool for application pods. The pool names describe their intended jobs, but the name alone does not prevent apps from running on system nodes; a dedicated system pool needs a scheduling rule such as a taint to enforce that separation.3
Each node needs a container runtime to start an image. AKS uses containerd; Docker can still build the image because both tools use compatible image standards.1 You choose pool capacity and the scheduler places eligible pods on nodes. Multiple replicas are not a guarantee that they land on different nodes. Placement rules can spread them; replacement after a node failure also needs spare capacity and a working image. Start with the pool, then inspect individual nodes when placement or capacity is the problem.
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.
Those three commands are a starting point. You will also need logs to read application output and rollout status to check a deployment. A manifest kept in Git records what you asked the cluster to run. kubectl apply -f app.yaml updates the live object toward that manifest; it does not prove the app became healthy. Check the rollout and pods after applying.
Declare it, observe it, read the gap. That is the loop.
Pods, ReplicaSets, Deployments — a chain of promises
A pod is the smallest deployable unit: one or more containers that share networking and storage. A pod can disappear and be replaced, so application callers should not depend on its name or IP.2 For a stateless app, create a Deployment that requests a replica count. It manages a ReplicaSet, which creates replacement pods when the count falls. A replacement may take time to start, and a requested replica is not necessarily a ready, serving replica. That distinction matters during failure and maintenance.
When you change the Deployment's pod template, it creates a new ReplicaSet and gradually shifts replicas from the old one. If new pods cannot become ready, the rollout can stall; Kubernetes reports the problem, but it does not automatically roll back to the previous version. Check kubectl rollout status deployment/web, inspect the cause, and make an explicit repair or rollback decision. A Service gives callers a stable address while eligible pods change behind it.
Play it through
Three minutes. In this scenario, the app starts with one serving copy on node B. Drain that node, then try three copies placed across three nodes and drain it again. The second result depends on that placement and on the remaining pods being ready.
Do it for real, before §4. Services and namespaces make more sense once you have watched a pod come back on its own. The first AKS cluster lab creates a billable node, deploys an app, deletes a pod and observes its replacement, then walks through cleanup. Its one-node setup demonstrates reconciliation, not high availability. Check Azure charges and verify deletion when finished.
Services — a stable name in front of moving pods
Pod addresses change when pods are replaced, so app-to-app callers should use a stable Service address. A Service selects pods by label and routes to ready endpoints. ClusterIP is the default for in-cluster traffic. NodePort exposes a port on each node and needs deliberate network controls. In AKS, a LoadBalancer Service can provision an Azure load balancer; whether its address is public or internal depends on its configuration. Choose exposure based on who actually needs access.
An ingress controller can route many hostnames and paths to Services through a shared entry point; §27c covers that design. For now, hold the layers: pods run code, a Service gives selected ready pods a stable address, and external exposure is a separate choice. When an app is running but unreachable, check the pod's readiness, the Service selector and endpoints, then the entry point.
Namespaces — walls inside one cluster
A namespace groups namespaced objects within one cluster. AKS uses kube-system for add-ons; objects created without a namespace commonly land in default. Two teams can each name a Deployment web in different namespaces. You can add quotas, access rules and network policies, but a namespace alone is not a security wall: cluster-scoped resources and the underlying control plane remain shared.
Use namespaces to organize trusted workloads that can share a control plane and lifecycle. Add explicit access, quota and network controls when those are required. Consider separate clusters when teams need stronger isolation, incompatible upgrade schedules, or separate failure domains. The decision depends on the actual security and operating requirements, not the namespace name.
The partner integration gets its first Deployment
In this fictional case, the partner gateway goes into its own namespace, partner-gw, as a Deployment with two replicas and an internal ClusterIP Service. Two replicas alone do not guarantee availability during a node reboot: they need to run on separate nodes, be ready, and have enough capacity to survive the drain. The public entry point comes later in §27c. Start with this small object set, then add the placement and reliability controls the requirement needs.
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.
Deploy it for real. This same shape — a Deployment fronted by a Service — is what the Campux Retail application runs on a live cluster. Its repository ships the manifests you will apply at the capstone: a Deployment with CPU requests and health probes, a Service, an ingress, and a HorizontalPodAutoscaler. github.com/kloudcaptain/campux-retail
Reading a cluster you did not build
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.
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.
B. A Deployment requests three replicas and manages a ReplicaSet that creates replacements when pods disappear. It does not guarantee all three are ready; check the rollout and available replicas. Bare pods have no replacement controller. A Service gives pods an address, and a namespace groups objects; neither creates the app's replicas.
A. ClusterIP is the default stable address for callers inside the cluster. A public LoadBalancer would expose an app that does not need public access; NodePort opens a port on each node. A caller that hardcodes a pod IP will break when that pod is replaced. For ordinary app traffic, use the Service; direct pod access remains useful for targeted debugging.
containerd, the Deployment-to-ReplicaSet chain, and the system pool. A system pool runs essential add-ons; add a user pool and explicit scheduling rules if you need app pods kept off system nodes. Pod names are unique within a namespace, not across the entire cluster. apply submits an object, but the controller must still create ready pods; always check the result. Images built in Class 26 can run under containerd because the image format is shared.
# 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.
Line three. A replacement pod can get a new IP, so a script that saves pod IPs may call an address that no longer serves the app. Use the ClusterIP Service in line two for ordinary app traffic, and check its endpoints if requests fail.
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.
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.
Start with the isolation requirement. A namespace separates names and can scope quotas and access rules, but those controls must be configured. It shares a cluster's control plane and upgrade schedule. A separate cluster gives you a distinct control plane and failure domain, at the cost of operating another cluster.
Ask what must be independent. Does the project need a distinct compliance scope, cluster administrators, upgrade window or outage boundary? If so, evaluate a separate cluster. If trusted teams can share those, a namespace with explicit quotas, access controls and network policy may suffice. Dedicated nodes can reduce shared-node risk but do not create a separate control plane.
State the decision and its conditions. Use a namespace only after the required controls are named and tested. Use a separate cluster when shared administration or lifecycle is unacceptable. Revisit the choice if the project's risk or workload changes.
Five things worth carrying out of Part A
- A node pool groups similarly configured VMs. System pools host AKS add-ons; user pools are intended for apps. Use scheduling rules if apps must stay off system nodes.
- 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.
- The chain: a Deployment manages a ReplicaSet, which creates pods to meet the requested count. Check readiness and rollout status; a stalled rollout does not automatically roll back.
- Use a Service as the stable address for ordinary app traffic. ClusterIP is internal by default; a LoadBalancer can be public or internal depending on configuration.
- A namespace groups namespaced objects but does not isolate them by itself. Add access, quota and network controls, or use a separate cluster when the control plane and lifecycle must be separate.
- 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. ↩
- 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. ↩
- Microsoft's AKS system-pool guidance says application pods can run on a system pool unless scheduling rules prevent it. A dedicated pool with a
CriticalAddonsOnlytaint is one way to reserve it for system components. ↩
Explain the control plane, nodes and pods, and create a cluster you can defend the shape of.
Play the lesson above to stamp this class.