Registry and deployment
- Lesson 13
- 50 min
- Module 5: Deploy and clean up
Lesson 13 of 15 · Docker and Cloud Essentials for AI DevelopersRegistry and deployment
1. Understand containers
2. Build the application image
3. Networking, configuration and persistence
4. Cloud building blocks
5. Deploy and clean up
What you will be able to do
Put the image where a cloud service can get it, with a version number that never changes its meaning. Then start it on a managed container service that you can delete in one step.
Before you startWhat to know and to have ready
What you need to know
- Tags, and why
latestis not a version, from Dockerfile essentials: Tags and why latest is not a version. - CPU architectures (
linux/arm64andlinux/amd64), from Install and verify: Your computer’s processor architecture. - Settings and secret files at run time, from Runtime configuration: A file of settings and Secret files.
- The resource group, from Regions and service types: Resource groups, subscriptions and tenants.
- The managed identity and the
AcrPullrole, from Identity and secrets: Identities and Roles and scope. - What each resource can cost, from Cost awareness: What can charge.
What you need on your computer
- The project
~/projects/ticket-api(Windows:$HOME\projects\ticket-api) at version 1.1.0, withcompose.yamland the git-ignoredsecrets/api_key.txt. They come from Persistent data: Guided practice: the API and its database and Runtime configuration: Secret files. - Your cloud design with its resource inventory,
docs/cloud-design.md, from Cost awareness: Module practice. This module checks it against what you really make. - Docker Desktop (or Docker Engine on Linux) with Buildx, from Install and verify: Install Docker.
- Live route only: an Azure subscription where you can create resources, and the Azure CLI with the
containerappextension. The live route costs a few cents if you delete everything on the same day (Verify and remove does that). Simulated route: nothing more. It is free. - If your project is missing or broken, copy the snapshot
end-of-m04, as in Use a snapshot. Then makesecrets/api_key.txtagain, as the snapshot’s README says.
Tested with Docker Desktop 4.81.0 (Docker Engine 29.6.1, Buildx 0.35.0) on macOS, Apple silicon. The Azure steps were run with Azure CLI 2.88.0 and the containerapp extension 1.3.0b5, in region canadacentral. The Windows and Linux steps are not tested.
Two routes, one set of ideas
Section titled “Two routes, one set of ideas”This module has two routes. Choose one before you start, and use the same one for all three lessons.
| Live | Simulated | |
|---|---|---|
| Where the API runs | Azure Container Apps, with a public HTTPS address | A container on your computer, from deploy/local-cloud.yaml |
| Registry | Azure Container Registry | A registry container on 127.0.0.1:5000 |
| Cost | A few cents, if you delete everything the same day | Free |
| You need | An Azure subscription | Only Docker |
Every output in these lessons has a label. Live outputs come from the real Azure run. Simulated outputs come from Docker on a Mac on the same day. A simulated output never claims that something ran in a cloud. Both routes give you the evidence for the module practice and the final assignment.
Registry, repository and tag
Section titled “Registry, repository and tag”Amira starts with a small experiment on her computer. She runs a registry: a server that stores images, so that other computers can download them. Docker’s official registry image is one, and it runs on her computer like any other container:
docker run -d --name ticket-api-registry -p 127.0.0.1:5000:5000 -v ticket-api-registry-data:/var/lib/registry registry:3.1.2She gives her image a second name, which starts with the registry’s address, and pushes it (sends it to the registry):
docker tag ticket-api:1.1.0 127.0.0.1:5000/ticket-api:1.1.0docker push 127.0.0.1:5000/ticket-api:1.1.0The output (simulated, shortened):
The push refers to repository [127.0.0.1:5000/ticket-api]0b13ca62e0be: Pushed4732e419703d: Pushed...bbeda6b4abb7: Pushed1.1.0: digest: sha256:1ba724a2b1215f0d2225b7276fa6ab5f5226c1e10c46c98ee9845af3fec459ee size: 856Then she asks the registry what it has. A registry answers HTTP requests, so curl can ask:
curl -s http://127.0.0.1:5000/v2/_catalogcurl -s http://127.0.0.1:5000/v2/ticket-api/tags/listThe output (simulated):
{"repositories":["ticket-api"]}{"name":"ticket-api","tags":["1.1.0"]}Now the names. A full image name has three parts: <registry>/<repository>:<tag>.
| Part | Here | Live route |
|---|---|---|
| Registry: the server | 127.0.0.1:5000 |
ticketapi4821.azurecr.io |
| Repository: one image’s versions, together | ticket-api |
ticket-api |
| Tag: one version | 1.1.0 |
1.1.0 |
A name without a registry, such as ticket-api:1.1.0, means Docker Hub, or only your computer if the image was never pushed. The digest (sha256:1ba7…) is the exact content. A tag is a label that points to a digest, and anyone who can push can move it to a different digest. That is why every change gets a new version number: 1.1.0, then 1.1.1. Never deploy only latest. In a month, nobody can say which code latest was.
Each Pushed line is one layer. The registry stores layers, not whole images, so a second push of a similar image sends only the layers that changed. The push moves the compressed layers: the content size column of docker image ls (73MB for ticket-api:1.1.0), not the disk usage (345MB).
The workflow, and where it can fail
Section titled “The workflow, and where it can fail”A deployment is four actions: build, push, deploy, verify. Each one can fail in a way that you can see, if you know where to look.
Text description of the diagram
The build makes an image for linux/amd64, the CPU type of the cloud servers. Check the platform before you push. The push puts it in the registry under a versioned tag. The deploy makes a new revision: a fixed copy of the app’s settings and image. If the revision cannot start, the old one keeps the traffic. You read the system logs, fix the cause and deploy again. If it starts, the traffic moves to it, and you run the smoke checks. When they pass, you record what you deployed. This lesson does steps 1 to 4. Operational configuration does step 5, and Verify and remove does steps 6 and 7.
Build for the cloud’s CPU
Section titled “Build for the cloud’s CPU”Azure Container Apps runs linux/amd64 images only. A plain docker build on an Apple silicon Mac makes linux/arm64. Amira checks what her image holds:
docker buildx imagetools inspect 127.0.0.1:5000/ticket-api:1.1.0The output (simulated, shortened):
Name: 127.0.0.1:5000/ticket-api:1.1.0MediaType: application/vnd.oci.image.index.v1+jsonDigest: sha256:1ba724a2b1215f0d2225b7276fa6ab5f5226c1e10c46c98ee9845af3fec459ee
Manifests: Name: 127.0.0.1:5000/ticket-api:1.1.0@sha256:97dd1c69... Platform: linux/arm64
Name: 127.0.0.1:5000/ticket-api:1.1.0@sha256:c66bcb26... Platform: unknown/unknownOnly linux/arm64. The unknown/unknown entry is the build’s attestation: a record of how the image was built, not a second image. On an Intel or AMD computer, you see linux/amd64 here, and the next build is the same as yours.
Predict: what happens if a computer with an amd64 CPU asks for this image? Amira asks for it as an amd64 computer would:
docker pull --platform linux/amd64 127.0.0.1:5000/ticket-api:1.1.0-arm64The output (simulated; she pushed the same arm64 image with the tag 1.1.0-arm64 first):
Error response from daemon: no matching manifest for linux/amd64 in the manifest list entries: no match for platform in manifest: not foundDocker says it clearly. Azure does not, as you see in Operational configuration. So Amira builds for the cloud with --platform:
docker buildx build --platform linux/amd64 -t 127.0.0.1:5000/ticket-api:1.1.0 --push .The output (simulated, the end):
#12 naming to 127.0.0.1:5000/ticket-api:1.1.0 done#12 pushing layers 0.0s done#12 pushing manifest for 127.0.0.1:5000/ticket-api:1.1.0@sha256:204c4f72f635011840ac1cb898cbd2de5e1aa6c189905078971cfe8283f002f6 0.1s done#12 DONE 0.2sThe amd64 layers were in the build cache from an earlier build, so this took less than a second. Without the cache, the same build took 23 s, and RUN pip install took 19.7 s instead of 11.8 s. An Apple silicon Mac runs amd64 programs with emulation: a program that translates the other CPU’s instructions. --push sends the result to the registry at once. Now imagetools inspect says Platform: linux/amd64.
Look at the digest: it is not 1ba724… any more. The same tag, 1.1.0, now points to different content. Remember this for the common mistake at the end of the lesson.
The live route: create the deployment
Section titled “The live route: create the deployment”Text description of the diagram
The numbers are the order of the steps below. The resource group holds everything, so deleting it deletes everything (with one exception, the Key Vault, which Verify and remove handles). The identity can only pull from this one registry. The environment makes a Log Analytics workspace that you did not ask for, and it can charge for log data.
Amira follows the design from Module 4. She puts the names in shell variables first, so that each command is shorter and she cannot mistype a name. Choose your own registry name: it must be unique in all of Azure, 5 to 50 letters and numbers, with no hyphens. Add your own digits to ticketapi.
RG=rg-ticket-api-practiceLOCATION=canadacentralACR=ticketapi4821$RG = "rg-ticket-api-practice"$LOCATION = "canadacentral"$ACR = "ticketapi4821"The variables live only in this terminal window. If you open a new one, set them again. The commands below use $RG, $ACR and the others, which works the same way in both shells. Where a command differs, there are tabs.
Before step 1: sign in and prepare the subscription
Section titled “Before step 1: sign in and prepare the subscription”az loginaz extension add --name containerapp --upgradeaz provider register --namespace Microsoft.Appaz provider register --namespace Microsoft.OperationalInsightsaz provider register --namespace Microsoft.ContainerRegistryaz login opens the browser for your Azure sign-in. The extension adds the az containerapp commands. A resource provider is the part of Azure that makes one kind of resource. A new subscription must register each provider once. It can take a few minutes. Check it with az provider show -n Microsoft.App --query registrationState -o tsv: the answer must be Registered. In the test subscription, all three were registered already.
The extension prints WARNING: The behavior of this command has been altered by the following extension: containerapp on every az containerapp command. It is harmless. The outputs below leave it out.
Step 1: the resource group, with tags
Section titled “Step 1: the resource group, with tags”az group create --name $RG --location $LOCATION --tags purpose=practice course=C18 -o tableThe output (live):
Location Name------------- ----------------------canadacentral rg-ticket-api-practiceThe tags say why the group exists. They help a person who reads the subscription’s list later. They do not help a search for its resources, as Verify and remove shows.
Step 2: the registry
Section titled “Step 2: the registry”az acr create --resource-group $RG --name $ACR --sku Basic -o tableThe output (live):
NAME RESOURCE GROUP LOCATION SKU LOGIN SERVER CREATION DATE ADMIN ENABLED------------- ---------------------- ------------- ----- ------------------------ -------------------- ---------------ticketapi4821 rg-ticket-api-practice canadacentral Basic ticketapi4821.azurecr.io 2026-10-07T16:10:57Z FalseLOGIN SERVER is the registry part of the image name. ADMIN ENABLED False: the registry’s admin user, a shared password, is off. Keep it off. The app pulls with its identity, so it needs no password.
Step 3: build for amd64 and push
Section titled “Step 3: build for amd64 and push”az acr login --name $ACRdocker buildx build --platform linux/amd64 -t $ACR.azurecr.io/ticket-api:1.1.0 --push .Run the build in the project folder: the . at the end is the build context. The output (live, shortened):
Login Succeeded...#13 exporting to image#13 pushing layers 11.8s done#13 pushing manifest for ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:cfd04194eb1be66f49a40575f75a0b2105a74e172f953df26a355291a5191afd 1.0s done#13 DONE 14.7saz acr login gives Docker a token for this registry. The token expires after a few hours: if a later push says unauthorized, run az acr login again. The whole build and push took 27 s. Check the tag and the platform:
az acr repository show-tags -n $ACR --repository ticket-api -o tabledocker buildx imagetools inspect $ACR.azurecr.io/ticket-api:1.1.0The output (live, shortened):
Result--------1.1.0
Name: ticketapi4821.azurecr.io/ticket-api:1.1.0MediaType: application/vnd.oci.image.index.v1+jsonDigest: sha256:cfd04194eb1be66f49a40575f75a0b2105a74e172f953df26a355291a5191afd
Manifests: Name: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:b08764e2... Platform: linux/amd64
Name: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:eaa1e2c6... Platform: unknown/unknownlinux/amd64: the cloud can run it.
Step 4: the identity and its one role
Section titled “Step 4: the identity and its one role”az identity create --resource-group $RG --name id-ticket-api -o tableIDENTITY_ID=$(az identity show -g $RG -n id-ticket-api --query id -o tsv)PRINCIPAL_ID=$(az identity show -g $RG -n id-ticket-api --query principalId -o tsv)REGISTRY_ID=$(az acr show -n $ACR --query id -o tsv)az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal --role AcrPull --scope $REGISTRY_ID -o tableaz identity create --resource-group $RG --name id-ticket-api -o table$IDENTITY_ID = az identity show -g $RG -n id-ticket-api --query id -o tsv$PRINCIPAL_ID = az identity show -g $RG -n id-ticket-api --query principalId -o tsv$REGISTRY_ID = az acr show -n $ACR --query id -o tsvaz role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal --role AcrPull --scope $REGISTRY_ID -o tableThe output (live, columns shortened):
ClientId Location Name PrincipalId ResourceGroup-------------- ------------- ------------- -------------- ----------------------faf6b35b-... canadacentral id-ticket-api d2066809-... rg-ticket-api-practice
CreatedOn PrincipalType Scope-------------------------------- ---------------- ---------------------------------------------------------------------------------------2026-10-07T16:12:09.352851+00:00 ServicePrincipal /subscriptions/.../resourceGroups/rg-ticket-api-practice/providers/Microsoft.ContainerRegistry/registries/ticketapi4821The scope is the registry, not the group or the subscription. The identity can pull images from this one registry, and do nothing else: least privilege, as in Module 4. --assignee-principal-type ServicePrincipal avoids an error when the new identity is not yet known to the role service.
Step 5: the Container Apps environment
Section titled “Step 5: the Container Apps environment”az containerapp env create --resource-group $RG --name cae-ticket-api --location $LOCATION -o tableThe output (live, shortened):
WARNING: No Log Analytics workspace provided.WARNING: Generating a Log Analytics workspace with name "workspace-rgticketapipracticeXXXX"...Container Apps environment created. To deploy a container app, use: az containerapp create --help
Location Name ResourceGroup-------------- -------------- ----------------------Canada Central cae-ticket-api rg-ticket-api-practiceThe environment is the shared space where container apps run: one network and one place for logs. It took about 2 to 3 minutes. Read the two warnings: Azure made a Log Analytics workspace for the logs. You did not ask for it, and it can charge for log data. Your random characters differ from XXXX. Add it to your inventory now:
az resource list -g $RG -o tableThe output (live):
Name ResourceGroup Location Type Status--------------------------------- ---------------------- ------------- ------------------------------------------------ ---------ticketapi4821 rg-ticket-api-practice canadacentral Microsoft.ContainerRegistry/registries Succeededid-ticket-api rg-ticket-api-practice canadacentral Microsoft.ManagedIdentity/userAssignedIdentities Succeededworkspace-rgticketapipracticeXXXX rg-ticket-api-practice canadacentral Microsoft.OperationalInsights/workspaces Succeededcae-ticket-api rg-ticket-api-practice canadacentral Microsoft.App/managedEnvironments SucceededFour resources, and you asked for three of them. The role assignment from step 4 is not in the list: az resource list does not show role assignments.
Step 6: create the container app
Section titled “Step 6: create the container app”KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(24))")az containerapp create --resource-group $RG --name ticket-api --environment cae-ticket-api \ --image $ACR.azurecr.io/ticket-api:1.1.0 \ --user-assigned $IDENTITY_ID --registry-server $ACR.azurecr.io --registry-identity $IDENTITY_ID \ --ingress external --target-port 8000 \ --cpu 0.25 --memory 0.5Gi --min-replicas 0 --max-replicas 2 \ --secrets api-key="$KEY" \ --env-vars API_KEY=secretref:api-key REQUIRE_API_KEY=true SHOW_DOCS=false$KEY = python -c "import secrets; print(secrets.token_urlsafe(24))"az containerapp create --resource-group $RG --name ticket-api --environment cae-ticket-api ` --image "$ACR.azurecr.io/ticket-api:1.1.0" ` --user-assigned $IDENTITY_ID --registry-server "$ACR.azurecr.io" --registry-identity $IDENTITY_ID ` --ingress external --target-port 8000 ` --cpu 0.25 --memory 0.5Gi --min-replicas 0 --max-replicas 2 ` --secrets "api-key=$KEY" ` --env-vars API_KEY=secretref:api-key REQUIRE_API_KEY=true SHOW_DOCS=falseThe shell history keeps $KEY, the name of the variable, not the key. The flags, one by one:
| Flag | What it does |
|---|---|
--environment cae-ticket-api |
Runs the app in the environment from step 5. |
--image …/ticket-api:1.1.0 |
The exact version to run. |
--user-assigned $IDENTITY_ID |
Gives the app the identity from step 4. |
--registry-server, --registry-identity |
Pulls from the registry as that identity: no password. |
--ingress external --target-port 8000 |
Gives the app a public HTTPS address, and sends requests to port 8000 in the container. |
--cpu 0.25 --memory 0.5Gi |
The size of each replica. The smallest size. |
--min-replicas 0 --max-replicas 2 |
No replicas when nobody calls; at most two. |
--secrets api-key="$KEY" |
Stores the key as the app’s secret api-key. |
--env-vars API_KEY=secretref:api-key … |
Sets API_KEY from the secret, and two plain settings. |
The output (live):
WARNING: User identity /subscriptions/.../userassignedidentities/id-ticket-api is already assigned to containerappContainer app created. Access your app at https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.io/23 s. The warning is harmless: --user-assigned and --registry-identity name the same identity. Your address has a different middle part. Check the state:
az containerapp show -g $RG -n ticket-api --query "{rev:properties.latestRevisionName, status:properties.runningStatus, prov:properties.provisioningState}" -o tableThe output (live):
Rev Status Prov------------------- -------- ---------ticket-api--nz14cir Running SucceededThe first revision is ticket-api--nz14cir. Succeeded means that Azure accepted the settings. It does not prove that the API answers: that is the next two lessons.
The simulated route: the same steps on your computer
Section titled “The simulated route: the same steps on your computer”The simulated route keeps the ideas and leaves out the account. The table maps each live part to its local version:
| Live (Azure) | Simulated (your computer) |
|---|---|
Registry ticketapi4821.azurecr.io |
The registry container on 127.0.0.1:5000 |
az acr login |
Not needed: only your computer can reach this registry |
The image for linux/amd64 |
The same build, pushed to the local registry |
Container app ticket-api |
The service api in deploy/local-cloud.yaml |
The secret api-key, secretref: |
A Compose secret from secrets/api_key.txt, read with API_KEY_FILE |
--cpu 0.25 --memory 0.5Gi |
cpus: 0.25 and mem_limit: 512m |
| HTTPS address, external ingress | http://127.0.0.1:8080: no HTTPS |
| Revisions, scaling, the registry pull | Not simulated |
The simulation runs the image that you built for your own computer, ticket-api:1.1.0. It cannot run the amd64 image quickly on Apple silicon: emulation works, but it is slow. deploy/local-cloud.yaml is in the project:
name: ticket-api-cloud-sim
services: api: image: ticket-api:1.1.0 ports: - "127.0.0.1:8080:8000" environment: API_KEY_FILE: /run/secrets/api_key REQUIRE_API_KEY: "true" SHOW_DOCS: "false" secrets: - api_key cpus: 0.25 mem_limit: 512m restart: on-failure healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)"] interval: 10s timeout: 3s retries: 3 start_period: 5s
secrets: api_key: file: ../secrets/api_key.txtThe secret’s path is ../secrets/api_key.txt, because Compose reads paths from the folder of the Compose file, deploy/. Operational configuration explains the health check and the restart policy. Start it from the project folder:
docker compose -f deploy/local-cloud.yaml up -ddocker compose -f deploy/local-cloud.yaml psThe output (simulated):
Network ticket-api-cloud-sim_default Creating Network ticket-api-cloud-sim_default Created Container ticket-api-cloud-sim-api-1 Creating Container ticket-api-cloud-sim-api-1 Created Container ticket-api-cloud-sim-api-1 Starting Container ticket-api-cloud-sim-api-1 StartedNAME IMAGE COMMAND SERVICE CREATED STATUS PORTSticket-api-cloud-sim-api-1 ticket-api:1.1.0 "fastapi run --host …" api 13 seconds ago Up 12 seconds (healthy) 127.0.0.1:8080->8000/tcp-f names the Compose file, because it is not compose.yaml. The name ticket-api-cloud-sim keeps it apart from the database project from Module 3, so both can exist together. The status changes from health: starting to healthy after the first health check, about 10 s after the start.
Guided practice: push a version and deploy it
Section titled “Guided practice: push a version and deploy it”Use your route. Work in the project folder.
- Write in
docs/cloud-design.mdwhich route you use. - Simulated route: start the local registry with the
docker run … registry:3.1.2command from Registry, repository and tag. Live route: sign in, then do steps 1 and 2 of the live route. - Build for
linux/amd64with--push, to your registry, with the tag1.1.0. - Check the platform with
docker buildx imagetools inspect. Expected:Platform: linux/amd64, and oneunknown/unknownentry. - Check the tag list. Simulated:
curl -s http://127.0.0.1:5000/v2/ticket-api/tags/listshows"tags":["1.1.0"]. Live:az acr repository show-tagsshows1.1.0. - Simulated route: start
deploy/local-cloud.yaml, and wait for(healthy). Live route: do steps 4 to 6, and wait forRunningandSucceeded. - Write down the image name with its digest, and (live) the address and the first revision’s name. You need them in the next two lessons.
Show the expected result
Simulated: docker compose -f deploy/local-cloud.yaml ps shows ticket-api-cloud-sim-api-1 Up … (healthy) on 127.0.0.1:8080->8000/tcp, and the local registry has ticket-api with the tag 1.1.0 for linux/amd64.
Live: az resource list -g rg-ticket-api-practice -o table lists five resources: the registry, the identity, the workspace, the environment and the container app. az containerapp show says Running and Succeeded. Your notes have something like this:
Image: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:cfd04194eb1b...Address: https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.ioRevision: ticket-api--nz14cirYour turn: the build without --platform
Section titled “Your turn: the build without --platform”Build the image again, but leave out --platform, and push it with the tag 1.1.0-native:
docker buildx build -t 127.0.0.1:5000/ticket-api:1.1.0-native --push .Before you run imagetools inspect on it, predict the platform. Then answer: on which computers can this tag run, and could Azure Container Apps run it?
Show the answer
Without --platform, Buildx builds for the computer that runs the build. On Apple silicon, imagetools inspect shows Platform: linux/arm64. On an Intel or AMD computer, it shows linux/amd64. An arm64-only image runs on arm64 computers, and an amd64 computer cannot pull it: docker pull --platform linux/amd64 gives no matching manifest for linux/amd64. Azure Container Apps runs only amd64, so it could not run this tag on a Mac with Apple silicon. Always write --platform linux/amd64 for a cloud build, even on a computer where it is the default. Then the command does the same thing on every computer.
Common mistake
The same tag, different content
Symptom: Amira pushed 127.0.0.1:5000/ticket-api:1.1.0 twice: first the arm64 build, then the amd64 build. The tag list still shows only "tags":["1.1.0"], and nothing warned her. But the digest changed from sha256:1ba724a2… to sha256:204c4f72…. A deployment that says 1.1.0 now runs different content from yesterday’s deployment with the same name.
Cause: a tag is a label that points to a digest. A push with an existing tag moves the label. Most registries allow it by default, Azure Container Registry too.
Fix:
- Give every change a new version:
1.1.1for a fix,1.2.0for a new feature. Never push a different build under a version that was deployed. - Record the digest with the tag in
DEPLOY.md. The digest proves what ran. - For the strictest pin, deploy by digest:
ticketapi4821.azurecr.io/ticket-api@sha256:cfd04194…. Nobody can move a digest.
For a real AI service: an image often carries a trained model. If someone moves the tag 2.0.0 to a new model, the service’s predictions change, and the deployment record still says 2.0.0. Nobody can then explain why the results changed. A version must mean one model and one piece of code.
Check your understanding
Name the three parts of ticketapi4821.azurecr.io/ticket-api:1.1.0, and say which part a push can change without any warning.
Show the answer
ticketapi4821.azurecr.io is the registry, the server that stores the images. ticket-api is the repository, the versions of one image together. 1.1.0 is the tag, one version. A push with the same name moves the tag to new content without a warning. Only the digest (sha256:…) always means the same content. That is why each change gets a new version number, and why DEPLOY.md records the digest too.
Does your answer have the main points of ours?
Sign in and enroll in the course to save your answers. Every check counts toward the certificate.
Check your understanding
Predict: on an Apple silicon Mac, you run docker build -t ticket-api:1.1.0 . and push it to the Azure registry. Will Azure Container Apps run it? What do you change?
Show the answer
No. A plain build on Apple silicon makes a linux/arm64 image, and Azure Container Apps runs only linux/amd64. Build with docker buildx build --platform linux/amd64 -t ticketapi4821.azurecr.io/ticket-api:1.1.0 --push ., then check with docker buildx imagetools inspect that the platform is linux/amd64 before you deploy.
Does your answer have the main points of ours?
Sign in and enroll in the course to save your answers. Every check counts toward the certificate.
Check your understanding
The container app needs images from the registry. Why does the course give it an identity with AcrPull on the registry, and not the registry's admin user?
Show the answer
The admin user is one shared password with full rights on the registry. Anyone who sees it can push and delete images, and it must be stored and changed by hand. The identity needs no password: Azure gives the app its tokens. Its role, AcrPull, lets it only pull, and its scope is this one registry. If the app is misused, the attacker cannot push a changed image or reach anything else. That is least privilege.
Does your answer have the main points of ours?
Sign in and enroll in the course to save your answers. Every check counts toward the certificate.
Recap
- A registry stores images. A full name is
<registry>/<repository>:<tag>. A tag can move; a digest cannot. - Give every change a new version, and never deploy only
latest. - Build for the cloud with
--platform linux/amd64, and check withdocker buildx imagetools inspectbefore you deploy. - Live: a tagged resource group, a registry (with the admin user off), an environment (which makes a Log Analytics workspace), an identity with
AcrPullon the registry, and the container app with a new key as its secret. - Simulated: a local registry on
127.0.0.1:5000, anddeploy/local-cloud.yamlwith the same settings and limits.
The app is running, but the platform knows only that something listens on port 8000. The next lesson tells it how to check the app and how large it may grow. It also says what must happen when a new version cannot start.