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?
| App Service (containers) | Container Apps | AKS | |
|---|---|---|---|
| What it is | The classic web-app platform, fed an image instead of code | Serverless containers on managed Kubernetes you never see | Kubernetes itself, with Azure running the control plane |
| Best at | One web app or API, plain and steady | Microservices, background jobs, event-driven work, spiky traffic | Full control: custom networking, service mesh, anything Kubernetes can express |
| Scale to zero | No — the plan bills while it exists | Yes — zero replicas, zero compute cost | Not natively — nodes bill while they exist |
| Kubernetes knowledge | None | None — it is inside, but not your problem | Real, ongoing, and on-call |
| Operating cost in people | Near zero | Near zero | A 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
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.
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.
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.
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.
The trough finally costs nothing
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.
The official pages, and a CAMPUX overview
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
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.
One command to a public URL
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.
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.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.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.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.
Watch it disappear, then time the resurrection
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.
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.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.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.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.
Run the batch job on a schedule — Campux's actual design
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.
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.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.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 tableOn 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.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-waitThe 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.
The right amount of platform
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.
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.
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.
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.
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.
# 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.
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.
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.
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.
Five things worth carrying out of this class
- 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.
- Container Apps is serverless containers: environments as the boundary, always-on apps and finite jobs (manual, scheduled, event) inside, orchestration entirely Azure's problem.
- 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."
- 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.
- 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.
- 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. ↩
- 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. ↩
- 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. ↩