Why a registry comes first
Before you start: this course is independent of Microsoft. The official AI-200 study guide belongs to Microsoft and you can read it free on Microsoft Learn, so we don't reproduce it here. You need 700 to pass, and no course can promise you a pass. Practice questions in this course are original and are not real exam questions.
The skill area here is Implement container application hosting. Every hosting service in this exam (App Service, Azure Container Apps, AKS) starts by pulling an image from somewhere. When you run docker build on your laptop, the image sits in your local Docker image cache. Azure can't see that cache. A Container App that refers to myapp:v1 has no idea your laptop exists. It goes over the network to a registry and asks for the image there.
Azure Container Registry (ACR) is Azure's private registry. A useful comparison is a private PyPI for container images. You push to it once, and any service with the right permissions can pull from it.
Step 1: Pick a tier and create the registry
ACR has three service tiers (SKUs):
| Tier | Use it for | Notes |
|---|---|---|
| Basic | Learning, low-volume dev | Same APIs as the others (Microsoft Entra auth, webhooks, image deletion), with less included storage and throughput |
| Standard | Most production workloads | More storage and throughput |
| Premium | High volume, enterprise needs | Adds geo-replication, private link with private endpoints, and the most storage and concurrency |
When an exam scenario mentions geo-replication or private endpoints, the answer is Premium.
az group create --name rg-ai200 --location eastus
# Registry name: unique across Azure, 5-50 lowercase alphanumeric chars (no dashes)
az acr create \
--resource-group rg-ai200 \
--name ai200demoacr \
--sku Standard
Part of the output:
{
"adminUserEnabled": false,
"loginServer": "ai200demoacr.azurecr.io",
"sku": { "name": "Standard", "tier": "Standard" }
}
Gotcha: the login server is the name you tag with. It's usually
<registry>.azurecr.io. If you create the registry with the optional--dnl-scopeflag (Domain Name Label protection against subdomain takeover), every scope exceptUnsecureadds a hash, for exampleai200demoacr-e7ggejfuhzhgedc8.azurecr.io. Don't guess the name. Read it from the registry:az acr show -n ai200demoacr --query loginServer -o tsv.
Step 2: Build a Dockerized Python app
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
docker build -t rag-api:v1 . # local name only, Azure can't see it yet
Step 3: Log in, tag, push
az login # your Microsoft Entra identity
az acr login --name ai200demoacr # registry RESOURCE name, not the FQDN
# -> Login Succeeded
# Retag with the full name: <login-server>/<repository>:<tag>
docker tag rag-api:v1 ai200demoacr.azurecr.io/rag-api:v1
docker push ai200demoacr.azurecr.io/rag-api:v1
The push creates the rag-api repository and stores the v1 tag in it. Check with:
az acr repository list --name ai200demoacr -o table
az acr repository show-tags --name ai200demoacr --repository rag-api -o table
You can do the same check from Python with the azure-containerregistry SDK:
from azure.containerregistry import ContainerRegistryClient
from azure.identity import DefaultAzureCredential
client = ContainerRegistryClient(
"https://ai200demoacr.azurecr.io",
DefaultAzureCredential(),
audience="https://management.azure.com",
)
for repo in client.list_repository_names():
print(repo) # rag-api
Gotchas.
az acr loginwrites a Microsoft Entra token into your Docker config, and that token lasts 3 hours. If a push fails in the afternoon withunauthorized, runaz acr loginagain. The command also needs the Docker daemon running. In environments without it,az acr login --expose-tokengives you a token to pass todocker login.
Step 4: Choose how things authenticate
You logged in as yourself, which is right for interactive work on your own machine. Everything else needs a different identity:
- Admin user: one shared username with two passwords. It's disabled by default and always has full push and pull rights. It doesn't support RBAC, and every caller shows up as the same user. Use it only for quick tests or the few portal deployment cases that need it (
az acr update -n ai200demoacr --admin-enabled true). - Service principal: a Microsoft Entra app identity for headless use, such as a CI/CD pipeline outside Azure or a non-Azure cluster. It supports RBAC, but you have to store and rotate its secret yourself (the password expires after 1 year by default).
- Managed identity: an identity that Azure manages for an Azure resource. There's no secret to leak or rotate, and it supports RBAC. Container Apps, App Service, Azure Functions, and the AKS kubelet identity can all use one to pull.
The usual production setup gives the hosting service a managed identity with the AcrPull role, scoped to the registry. AcrPull lets it pull and nothing more. Push rights (AcrPush) go to the build pipeline.
ACR_ID=$(az acr show -n ai200demoacr --query id -o tsv)
az role assignment create \
--assignee <principal-id-of-the-app-identity> \
--role AcrPull \
--scope $ACR_ID
Newer option. A registry can use the role assignment mode "RBAC Registry + ABAC Repository Permissions" (
--role-assignment-mode rbac-abac). In that mode the pull role is Container Registry Repository Reader instead of AcrPull, and you can limit it to particular repositories. The idea is the same: give least privilege to a managed identity.
The exam angle: what it asks about this
- Naming: read code and spot the correct
<loginserver>/<repo>:<tag>(wrong: a missing login server, or the registry name in place of the FQDN). - Authentication choice: "an Azure-hosted app must pull without storing credentials" points to a managed identity plus AcrPull. "Single developer quick test" points to the admin user. "Pipeline outside Azure" points to a service principal.
- Tier: geo-replication or private endpoints mean Premium.
- Order: create the registry, log in, tag, push, then deploy. If a deployment says the image wasn't found, the image was probably never pushed, or the tag doesn't match.
Key takeaways
- Hosting services pull over the network, so the image has to be in ACR before App Service, Container Apps or AKS can run it.
- Create the registry with
az acr create --sku Basic|Standard|Premium. Premium is the only tier with geo-replication and private endpoints. - Tag with the full login server:
ai200demoacr.azurecr.io/rag-api:v1. Read the login server from the registry, because DNL can add a hash. az acr login --name <registry>uses your Entra identity, and the token lasts 3 hours.- The admin user is disabled by default, shared, and has full access. Keep it for tests.
- For production pulls, give the hosting service a managed identity with AcrPull, and give the pipeline AcrPush.