CAMPUX Cloud Bootcamp Phase Four · Class Twenty-Seven
Phase Four — Operate, Secure & AI
Reading 35 min · Drills 6 · 3 Labs
Build IV foundations
Class Twenty-Seven

Containers on Azure

The image is built and sitting in the registry; Azure offers three different homes for it, and picking the wrong one costs either money you did not need to spend or engineers you do not have.

§1

The decision — three homes for one image

Last class ended with pos-batch:1.0 in the registry and nowhere to run. Azure's answer is not one service but a menu, and the menu is where engineers get talked into overspending — because the most famous option is also the most expensive to operate, and the fame does the selling. Learn the three main choices as a single decision, made on two questions: how much control do you actually need, and who is going to operate it?

Table 1 — The decision, as a ledger
App Service (containers)Container AppsAKS
What it isThe classic web-app platform, fed an image instead of codeServerless containers on managed Kubernetes you never seeKubernetes itself, with Azure running the control plane
Best atOne web app or API, plain and steadyMicroservices, background jobs, event-driven work, spiky trafficFull control: custom networking, service mesh, anything Kubernetes can express
Scale to zeroNo — the plan bills while it existsYes — zero replicas, zero compute costNot natively — nodes bill while they exist
Kubernetes knowledgeNoneNone — it is inside, but not your problemReal, ongoing, and on-call
Operating cost in peopleNear zeroNear zeroA team, or a slice of everyone, forever

The reading order matters: start in the middle. Container Apps is the default answer for containerized work at the scale of most companies, App Service remains a fine home when the workload is literally "one web app", and AKS is the choice you make when a named requirement demands Kubernetes' full surface — and you can staff it. That last clause is §3's whole subject, because it is the clause the enthusiasm always omits.1

§2

Container Apps — the serverless middle

Azure Container Apps runs your image on a Kubernetes-based platform that Azure operates entirely — you hand it an image, a port, and scaling rules; it handles the machines, the orchestration, the restarts, and the TLS-terminated URL. The unit of organisation is an environment (a secure boundary sharing networking and logging), inside which live two kinds of compute: apps, which run continuously and restart if they fail — web APIs, storefronts, queue processors — and jobs, which start, do a finite piece of work, and stop, triggered manually, on a cron schedule, or by events.

Container app
A container that Azure runs, scales, and heals for you — from a maximum replica count down to zero — billed by the seconds of CPU and memory it actually consumes, with the orchestrator entirely out of sight.

The apps-versus-jobs split maps exactly onto Campux's estate: the storefront is an app (always answering, scaled by traffic), and the POS reconciliation is a job (runs nightly for eight minutes, then does not exist). The platform also carries the operational features you would otherwise build: revisions for safe rollouts, secrets and managed identity per Class Nine, and traffic-splitting between versions. What it deliberately hides is Kubernetes itself — no cluster to patch, no nodes to size, no YAML zoo. For the large majority of container workloads, that hiding is not a limitation. It is the product.

§3

AKS — priced in people

Azure Kubernetes Service gives you a genuine Kubernetes cluster with Azure managing the control plane. Everything Kubernetes can do, AKS can do — custom operators, service meshes, GPU node pools, network policies of arbitrary sophistication. When the requirement is real, nothing else answers it. The mistake is thinking the price is the node bill.

The real price is denominated in people. Somebody must plan cluster upgrades three versions deep, because Kubernetes releases move and old versions fall out of support. Somebody must size and patch node pools, tune autoscalers, keep the ingress controller and cert-manager and a dozen add-ons current, understand why a pod is Pending at 2am, and hold the pager. Industry experience puts honest AKS operations at a meaningful slice of several engineers — permanently, not as a project. For a company with forty stores and a platform team you can count on one hand, that slice is the difference between shipping features and tending a cluster. Container Apps exists precisely because Microsoft noticed how many AKS clusters were running three small services that never needed Kubernetes' surface at all.2

Kubernetes is a team you hire, not a service you click.

§4

Scale to zero — the January trough, solved

Here is the feature this bootcamp has been walking toward since Class One. Campux's origin story is a mismatch: compute sized for the November peak, billed through the January trough. Every phase has narrowed the waste — reserved sizing, autoscale, disposable environments — but something always ran, and whatever runs, bills. Scale to zero ends the sentence: a Container App with --min-replicas 0 that receives no traffic runs no replicas, and consumption pricing bills the CPU-seconds and memory-seconds you use — which, at zero replicas, is zero.

The trade is the cold start: the first request after idleness must wait for a container to start — typically seconds, and Lab 2 has you time it with your own watch. That trade is glorious for some workloads and wrong for others, and the sorting is simple. Nightly jobs, internal tools, dev and test environments, spiky event processors: idle is their natural state, and zero is the correct price for idle. A checkout API in November: set --min-replicas 1 (or more) and pay for the warmth, because a customer's first click should not wait for a container to boot. The point is not that zero is always right; it is that the trough finally has a price of zero available, per workload, as a one-flag decision — and the Class Twenty-Six lesson about small images pays again here, because cold-start time is substantially pull time.

§5

The honest AKS interview answer

You will be asked about Kubernetes in interviews — it is the most name-dropped technology in the field — and the trap is symmetrical. Dismiss it and you sound like you cannot operate serious infrastructure; gush over it and you sound like you have never paid for it. The honest answer has three moves. First, demonstrate you understand what it is: the industry's standard orchestrator, the full-control option, the thing Container Apps is built on. Second, name the decision rule: Kubernetes when a requirement demands its surface — custom networking, operators, multi-hundred-service estates, portability mandates — and a managed abstraction when none does. Third, price it out loud: "AKS is the right tool when you can dedicate real engineering capacity to operating it; at my last project the workload was three services and a nightly job, so Container Apps delivered the same containers with zero cluster operations."

That answer wins both rooms, the same way Class Twenty-One's Bicep-versus-Terraform rule did: shops running AKS hear that you will not fight the platform, and shops that avoided it hear that you will not burn their headcount on résumé-driven infrastructure. The pattern is now familiar enough to name — the senior answer to "which technology?" is always a decision rule with a price attached. Juniors pick sides; seniors pick criteria.

Case File · Campux Retail

The trough finally costs nothing

pos-batch lands on Container Apps; nobody hires a cluster team

The decision meeting is short, because Table 1 makes it short. The storefront is already happy on App Service. The POS job needs to run at 02:00 for about eight minutes and not exist otherwise — a textbook scheduled job. Nothing at Campux needs custom operators, service meshes, or GPU pools, and the platform team is four people who have other work. So: a Container Apps environment in rg-campux-platform, written in Bicep like everything else; the job created with a cron trigger, pulling pos-batch:1.0 from the registry with a managed identity — no password, per Class Nine; deployed through the pipeline, per Phase Three.

Then the bill arrives, and it is the best number in the bootcamp. The old VM ran the batch job for eight minutes a day and billed for twenty-four hours of existing — 99.4 percent of its cost was idleness. The job now bills roughly eight minutes of consumption per day, and the January trough, the thing that started this entire course in Class One, finally costs what it should: nothing.3 The CTO reads the invoice twice. Then he reads a blog post about Kubernetes, and asks the question that becomes this class's Situation 01.

Watch · Microsoft Learn

The official pages, and a CAMPUX overview

The quickstart mirrors Lab 1; the jobs page is Lab 3's reference
Microsoft Learn · Docs

Quickstart: deploy your first container app
learn.microsoft.com/azure/container-apps/get-started

Jobs in Azure Container Apps
learn.microsoft.com/azure/container-apps/jobs

CAMPUX overview video

The Table 1 decision walked out loud, a live scale-to-zero with a stopwatch on the cold start, and the scheduled job firing on its cron will live here. Video to be added.

Lab 1 · First container app

One command to a public URL

~10 minutes · Cloud Shell or az CLI · everything lands in one throwaway resource group

Deploy a container to a live, HTTPS-terminated public URL with a single command, then look behind the curtain at what Azure created for you. Labs 2 and 3 reuse everything this lab builds — run them in one sitting.

  1. One-time setup — the Container Apps CLI extension and resource providers:

    az extension add --name containerapp --upgrade
    az provider register --namespace Microsoft.App
    az provider register --namespace Microsoft.OperationalInsights
    What to notice: provider registration can take a minute or two the first time and is once-per-subscription. If step 2 complains about the provider, wait a moment and rerun it.
  2. Deploy Microsoft's quickstart image — one command does everything:

    az containerapp up \
      --name campux-hello \
      --resource-group rg-aca-lab \
      --location eastus \
      --environment aca-lab-env \
      --image mcr.microsoft.com/k8se/quickstart:latest \
      --target-port 80 \
      --ingress external \
      --query properties.configuration.ingress.fqdn
    On screen: the command creates the resource group, a Log Analytics workspace, the environment, and the app — then prints a hostname like campux-hello.<something>.eastus.azurecontainerapps.io. That hostname is your deliverable.
  3. Open the printed URL in a browser.

    On screen: the "Your Azure Container Apps app is live" welcome page — over HTTPS, with a certificate you never configured. Compare the effort against Phase Two: no VM, no load balancer, no NSG, no cert. All of that still exists; it is simply no longer your job.
  4. Look at what actually got created:

    az resource list --resource-group rg-aca-lab -o table
    The lesson: a managed environment, a container app, and a Log Analytics workspace — three resources where Phase Two needed a page of them. Leave everything running: Lab 2 starts from exactly here.
Lab 2 · Scale to zero

Watch it disappear, then time the resurrection

~10 minutes · continues Lab 1 · bring a stopwatch (your phone counts)

Turn on scale-to-zero, watch the replicas actually vanish, and measure the cold start with your own timer — after this lab, §4's trade is something you have felt, not read.

  1. Allow the app to scale to zero:

    az containerapp update \
      --name campux-hello \
      --resource-group rg-aca-lab \
      --min-replicas 0 \
      --max-replicas 3
    What to notice: one flag is the entire §4 decision. min-replicas 0 means "idle may cost nothing"; a checkout API in November would set 1 or more here instead.
  2. Stop visiting the URL, wait five to ten minutes (make tea), then count the replicas:

    az containerapp replica list \
      --name campux-hello \
      --resource-group rg-aca-lab -o table
    On screen: an empty list. Nothing is running. Right now this app consumes no CPU, no memory, and — on consumption pricing — no money. This is the state the old Campux VM could never reach.
  3. Now resurrect it: start your stopwatch, load the URL, and stop timing when the page renders.

    On screen: a pause — typically a handful of seconds — and then the page. That pause was Azure pulling the image and starting a container because you knocked. Run replica list again: one replica exists, born from your request.
  4. Load the page again immediately and compare.

    The lesson: the second load is instant — the replica is warm. You have now personally measured both sides of §4's trade: seconds of cold start against a price of zero for idleness. Say the numbers out loud; they are your interview evidence. Leave the app running for Lab 3's environment.
Note · idle-to-zero timing varies — if the replica list is not empty yet, wait a few more minutes. Cold-start time depends heavily on image size, which is the Class 26 small-image lesson collecting interest.
Lab 3 · The nightly job

Run the batch job on a schedule — Campux's actual design

~15 minutes · continues Lab 2 · uses Microsoft's sample job image

Build the case file for real: a scheduled Container Apps job that runs every two minutes (so you can watch it), fired by cron, with an execution history. Swap the schedule to 02:00 and the image to pos-batch and this is Campux's production design, line for line.

  1. Create a scheduled job in the same environment:

    az containerapp job create \
      --name pos-batch-job \
      --resource-group rg-aca-lab \
      --environment aca-lab-env \
      --trigger-type Schedule \
      --cron-expression "*/2 * * * *" \
      --image mcr.microsoft.com/k8se/quickstart-jobs:latest \
      --cpu 0.25 --memory 0.5Gi \
      --replica-timeout 300 \
      --replica-retry-limit 1 \
      --parallelism 1 \
      --replica-completion-count 1
    What to notice: */2 * * * * is "every two minutes" — lab speed. Campux's real line is 0 2 * * *: 02:00 every night, evaluated in UTC. The sample image waits a few seconds, prints a message, and exits — a stand-in for eight minutes of reconciliation.
  2. Do not wait for the clock — fire one execution by hand:

    az containerapp job start \
      --name pos-batch-job \
      --resource-group rg-aca-lab
    What to notice: manual start exists on every job type — it is how you rerun a failed night without waiting for tomorrow, and how you test before trusting the schedule.
  3. Watch the execution history fill in (rerun this a few times over the next several minutes):

    az containerapp job execution list \
      --name pos-batch-job \
      --resource-group rg-aca-lab \
      --query "[].{name:name, status:properties.status}" -o table
    On screen: your manual run marked Succeeded, then — as the cron fires — new executions appearing every two minutes, each starting, working, and stopping. Between executions, nothing runs and nothing bills. That rhythm is the case file's cost story.
  4. Read one execution's output in the portal, then tear everything down:

    # portal: Container App Jobs → pos-batch-job → Execution history
    az group delete --name rg-aca-lab --yes --no-wait
    The lesson: the execution history is your morning-after audit: which nights ran, which failed, how long each took. In production this job pulls pos-batch:1.0 from ACR with a managed identity and posts failures to the Class 28 monitoring you are about to build. One delete removes the whole lab — total cost, a few cents.
Note · a job with a two-minute cron left running becomes 720 executions a day — cheap, but noisy. Run the group delete before you leave, and remember cron here is UTC: Campux's "02:00 local" needs converting.
On the job

The right amount of platform

You · Cloud Engineer · a container needs to run in production

The image works; now it has to run somewhere real without you babysitting a VM. You push it to a registry and run it on Container Apps, which scales it on demand and to zero when idle. You get production without a cluster to operate — the right amount of platform for a team that cannot staff Kubernetes.

Class Twenty-Seven

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; this is between you and the page.

Drill 01Pick the service
A report generator runs for ten minutes every night and must cost nothing the rest of the day. Which home fits?
Marked

B. "Finite work, on a schedule, then nothing" is the definition of a scheduled job — Lab 3, verbatim. A fails the cost requirement: an App Service plan bills while it exists, ten minutes of work or not. C answers a batch job with a cluster and an on-call rota — the §3 people-price for a task that needed a cron line. D is the pre-container world: it works, until the "by hand" part meets a holiday, and its idle VM is the exact waste the case file just deleted. The tell in the question is "must cost nothing the rest of the day" — only consumption-billed, scale-to-zero compute can promise that.

Drill 02Pick the service
A team of three runs four small containerized microservices with modest, spiky traffic. No custom networking, no operators, no GPU. They ask which platform to build on. What do you recommend?
Marked

C. This is Table 1's middle column wearing a realistic costume: several services, spiky traffic, no requirement that names Kubernetes' surface, and — the deciding fact — three people. A is the famous trap: "microservices = Kubernetes" was true when Kubernetes was the only orchestrator on offer; Container Apps runs the same containers on the same orchestration without handing three engineers a cluster to operate. B works but pays for four always-on plans and gives up scale-to-zero on the quiet services. D rebuilds Phase Two by hand for no stated reason. Notice what actually decided the answer: not the technology's ceiling, but the team's size. That is §3's lesson doing its job.

Drill 03Select three
Which three are true of Azure Container Apps?
Marked

Scale-to-zero billing, apps-plus-jobs, and the shared environment. The two rejects mark the product's honest edges. Kubernetes is genuinely underneath, but the entire point is that you never touch it — there is no cluster surface for you to administer, which is why Table 1's "Kubernetes knowledge" row reads none; wanting kubectl is the signal you have outgrown the service and earned §3's conversation. And the instant-first-request claim erases the cold start you personally timed in Lab 2 — scale-to-zero is a trade, not magic, and vendors' enthusiasm routinely forgets the trade. Knowing a product's edges as well as its features is what separates an engineer from a brochure.

Drill 04Spot the error
This platform proposal is about to be approved. One line is a serious mistake. Which?
# memo: compute platform for the loyalty-points service
1.  The service is one container: an API with spiky daytime
    traffic and near-zero use overnight.
2.  The team is two engineers, who also own three other services.
3.  We will deploy an AKS cluster, since Kubernetes is the
    industry standard for containers.
4.  Images will come from campuxregistry via managed identity.
Marked

Line three — and lines one and two are the evidence against it. Read the memo as a Table 1 exercise: one container, spiky-to-idle traffic, two engineers already stretched across four services. Every fact points at Container Apps — scale-to-zero for the idle nights, consumption billing for the spikes, zero cluster operations for the two humans. Line three answers none of those facts; it answers a blog post. "Industry standard" is not a requirement — it is the sound a decision makes when nobody priced it, and the price here is §3's: upgrades, node patching, add-on maintenance, and a pager, paid by two people who did not have spare capacity in line two.

The repair is one sentence: replace line three with "we will deploy to Container Apps with min-replicas 0, and revisit if a requirement emerges that names Kubernetes' surface." The other lines are healthy — spiky APIs are normal (A), small teams owning several small services is exactly who managed platforms are for (B), and managed-identity pulls from ACR are the Class Nine pattern working as designed (D). When a proposal's technology choice cites fashion, the reviewer's question is always the same: which line of this memo does the cluster answer? Here, none.

Situation 01Write before you reveal
The CTO, invoice in hand and blog post in browser, says: "This Container Apps thing works, but I keep reading that everyone serious runs Kubernetes. Are we falling behind? Should we migrate to AKS while we're small?" Respond — with the people-cost, not dogma.
He is asking a hiring question wearing a technology costume. Answer both, price first.
Reasoning

Concede the true part before you argue. The blog is not lying: at large engineering organisations, Kubernetes genuinely is the standard, and for their scale — hundreds of services, platform teams by the dozen, requirements that name its surface — it earns its keep. The CTO's instinct to ask "are we behind?" is a good instinct. The correction is one word: the articles describe companies whose constraint is different, and copying a big company's infrastructure without copying its headcount imports the cost while missing the benefit.

Then price the migration in the only currency that matters here: people. AKS at Campux means someone owns cluster upgrades on Kubernetes' release cadence, node patching, autoscaler tuning, ingress and certificate add-ons, and the 2am page when a pod sticks — a permanent slice of a four-person team, spent operating a platform instead of shipping the storefront. And the punchline is on the invoice he is holding: Container Apps is Kubernetes — Azure's team operating it — and the batch job just went from billing twenty-four hours a day to billing eight minutes. Migrating to AKS would mean paying our own people to run the layer Azure currently runs for us, to arrive at a bill that cannot beat the one in his hand.

Close with the trigger list, so "no" is not "never". Name the conditions that would change the answer: a requirement that needs Kubernetes' full surface — custom operators, a service mesh, GPU node pools, a multi-hundred-service estate, or a portability mandate. Write them down; revisit when one appears. And answer the career subtext honestly: the concepts the team learns on Container Apps — images, registries, scaling rules, revisions — are Kubernetes concepts with the sharp edges filed down, so nobody is falling behind by using it. "We run on Kubernetes; we just don't run Kubernetes" is a sentence the CTO can repeat to the board, which is precisely what he needed from you.

Situation 02Write before you reveal
A week after an internal dashboard moves to Container Apps with min-replicas 0, its owner complains: "Every morning the first load takes ages. Scale-to-zero is clearly broken — set it back to always-on." What do you actually do?
Nothing is broken. Something is being traded. Decide the trade per workload — with numbers.
Reasoning

The trap is the premise — "broken" is the wrong word for "working as designed". The morning pause is the Lab 2 cold start: the app scaled to zero overnight (the feature), and the first visitor pays seconds of startup (the price). Say so without condescension, because the owner's experience is real — and then reframe the request from "fix a bug" to "choose a trade", which is a decision, not a repair. Decisions need numbers: how long is the pause actually (measure it — Lab 2 style, not vibes), how many people hit it (one first-loader per morning, or everyone?), and what does always-on cost for this app per month?

Then check the cheap middle options before buying the expensive end. Cold starts are substantially image-pull time, so the Class Twenty-Six small-image work may cut the pause in half for free. If the dashboard's traffic is "everyone at 09:00", a scheduled warm-up — the Class Twenty-Five robot loading the page at 08:55 — makes the first human's experience instant for pennies. Only if the pause remains genuinely painful does min-replicas 1 enter, and then §4's sorting applies: this is an internal dashboard, not the November checkout, so the question is whether seconds once a morning are worth a month of always-on billing. Sometimes they are. Make it a line item, not a reflex.

Close by protecting the principle from the anecdote. The owner's proposal was really "scale-to-zero is bad, revert it" — and if that sentiment spreads, every app drifts back to always-on and the January trough quietly returns. The correct policy is per-workload: zero for the nightly job and the idle dev environments (where it is pure savings), warm replicas where a human's first impression is the product. One complaint, measured, becomes a config choice; unmeasured, it becomes a culture. You are paid to notice the difference.

Examination record · first attempt
0/4
Class Twenty-Seven · Complete
Retain this much

Five things worth carrying out of this class

  1. Three homes, one decision, two questions: how much control does the workload actually need, and who operates it? App Service for one plain web app; Container Apps as the default middle; AKS when a named requirement demands Kubernetes' surface.
  2. Container Apps is serverless containers: environments as the boundary, always-on apps and finite jobs (manual, scheduled, event) inside, orchestration entirely Azure's problem.
  3. AKS is priced in people — upgrades, node patching, add-ons, and a pager, permanently. "Kubernetes is a team you hire, not a service you click."
  4. Scale to zero ends the January trough: min-replicas 0 plus consumption billing makes idle cost nothing, traded against a cold start you should measure, then decide per workload.
  5. The senior answer to "which technology?" is a decision rule with a price attached — for Kubernetes, for Terraform, for everything. Juniors pick sides; seniors pick criteria.
Notes
  1. The menu is longer than three — Azure Container Instances runs single containers with no platform around them, Azure Functions now runs containers, and Service Fabric still exists — but the three in Table 1 cover the decision you will actually face, and the others slot into the same two questions. If a fourth option is on your table, ask it the control question and the people question and it will file itself.
  2. Treat the specific staffing figures with suspicion — "how many engineers does Kubernetes take?" produces answers from one-tenth to ten depending on cluster count, add-on ambition, and who is doing the telling. Treat the direction as settled: operating Kubernetes is a standing engineering commitment, not a setup task, and every honest AKS shop budgets for it. The dishonest ones discover the budget at incident time.
  3. Consumption pricing has fine print worth reading before you promise a CFO zero: environments can carry a small baseline depending on plan type and features (a dedicated plan bills differently, idle-but-allocated resources are not always free, and prices shift). The structural claim survives the fine print — zero replicas costs radically less than an always-on VM — but quote the calculator, not this page, when money is on the table.