Lab 11 — Azure Containers with ACR, ACI, and Container Apps
azure administrator series

Cover illustration; not a Portal screenshot.
Draft ZIP SHA-256: 7d923ed407de8a4f6c1659a0001d48a424ccccd4ed6c2f6c99841869c4b52541
Implementation package · 150–210 minutes · Azure CLI, PowerShell 7, Bicep and Portal
Instructional walkthrough with offline-checked scripts. Live Azure execution and Portal evidence are outside the verified scope of this release. Follow the steps in a disposable environment and collect your own validation evidence.
What you will learn
Deploy one Microsoft sample image from an authenticated registry into two Azure container services. Compare container-group replacement with Container Apps revisions, change CPU and memory, observe actual replicas, and troubleshoot a replacement revision that cannot pull its image.
The failure is a rollout failure, not an assumed application outage. In single-revision mode, the previously healthy revision should continue serving until its replacement is ready. Verify that behavior rather than treating an image-pull error as proof that all traffic has stopped.
The workshop maps to the AZ-104 objectives for Azure Container Registry, Azure Container Instances, Azure Container Apps, sizing and scaling. It is an independent training exercise, not an official Microsoft exam lab. AZ-104 study guide.
Design and limits
One fresh resource group in West Europe contains a Basic ACR, one user-assigned managed identity, an ACI group, a Consumption environment, and one Container App. The environment may create Azure-managed infrastructure; track its returned relationship, not a name prefix.
ACR has an authenticated public endpoint, with anonymous pulls and admin credentials disabled. Basic ACR does not provide the private-network design of Premium ACR. This lab explicitly uses RBAC-only permissions and an exact registry-scoped AcrPull assignment. ABAC is explained separately; do not switch permission modes during the exercise. Registry RBAC/ABAC guidance.
ACI has no public IP or DNS label. The Container App has public HTTPS ingress restricted to exactly one verified workstation IPv4 /32 from its first deployment. There is no temporary unrestricted ingress, allow-all fallback, customer VM, VNet, NAT Gateway, Bastion or Log Analytics workspace. Persistent Container Apps log storage is disabled; bounded live diagnostics remain available.
The source is Microsoft's mcr.microsoft.com/k8se/quickstart sample. Resolve its Linux AMD64 manifest, import that digest, and deploy by digest. A tag is a mutable name; a digest identifies the selected manifest. Pinning a digest does not prove that an image is vulnerability-free. Microsoft quickstart.
Allow EUR15 for active resources and retain EUR5 for cleanup. The implementation estimate refreshed on 9 October 2026 was EUR5.33 for a conservative six-hour window; actual billing depends on your offer, usage, taxes and meter updates. Refresh prices immediately before deployment. Stop new exercises at five hours and target cleanup before six.
Before you start
Use a disposable lab environment, the selected Visual Studio Enterprise subscription, PowerShell 7.5 or newer, existing Azure CLI/Bicep, and compatible Az.Accounts/Az.Resources. Do not automatically upgrade tools, install Az.App, register providers, grant permissions, change quota or exempt policies.
CLI and PowerShell must match tenant, subscription and operator. The operator needs the planned resource permissions, image import and console actions, and authority to create the single AcrPull assignment. The managed identity is for image pulls; it is not the operator identity used to administer resources.
Six independent, fresh IPv4 requests—three each to two endpoints, without proxies—must agree. The same gate is repeated before deployment and public requests. If it fails or the recorded address changes, stop public work. Cleanup does not require the workstation IP to remain stable.
Preflight saves quota, governance and pricing records privately. Review policy definitions, parameters and scope before acknowledging -ReviewedGovernance. No provider registration or policy exception is created. After the environment is created, review its CPU quota as well as regional quota. A blocked gate is a reason to stop, not to choose a larger service automatically.
Files and script contract
Start-Lab11.ps1: stages Preflight|Registry|Import|Containers|Sizing|Scaling.
Test-Lab11.ps1: phases Baseline|Fault|Recovery; guest sessions and HTTPS traffic require -Execute.
Invoke-Lab11Fault.ps1 and Restore-Lab11.ps1: controlled image fault and PowerShell recovery.
Reconcile-Lab11.ps1: -Execute -InspectOnly inspects pending operations; -Execute alone records only proven outcomes.
Remove-Lab11.ps1: guarded cleanup, then safe repeated absence verification.
Export-Lab11Evidence.ps1: allowlisted summary, not raw logs or a publication approval.
Test-Lab11Safety.ps1: offline simulations, clearly separate from Azure tests.
Test-Lab11Package.ps1: ZIP and per-file integrity checks.
templates/: separate registry, environment, ACI and app templates. All deployments are Incremental.
Every mutation, import, console session and application request requires -Execute. A normal entry-point preview returns a description without contacting Azure or creating state. Reconciliation with -Execute -InspectOnly reads Azure records and writes a private diagnostic, but never mutates Azure or runs a container command.
-ReviewedWhatIf is an explicit acknowledgement, not an automatic review. First run the stage without that switch to produce private validation/what-if files. Inspect the complete diff; expected changes must be limited to the exact lab targets and intended properties. Then rerun with the acknowledgement. ACI replacement additionally requires reviewing its exact deletion and recreation before execution.
Execution sequence
Run from this package directory in PowerShell 7. Choose a new private directory outside the downloadable package. Never place private state, signed console URLs, credentials or raw evidence inside this folder.
$privateDir = Join-Path (Resolve-Path ..) ('lab11-private-' + [guid]::NewGuid().ToString('N'))
./Initialize-Lab11StateDirectory.ps1 -Path $privateDir -Execute
$statePath = Join-Path $privateDir 'state.json'
# Read-only Azure checks; writes a new local manifest only if gates pass.
./Start-Lab11.ps1 -StatePath $statePath -Stage Preflight -ExecuteIf governance review is required, inspect the private report first, then rerun preflight with -ReviewedGovernance. Never acknowledge an unread report. If preflight fails before the manifest exists, nothing has been deployed; retain the private diagnostics and fix the prerequisite.
1. Registry and immutable import — approximately 20 minutes
./Start-Lab11.ps1 -StatePath $statePath -Stage Registry -Execute
# Inspect private *.whatif.json, then acknowledge the reviewed registry change.
./Start-Lab11.ps1 -StatePath $statePath -Stage Registry -Execute -ReviewedWhatIf
./Start-Lab11.ps1 -StatePath $statePath -Stage Import -ExecuteThe first Registry attempt can create the isolated owned resource group before ARM validation/what-if. It does not submit the resource template until review is acknowledged. Record the source and imported digests; the import must match. Do not retrieve registry passwords or enable its admin user to make a pull succeed.
In Portal, check Basic SKU, authenticated access, RBAC-only permission mode, admin disabled, the managed identity, and its registry-scoped AcrPull assignment. Hide account identifiers before capturing evidence. No password values should ever appear.
2. Containers and baseline — approximately 30 minutes
./Start-Lab11.ps1 -StatePath $statePath -Stage Containers -Execute
# Review each environment/ACI/app diff as it is produced, then resume.
./Start-Lab11.ps1 -StatePath $statePath -Stage Containers -Execute -ReviewedWhatIf
./Test-Lab11.ps1 -StatePath $statePath -Phase Baseline -ExecuteReview the initial app template before allowing ingress: external HTTPS, port 80, exactly one workstation Allow rule, minimum one and maximum two replicas. ACI must not gain an address or DNS label. Confirm the actual pull identity and digest, not merely a successful deployment status.
The validation runs bounded authenticated console checkpoints and SHA-256 checks for /app/static/index.html in both containers. It requires the sample to contain sha256sum and curl; changed sample capabilities stop the lab. Do not silently install tools or substitute another image.
A fresh workstation request must return HTTP 200 and the expected sample page. A separate HTTPS request originating inside ACI must be denied while the app restriction remains unchanged. A generic 403 alone is insufficient: retain the origin, actual response, unchanged rule, and successful approved-source request together.
Capture the genuine Portal application browser and console checkpoints now. Close the application browser before the later scale-to-zero observation.
3. Missing-tag challenge and recovery — approximately 30 minutes
Read challenge.md before opening hints or the separate solution.
./Invoke-Lab11Fault.ps1 -StatePath $statePath -Execute
./Test-Lab11.ps1 -StatePath $statePath -Phase Fault -ExecuteThe fault script snapshots configuration, confirms a unique tag is absent, then changes only the image reference and revision suffix. It saves the actual CLI response, revision state and bounded system logs privately. An unfamiliar diagnostic must be investigated; do not replace it with a guessed error code.
Inspect the failed revision and prior healthy revision separately. Validate that the old revision still serves HTTP 200 with unchanged bytes, and that the identity, AcrPull assignment, ingress, good digest and ACI configuration remain intact. Single-revision behavior.
./Restore-Lab11.ps1 -StatePath $statePath -Execute
# Review app-only what-if; no ingress, identity or permission changes are acceptable.
./Restore-Lab11.ps1 -StatePath $statePath -Execute -ReviewedWhatIf
./Test-Lab11.ps1 -StatePath $statePath -Phase Recovery -Execute
./Restore-Lab11.ps1 -StatePath $statePath -Execute -ReviewedWhatIfRecovery uses PowerShell's New-AzResourceGroupDeployment and restores the captured digest. The repeat path validates healthy desired state without deploying again; compare revision counts before and after. A passing HTTP page alone does not prove the desired replacement became ready.
4. CPU and memory sizing — approximately 25 minutes
./Start-Lab11.ps1 -StatePath $statePath -Stage Sizing -Execute -ReviewedWhatIfReview the sizing templates and exact ACI replacement plan before acknowledging this stage. ACI goes from 1 vCPU/1.5 GiB to 2 vCPU/2 GiB and back by deleting and recreating only the recorded disposable group. These are not supported in-place CPU/memory changes. The image hash can remain identical because the same image is used; this is not evidence that ephemeral writable data survived replacement. ACI update limitations.
Container Apps changes from 0.25 vCPU/0.5 GiB to 0.5 vCPU/1 GiB and back. Inspect each revision, actual ready replicas, requested resources and original hash. Record service-generated defaults separately from intended changes.
5. Observed scaling and HTTP activation — approximately 25 minutes
Close all sample-page browser tabs and stop traffic generators. Portal management views can stay open, but do not leave the public application page refreshing.
./Start-Lab11.ps1 -StatePath $statePath -Stage Scaling -Execute -ReviewedWhatIfThe script demonstrates minimum replicas 1 → 2 → 1, with maximum two throughout. It then sets minimum zero with an HTTP scaling rule, generates no application traffic during the bounded observation, and requires an actual zero-replica result. A fresh approved HTTPS request must activate a replica and return the same page. Minimum one is restored afterward.
Control-plane replica inspection does not send application requests. A timeout, background browser traffic, or configured minimum zero is not a successful scale-to-zero observation. Do not claim equal request distribution. Container Apps scaling.
6. Cleanup and evidence — approximately 20 minutes
./Remove-Lab11.ps1 -StatePath $statePath -Execute
./Remove-Lab11.ps1 -StatePath $statePath -Execute
./Export-Lab11Evidence.ps1 -StatePath $statePath -Destination './evidence-summary.json' -ExecuteCleanup removes only exact recorded assignments and resources, recorded deployment history, and empty owned groups. It verifies absence, and the second invocation must make no deletion. If unexpected resources or managed infrastructure remain, stop and investigate. Never force-delete a group by name prefix.
Retain the ACL-protected manifest and raw records privately for audit. Console authentication material is never persisted by these scripts. This sample uses no generated password, local container credentials or SSH key, so there is no credential file to publish or archive.
Interrupted operations
./Reconcile-Lab11.ps1 -StatePath $statePath -Execute -InspectOnly
./Reconcile-Lab11.ps1 -StatePath $statePath -ExecuteReconciliation checks exact deployment operations, terminal states and target IDs. A failed/canceled deployment can record proven successful partial resources for cleanup; the run becomes cleanup-only. An interrupted ACI deletion does not trigger automatic recreation. Uncertain state is not permission to retry a destructive command.
The exclusive lock is held across each stage. ACLs grant access only to the current Windows user and SYSTEM, with reparse-point checks. A mismatched tenant, target ID, owner, configuration or source address blocks progress. Do not edit a manifest to force a passing result.
Validation scope and release checklist
The download includes release-checklist.md, portal-evidence-guide.md and validation-report.md. Use them to verify the Azure exercises, repeat recovery safely, clean up twice, review genuine screenshots and check package integrity. The neon cover is an illustration, not operational evidence.
Series navigation links to the previous lab and the workshop collection are included below. Website ordering and Wix mobile-preview checks are separate from Azure validation; no actual-phone testing is claimed.
Previous lab: Lab 10 — VM Availability, Scale Sets, and Load Balancing.
The package includes a LinkedIn announcement draft. No LinkedIn post has been sent.
Challenge: the replacement never becomes ready
azure administrator series · Lab 11
You manage a small container application whose previous deployment was healthy. A change has created a replacement revision that cannot become ready. The approved workstation can still load the application page.
Your task is to explain the failed rollout, recover the intended desired state and prove that the original application contents remain unchanged.
Boundaries
Do not rebuild the environment, enable registry admin credentials, grant additional permissions, switch authorization modes, broaden ingress, replace the sample application or remove unrelated resources. Keep the recorded maximum at two replicas. Inspect genuine diagnostics before choosing a remedy.
Evidence to produce
Identify the failing revision and actual diagnostic. Compare it with the healthy serving revision, registry contents, image-pull identity and configuration. Show fresh approved-source HTTPS access before and after recovery. Verify the original container file hash, readiness and repeatable recovery without an extra revision.
Your conclusion must distinguish application availability from replacement readiness. A green old revision does not make the failed rollout healthy, and a failed new revision does not by itself prove an outage.
Open hints.md only when needed. Keep the solution separate until your investigation is complete.
Progressive hints
Hint 1
Compare the latest revision with the latest ready revision. Are they the same object? Which revision currently handles traffic?
Hint 2
Inspect the failing container's actual startup/pull diagnostic. Separate a missing image from authentication, network and application-readiness failures.
Hint 3
Compare the replacement's image reference with the registry inventory and the captured healthy reference. Check a tag and a digest separately.
Hint 4
Verify the existing user-assigned identity, registry-scoped AcrPull assignment, registry permission mode and ingress restriction. Do not change controls merely because the diagnostic mentions a pull.
Hint 5
Restore the captured known-good digest with the app-only PowerShell template. Verify that the replacement is ready, the static-file SHA-256 matches, fresh HTTPS succeeds, and repeated recovery deploys nothing.
Separate solution
Try the challenge and progressive hints first. The solution is also a separate solution.md file in the draft download.
Reveal the expected recovery procedure
azure administrator series · Lab 11
The planned fault changes the app's image to a unique tag confirmed absent from its lab repository. The failed pull prevents the replacement revision from becoming ready. The expected live diagnostic must name that reference and explain the pull/manifest problem; capture the actual text rather than assuming a fixed error code.
In single-revision mode, the prior healthy revision remains the serving revision until a replacement is ready. Verify this with its exact private revision identity, a fresh approved-source HTTP 200, and the original page/file hash. Also verify unchanged ingress, pull identity, role assignment and ACI configuration.
Run Restore-Lab11.ps1 with -StatePath and -Execute to generate validation/what-if. Review the app-only diff, then acknowledge it with -ReviewedWhatIf. PowerShell redeploys only the app template incrementally with the captured registry digest and expected settings. It does not grant roles, enable credentials or loosen network restrictions.
Recovery is complete only when the intended replacement is ready, the original hash is reproduced and fresh HTTPS access succeeds. Run recovery a second time. The script should validate without submitting a deployment and should leave the revision count unchanged.
If a live result differs from this expected scenario, investigate the actual response. A role or network change, missing inspection tool, drifting source IP, or ambiguous operation is a stop condition—not a reason to declare the lab passed.
Eight knowledge checks and answers
1. What does Azure Container Registry provide that ACI and Container Apps do not?
ACR stores and distributes container images. ACI runs container groups; Container Apps provides managed application hosting with revisions, ingress and scaling.
2. Why pin the healthy deployment to a digest instead of latest?
Tags can be moved to different manifests. A digest identifies the selected manifest, making the intended image reference explicit. It is not a vulnerability guarantee.
3. Which identity and role does this RBAC-only registry use for image pulls?
The recorded user-assigned managed identity has AcrPull at the exact lab registry scope. The registry remains RBAC-only. ABAC repository permission mode has different supported roles.
4. Does a failed replacement revision necessarily stop a single-revision app from serving traffic?
No. In single-revision mode, the previous healthy revision continues serving until the replacement is ready. Confirm both readiness and serving behavior; do not infer an outage solely from the failed rollout.
5. Can ACI CPU and memory be changed in place in this exercise?
No. Delete and recreate only the disposable recorded group for those CPU/memory changes. Identical image contents after recreation do not prove writable-layer persistence.
6. Why is setting minimum replicas to zero insufficient evidence of scale-to-zero?
Traffic, scaling rules and timing affect actual replicas. Stop application traffic and observe the real count reach zero, then verify that a fresh HTTPS request activates a replica.
7. Does authenticated public ACR access mean that Container Apps ingress is unrestricted?
No. Registry authentication and application ingress are independent controls. The app starts with one workstation IPv4 /32 Allow rule and secure ingress; ACI has no public address.
8. What makes recovery and cleanup safe to repeat?
Recovery compares desired state before acting and verifies no extra revision on repetition. Cleanup uses exact recorded identities, ownership/provenance checks, deletion confirmation and empty-group checks, then verifies absence again. Neither operation adopts targets by name prefix.
Lab 11 validation report
Validation report scope: offline authoring checks, 9 October 2026. The downloadable package retains its implementation-draft status.
The validation summary below covers source-image provenance, offline script checks, template builds and package integrity. It is not a live Azure test report.
Completed authoring checks
All four Bicep templates build using installed Bicep 0.46.1 and Azure CLI 2.88.0. The registry API is 2025-11-01 to support the explicit RBAC-only permission mode. Environment/app APIs are 2025-01-01; ACI uses 2023-05-01. No tools or modules were upgraded.
PowerShell 7.5 syntax parsing passes. PSScriptAnalyzer is available and is used for static review; warnings and any repairs are recorded in the package's authoring-check results rather than described as a live Azure pass.
Offline tests pass for mismatched target/recorded IDs, mismatched contexts, matching contexts in the wrong recorded tenant, broad/shared CIDRs, pending-operation rejection, actual exclusive file locking and seven no-execution entry-point previews. These use synthetic local fixtures and make zero Azure calls. They do not establish Azure policy behavior, console protocol compatibility or successful interrupted-cloud-operation reconciliation.
The Retail Prices API, refreshed at 16:56 UTC, produced a EUR5.33 conservative six-hour active estimate, with EUR5 reserved for cleanup. This is a retail estimate, not a guaranteed invoice total. The estimate includes peak ACI allocation, overlapping app revisions, a full registry day and EUR3 for bounded ancillary consumption.
Microsoft's source sample resolves to Linux AMD64 with manifest digest:
sha256:3a4d93c34c6753f24765ab17a36f1754aee9b02082b7d9553d17697b9e8252c4
This is source provenance inspection, not proof of a successful Azure import or image pull.
Before running the workshop
Use a stable outbound IPv4. Proceed only if six fresh samples agree and remain consistent throughout the public exercise. Run the staged workflow and record actual evidence for baseline, fault, recovery, scaling and cleanup.
Comments