Skip to content
CAMPUX Cloud Bootcamp Phase Four · Class Twenty-Seven
Phase Four — Operate, Secure & AI
4 drills · 2 situations · Part B of VII
AKS: Zero to Production
Class Twenty-Seven · Part B

Workloads & config

The image starts your app. Now decide where its settings come from, when it can receive traffic, and how much CPU and memory it needs. Those choices make a Deployment usable under load.

Phase Four · Operate, Secure, AI · Class 27 · Part B · 15 min · Assumes Class 27 Part A

After this you can deploy a workload with a Deployment, a Service and ConfigMaps, and roll it back.

New to this? Read Class 27 Part A first. Already done it, or know the material? Carry on.

§1

ConfigMaps and Secrets — pulling config out of the image

An app often needs a different database address in dev and production. If that address is baked into the image, each environment needs a different build. Instead, make the app read a setting supplied at runtime. A ConfigMap holds ordinary values such as the database hostname; a Secret holds sensitive values such as an API key. A pod can read either as environment variables or mounted files. Changing those objects does not automatically refresh every running process: environment variables usually require new pods, while mounted files can update if the app rereads them.

Base64 is not encryption. A person allowed to read a Kubernetes Secret through the API can decode its value. AKS encrypts managed disks at rest by default; optional KMS encryption protects Secret values before they are written to etcd. Neither changes what an authorized API reader can see.1 Limit who can read Secrets, never commit a Secret manifest containing real credentials, and choose storage and rotation controls from the threat model.

For credentials managed in Azure, §27e introduces Microsoft Entra Workload Identity and Azure Key Vault. The workload can authenticate without a long-lived Azure credential stored in the pod, then fetch an authorized secret from Key Vault. A Kubernetes Secret can also be appropriate when access, encryption and rotation meet the requirement. The key question is who can read the value, how it is protected and rotated, and whether the application needs a restart after a change.

ConfigMap vs Secret
A ConfigMap stores non-sensitive settings; a Secret stores sensitive values. Both can reach a pod as environment variables or mounted files. Base64 does not hide Secret values from authorized readers; use access control, appropriate encryption and rotation, or an external store such as Key Vault.
Play

Play it through

Refactor an app that has a staging database address baked into its image. One corrected build reads its address from runtime configuration; after that, dev and staging can use the same image with different ConfigMaps.

The lab comes after §3 and §4. Do the ConfigMap change first; this lab moves on to what comes after config: AKS memory limits and autoscaling. A pod with no memory limit, the OOMKill that contains the next one, and an autoscaler that grows and shrinks under load. About twenty-five minutes.

§2

Probes — how the cluster tells alive from ready

A process that is running is not the same as a process that is working, and a process that is working is not the same as one that is ready to take traffic. Kubernetes will not guess the difference; you tell it, with three probes it runs on a schedule. A liveness probe answers "is this container still healthy, or has it wedged?" — if it fails, the kubelet kills and restarts the container. A readiness probe answers "should this pod receive traffic right now?" — if it fails, the pod is pulled out of its Service's endpoints but left running, so a pod that is warming up or briefly overloaded stops getting requests without being killed.

The third exists because slow starters get murdered by the first. A startup probe guards an app that needs thirty seconds to load before it can answer anything: while the startup probe is still failing, the liveness probe is held back, so a legitimately slow boot is not mistaken for a hang and restarted into an endless crash loop. Get these wrong in either direction and you feel it. No readiness probe, and traffic hits a pod before it can serve, so users see errors during every deploy. A liveness probe pointed at a dependency you do not control, and an outage in that dependency makes Kubernetes restart your healthy pods on a loop, turning a small problem into a self-inflicted one.

Fig. 1 · Two questions, two different actions — liveness restarts, readiness gates traffic
Liveness failure restarts the container; readiness failure removes the pod from Service endpoints without killing it. pod one container liveness still healthy? readiness take traffic? fail → restart Service ready pods only failing readiness pulls traffic, not the pod
Two probes, two verbs. Liveness is a restart switch: fail it and the container is killed and brought back. Readiness is a traffic gate: fail it and the pod is quietly taken out of rotation but left alive to recover. Point liveness only at "is this process itself wedged," never at a downstream dependency — or you hand an outage the power to restart your own healthy pods.
§3

Requests and limits — rationing the node

A node has finite CPU and memory. A container's request tells the scheduler how much capacity to account for when placing its pod; CPU requests also affect the container's share during contention. A limit controls maximum use: CPU can be throttled, while crossing a memory limit can cause an OOM kill. Requests that are too high leave pods pending; requests that are too low can pack more work on a node than it handles well. Measure actual usage and revisit both settings as load changes.

At a CPU limit, the runtime throttles the container; the symptom may be slow responses. At a memory limit, the kernel can terminate it, and Kubernetes reports OOMKilled. Whether the container restarts depends on the pod's restart policy. Inspect kubectl describe pod and recent usage before deciding whether the limit is too low or the app is leaking memory.

Over memory you are killed; over CPU you are throttled.

§4

Autoscaling — pods on one axis, nodes on another

More load may require more app copies, more nodes, or both. A Horizontal Pod Autoscaler (HPA) changes the requested replica count using a configured metric. For CPU-utilization scaling, it compares measured CPU with the container's CPU request, so that request must be set. Other metric types have different requirements. The HPA also needs working metrics collection; check its status rather than assuming the signal is available.

The HPA can request ten pods, but some may stay Pending if they cannot be scheduled. An enabled cluster autoscaler can add nodes for pods blocked by resource capacity, within the pool's configured maximum and subscription quota. It cannot fix every Pending cause, such as an invalid image or incompatible placement rule. First read the pod's events. The distinction remains useful: the HPA requests pod replicas; the cluster autoscaler can change node count.

One more name to know but not yet wire up: KEDA, an event-driven autoscaler add-on for AKS. Where the HPA scales on CPU and memory, KEDA scales on the size of a queue, the lag on a topic, or a scheduled time — and it can scale a workload to zero when there is nothing to do. It is the right tool for a job that is bursty and event-shaped rather than steadily loaded; note where it lives so you reach for it when a queue, not a CPU graph, is what should drive your replica count.

Horizontal Pod Autoscaler
Changes desired pod replicas against a configured metric. CPU-utilization targets need CPU requests and working metrics. Answers "how many copies?"
Cluster autoscaler
When enabled, adjusts nodes in a pool for eligible unschedulable pods or safe scale-down, within limits. Answers "is there capacity for the copies?"
KEDA (add-on)
Event-driven scaling on queues, topics, or schedules — and down to zero. For bursty, event-shaped work rather than steady CPU load.
§5

Putting it on the workload — a Deployment that behaves under load

Take the objects from §1 through §4 and they are not four features; they are one hardened workload. Config and secrets come from outside the image, so the same build runs everywhere. Probes let the cluster route around a pod that is warming up and restart one that has truly wedged. Requests and limits make the pod a good tenant of its node, guaranteed its share and barred from eating its neighbours'. And an HPA turns a traffic spike into more replicas instead of a queue of dying pods. None of it is exotic; all of it is the difference between a demo and something you can leave running.

The order matters, too. You cannot sanely add an HPA before you have set requests, because the HPA measures against them; you should not set a memory limit without watching real usage first, or you are just guessing at the altitude where OOMKilled starts. So the honest sequence is: externalise config, add probes, observe real CPU and memory, set requests and limits from what you saw, then add the autoscaler on top. Each step earns the next, and doing them out of order is how a workload that looked fine in the demo falls over the first busy afternoon.

Case File · Campux Retail

The partner gateway learns to survive a wholesale spike

probes, sensible requests and limits, and an HPA — still one boring cluster

The partner-gateway Deployment in the partner-gw namespace has run its two replicas quietly since Part A, and now the first real wholesale partner is going live. Their nightly order pushes are spiky — a quiet gateway, then a flood as a partner's own batch fires. So the Deployment gets a readiness probe on its health endpoint, so a warming pod never takes traffic mid-restart, and CPU and memory requests and limits set from a week of watched usage rather than from a guess. Then an HPA on the same Deployment: keep two replicas at rest, add more up to a modest cap when CPU climbs, and settle back down when the flood passes.2

What they deliberately do not do is as important. The storefront stays on App Service; the nightly pos-batch job stays on Container Apps, scaling to zero as before. Nobody moves those onto the cluster because the gateway now has an autoscaler and "we have the room." The cluster is still exactly the size of the wholesale contract that justified it — it has simply learned to breathe with that one workload's load, so a partner's traffic spike stretches it instead of toppling it. Boring, on purpose, and now a little harder to knock over.

On the job

The pod that keeps restarting every few minutes

You · Cloud Engineer · a pod is CrashLooping and nobody changed the code

A pod is restarting on a loop and the app logs look clean. Before you touch the code you read the mechanism: kubectl describe pod and look at Last State. If the reason is OOMKilled, the memory limit is too low for real usage — raise it, or find the leak, but stop blaming the app. If instead the liveness probe is failing, ask what it points at: a probe wired to a downstream dependency turns that dependency's outage into your own restart storm. Two minutes of reading the exit reason saves an afternoon of changing things at random.

Class Twenty-Seven · Part B

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
A container exceeds the memory limit you set on it. What does Kubernetes do?
Marked

B. Crossing a memory limit can lead to an OOM kill. In a typical Deployment pod, the container restarts, but that is governed by the pod's restart policy. CPU over a limit is throttled instead. Kubernetes does not automatically move this pod to a larger node, and a memory limit is more than a scheduling hint. Inspect the last termination reason and memory usage before choosing a new limit or fixing a leak.

Drill 02Recall
An HPA requests eight replicas. Four new pods are Pending, and kubectl describe pod says Insufficient cpu on the eligible nodes. Which control can add capacity, if enabled and within quota?
Marked

B. The pod events identify a CPU-capacity shortage. An enabled cluster autoscaler can grow a suitable node pool, subject to its maximum and Azure quota. Raising the HPA cap creates more Pending pods. Reducing memory limits does not add the requested CPU capacity and could cause OOM kills. Service type changes exposure, not scheduling. Pending alone is insufficient evidence; read the events first.

Drill 03Select three
Which three statements about workloads and config on AKS are true?
Marked

Secret readability, CPU-HPA requests, and readiness gating traffic. Anyone authorized to read a Secret object can decode its base64 value; AKS disk encryption does not change that API access. CPU-utilization HPA needs CPU requests as its denominator. Readiness removes an unready pod from Service endpoints; liveness can restart a failing container. Requests guide placement; limits constrain use.

Drill 04Spot the error
A junior posts this plan for hardening the gateway Deployment. One line rests on a misunderstanding that will cause a self-inflicted outage. Which?
# plan: make the gateway survive load
1.  Move the API key out of the image into a Secret.
2.  Add a readiness probe on /healthz so warming
    pods do not take traffic.
3.  Point the liveness probe at the upstream partner
    API, so we restart if the partner is down.
4.  Set CPU and memory requests, then add an HPA.
Marked

Line three. A liveness probe is a restart switch for "is this container itself wedged." Aim it at the upstream partner API and you hand that partner the power to reboot your pods: the moment their API has a bad ten minutes, your perfectly healthy gateway fails its liveness check and Kubernetes kills and restarts it on a loop — an outage you manufactured out of someone else's. Liveness should test only the pod's own health; a dependency's reachability belongs in readiness at most, or in your app's own retry logic.

The other lines are valid in this plan. A Secret can hold an API key, though it still needs access controls and rotation. Readiness probes belong in the Deployment's pod template. CPU-utilization HPA needs CPU requests. Do not let an upstream service's outage trigger your own container restarts.

Situation 01Write before you reveal
A teammate says: "We put the database password in a Kubernetes Secret, so it is encrypted and we are fine for the audit." You know that is not quite right. How do you correct them without either waving it away or overstating the danger?
The word "Secret" is doing more work in their sentence than the object actually does.
Reasoning

Separate three facts. The manifest's base64 value is reversible, so anyone permitted to read the Secret object can decode it. AKS encrypts managed disks at rest by default, and KMS protection for Secret data in etcd can be enabled. Neither encryption layer by itself proves that the application and every operator have appropriately narrow access.

Ask what the audit requires. Check who can read the object through Kubernetes RBAC, whether plaintext appears in Git or logs, how the password is rotated, and whether KMS or customer-managed keys are required. A Secret is a valid mechanism when these controls satisfy the requirement; its name alone is not evidence.

Offer a concrete next step. For an Azure-managed password, evaluate Key Vault with Entra Workload Identity so the workload authenticates without a long-lived Azure credential. Document the exact retrieval, access, rotation and incident procedures before claiming compliance.

Situation 02Write before you reveal
During a spike, the gateway's pods hit their CPU limit and responses slow down. A colleague proposes removing CPU limits. What would you check before accepting or rejecting that change?
Look at throttling, node headroom, neighbours, request sizing, and whether the app can scale out.
Reasoning

Measure the bottleneck. Confirm CPU throttling, request and limit values, node utilization, HPA status, replica readiness and response latency. A CPU limit can cause avoidable throttling when spare CPU is available; removing or raising it can be reasonable for some workloads. It does not create extra CPU when the node is saturated.

Check the shared-node tradeoff. Without a CPU limit, a busy container may use spare cycles, but it can also compete more aggressively with neighbours. CPU requests and scheduling still matter. Decide whether this gateway has dedicated capacity or shares nodes with sensitive workloads, and test the change under representative load.

Choose the measured fix. If throttling is the main problem and nodes have headroom, adjust the limit or remove it with monitoring. If total demand exceeds node capacity, add replicas and nodes where the app can scale horizontally. Revisit CPU requests and HPA targets from observed usage, and verify latency and neighbour health after the change.

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

Five things worth carrying out of Part B

  1. ConfigMaps and Secrets keep environment settings out of an image that reads them at runtime. Base64 does not hide a Secret from authorized readers; use access, encryption and rotation controls or an external store.
  2. Three probes: liveness restarts a wedged container, readiness pulls a pod out of its Service without killing it, startup protects a slow boot from the liveness probe. Never aim liveness at a dependency you do not control.
  3. A request guides placement; a limit constrains use. CPU over a limit is throttled; a container over a memory limit can be OOMKilled. Inspect usage before changing either value.
  4. The HPA changes desired replicas using a configured metric; CPU-utilization targets need CPU requests. An enabled cluster autoscaler can adjust nodes for eligible unschedulable pods within quota and pool limits.
  5. KEDA is the event-driven add-on for queue-, topic-, or schedule-shaped work, and can scale to zero. Reach for it when a queue, not a CPU graph, should drive the replica count.
Notes
  1. Microsoft's AKS security guidance distinguishes default managed-disk encryption from optional KMS protection of Kubernetes Secret data in etcd. A reader authorized through the Kubernetes API can still retrieve the Secret value, so restrict that access and rotate credentials. ↩
  2. Treat any specific replica counts and limit values in this part as illustration, not prescription. The only honest way to set requests and limits is to watch a workload's real CPU and memory for a while and set them from what you saw, then revisit after load changes. Numbers copied from a blog post are guesses wearing a uniform; the method — observe, set, revisit — is the part worth keeping. ↩