Skip to content
Get Started for Free

Container Registry

Azure Container Registry (ACR) is a managed, private OCI-compatible registry for storing container images and Helm charts. It integrates natively with Azure Kubernetes Service, Azure Container Instances, and Azure App Service to streamline container-based application deployments. ACR is commonly used to build, store, and manage container images as part of a continuous integration and deployment pipeline. For more information, see What is Azure Container Registry?.

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Container Registry. Each registry is backed by its own local OCI registry, and its login server serves the Azure Container Registry token protocol, so Docker and the Azure CLI push, pull, and sign in as they do with Azure. The supported APIs are available on our API Coverage section, which provides information on the extent of Container Registry’s integration with LocalStack.

This guide walks you through creating a registry, logging in with Docker, pushing, pulling, and importing images, and listing repositories.

Launch LocalStack using your preferred method. For more information, see Introduction to LocalStack for Azure. Once the container is running, enable Azure CLI interception by running:

Terminal window
lstk az start-interception

This command points the az CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API. To revert this configuration, run:

Terminal window
lstk az stop-interception

This reconfigures the az CLI to send commands to the official Azure management REST API.

Create a resource group to hold all resources created in this guide:

Terminal window
az group create --name rg-acr-demo --location westeurope
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-acr-demo",
"location": "westeurope",
"name": "rg-acr-demo",
"properties": { "provisioningState": "Succeeded" },
"type": "Microsoft.Resources/resourceGroups"
}

Create a Basic-tier Azure Container Registry (Azure also offers Standard and Premium; limits differ by tier, as described in Azure Container Registry SKU features and limits):

Terminal window
az acr create \
--name myacrdemo \
--resource-group rg-acr-demo \
--sku Basic \
--admin-enabled true
Output
{
"adminUserEnabled": true,
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-acr-demo/providers/Microsoft.ContainerRegistry/registries/myacrdemo",
"location": "westeurope",
"loginServer": "myacrdemo.azurecr.azure.localhost.localstack.cloud:4566",
"name": "myacrdemo",
"provisioningState": "Succeeded",
"resourceGroup": "rg-acr-demo",
"sku": { "name": "Basic", "tier": "Basic" },
"type": "Microsoft.ContainerRegistry/registries"
...
}

Authenticate the local Docker daemon to the registry using the Azure CLI:

Terminal window
az acr login --name myacrdemo
Output
Login Succeeded

With Azure, az acr login is the documented way to authenticate Docker to your registry using your signed-in Microsoft Entra identity (Push your first image to your Azure container registry using the Docker CLI; for other auth options see Authenticate with an Azure container registry). LocalStack serves the same token exchange, so az acr login signs Docker in with your Microsoft Entra identity whether or not the admin user is enabled.

Create a minimal Dockerfile for the demo image:

Terminal window
cat > Dockerfile <<'EOF'
FROM alpine:latest
CMD ["echo", "Hello from LocalStack ACR!"]
EOF

Capture the registry login server returned by the emulator, then build and push the image using that address:

Terminal window
LOGIN_SERVER=$(az acr show --name myacrdemo --resource-group rg-acr-demo --query loginServer -o tsv)
docker build -t $LOGIN_SERVER/hello:v1 .
docker push $LOGIN_SERVER/hello:v1

Alternatively build directly within the emulated registry:

Terminal window
az acr build \
--image hello:v1 \
--registry myacrdemo \
.

Pull the image back from the registry to confirm it was pushed correctly:

Terminal window
docker pull $LOGIN_SERVER/hello:v1

List all image repositories stored in the registry:

Terminal window
az acr repository list --name myacrdemo
Output
[
"hello"
]

Import an image from Microsoft Container Registry without pulling it locally (see Import container images to a container registry):

Terminal window
az acr import \
--name myacrdemo \
--resource-group rg-acr-demo \
--source mcr.microsoft.com/hello-world:latest \
--image hello-world:latest

List the tags of the imported repository:

Terminal window
az acr repository show-tags --name myacrdemo --repository hello-world
Output
[
"latest"
]

Check registry name availability against the management API. The following example assumes you already created myacrdemo above, so the response matches a name that is not available:

Terminal window
az acr check-name --name myacrdemo
Output
{
"message": "The registry myacrdemo is already in use.",
"nameAvailable": false,
"reason": "AlreadyExists"
}

Disable the registry admin account (az acr update is the same command Azure documents for changing registry settings; see az acr update):

Terminal window
az acr update --name myacrdemo --resource-group rg-acr-demo --admin-enabled false
Output
{
"adminUserEnabled": false,
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-acr-demo/providers/Microsoft.ContainerRegistry/registries/myacrdemo",
"loginServer": "myacrdemo.azurecr.azure.localhost.localstack.cloud:4566",
"name": "myacrdemo",
"provisioningState": "Succeeded",
"resourceGroup": "rg-acr-demo",
"sku": { "name": "Basic", "tier": "Basic" },
"type": "Microsoft.ContainerRegistry/registries"
...
}

Show current storage usage statistics for the registry:

Terminal window
az acr show-usage --name myacrdemo --resource-group rg-acr-demo
Output
{
"value": [
{
"currentValue": 3871673,
"limit": 10737418240,
"name": "Size",
"unit": "Bytes"
},
{
"currentValue": 3871673,
"limit": 43980465111040,
"name": "MaximumStorageCapacity",
"unit": "Bytes"
},
{
"currentValue": 0,
"limit": 2,
"name": "Webhooks",
"unit": "Count"
},
{
"currentValue": 0,
"limit": 100,
"name": "ScopeMaps",
"unit": "Count"
},
{
"currentValue": 0,
"limit": 100,
"name": "Tokens",
"unit": "Count"
}
]
}

The limits are those of the registry’s tier, as listed in Azure Container Registry SKU features and limits.

Delete the registry and remove the demo Dockerfile created earlier:

Terminal window
az acr delete --name myacrdemo --resource-group rg-acr-demo --yes
rm -f Dockerfile

Deleting a registry also deletes its images, so a registry you create again with the same name starts empty. Verify that the resource group no longer contains a registry:

Terminal window
az acr list --resource-group rg-acr-demo
Output
[]
  • Registry lifecycle: Create, show, list, update, and delete registries using the Azure CLI or the ARM API. Deleting a registry deletes its images, so a registry created again under the same name starts empty.
  • Token authentication: The login server implements the Azure Container Registry token protocol, so az acr login signs Docker in with your Microsoft Entra identity whether or not the admin user is enabled, and the azure-containerregistry SDK signs in with a Microsoft Entra credential. Docker and containerd can also sign in with the admin user or a token, and credentials Azure refuses, such as a wrong password or the password of a disabled admin user, are refused.
  • Admin user management: Enable or disable the admin user, and show or regenerate its passwords. As on Azure, the passwords cannot be shown or regenerated while the admin user is disabled.
  • Scope maps and tokens: A token grants only the actions of its scope map, either one you create or one of the system-defined scope maps every registry has, such as _repositories_pull. A disabled token grants nothing.
  • Image push and pull: Push and pull images with the Docker CLI. Each registry is backed by a local OCI registry, so an image keeps its manifest and digest.
  • Repository metadata: List and show repositories, tags, and manifests with az acr repository list, az acr repository show, az acr repository show-tags, and az acr manifest list-metadata, including paging and ordering.
  • Image import: Import images with az acr import from another registry in LocalStack or from a public registry such as Docker Hub or Microsoft Container Registry. The registry stores the source’s own manifests and layers, so an imported image keeps its digest.
  • Builds and tasks: az acr build builds the image with your local Docker daemon and pushes it to the registry, and a failed build fails the command. Tasks created with az acr task create run with az acr task run, and runs can be shown, listed, archived, and canceled.
  • Webhooks: Webhooks deliver ping, push, and delete events to their service URI with the payload and headers Azure sends, and az acr webhook list-events lists each delivery with the endpoint’s response.
  • Name availability check: Check whether a registry name is available with az acr check-name. As on Azure, a registry name is unique across subscriptions and resource groups.
  • Registry settings: Network rules, public network access, the data endpoint, policies, encryption, identities, and tags are stored and returned as Azure returns them. A system-assigned identity is a real principal that you can assign roles to.
  • Service tiers: Basic, Standard, and Premium registries report their tier’s limits with az acr show-usage. As on Azure, a registry below Premium refuses network rules that restrict access, the data endpoint, and an enabled retention policy, and a Basic registry refuses anonymous pull. A move to a lower tier is refused while the registry keeps what that tier cannot have, such as IP rules or an enabled retention policy on a move from Premium, or anonymous pull on a move to Basic.
  • RBAC enforcement is opt-in: By default, data-plane operations succeed regardless of role assignments. Set LS_AZURE_ENFORCE_RBAC to require a Microsoft Entra caller to hold a role such as AcrPull, AcrPush, or AcrDelete, or a Container Registry Repository role on a registry that uses ABAC; the admin user and tokens keep the access their own credentials grant. The conditions of ABAC role assignments are not evaluated, so a role assigned for one repository applies to the whole registry. See Role Assignment: Enabling RBAC enforcement.
  • Requests without credentials are allowed: A pull or push without credentials is treated as coming from LocalStack’s default principal, which holds every permission, so Container Apps, Container Instances, and App Service can pull images without credentials. Azure refuses such a request unless the registry allows anonymous pull, and then only for pulls. Under RBAC enforcement, a pull from an AKS node counts as the cluster’s kubelet identity, as on Azure.
  • Access and refresh tokens are not verified: LocalStack does not check the signature or expiry of the access and refresh tokens its login server issues, and the Microsoft Entra token that az acr login exchanges only needs claims that can be read.
  • Network settings are not enforced: Network rules, public network access, and private endpoint connections are stored and returned but do not restrict access to the registry. The data endpoint host names are returned but not served, since the login server serves all data.
  • Customer-managed keys are not applied: A customer-managed encryption key is stored and returned but not applied, and it is accepted on any tier, whereas Azure requires Premium.
  • Tier limits are not enforced: The webhook, token, and scope map counts that az acr show-usage reports are not enforced, and a private endpoint to a Basic or Standard registry is connected, whereas Azure requires Premium.
  • Registry policies are not enforced: Quarantine, retention, and export policies are stored and returned but have no effect: new images are never quarantined, and untagged manifests are never purged.
  • Preview registry properties: Properties that the Azure CLI reads from a preview API version, such as metadata search, regional endpoints, the endpoint protocol, and the domain name label scope, are not supported, so az acr commands show them as null. The soft-delete policy shows as null until a request sets one, and then has no effect.
  • Geo-replication: Replications can be created on a Premium registry, but each registry has a single local backend, so images are not replicated.
  • Task steps are not run: Task files and encoded tasks (az acr run -f, az acr run --cmd, and tasks defined with them) are validated and reported successful without running their steps. Task triggers (source commits, base image updates, and timers) are stored but never start a run, and a task’s source must be uploaded with az acr task run --context <local folder>, since LocalStack does not fetch sources such as Git repositories.
  • Webhook targets: A webhook can call any host, including one on your machine (host.docker.internal from inside the LocalStack container), whereas Azure requires a public address. Helm chart and quarantine events are never delivered.
  • Repository changes: Changing the attributes of repositories, tags, and manifests, and deleting a repository or a tag, are not supported yet, so az acr repository update, az acr repository untag, and az acr repository delete --repository fail. Deleting an image with az acr repository delete --image works.

The following samples demonstrate how to use Azure Container Registry with LocalStack for Azure:

Every sample in the AKS samples also pushes its image to a registry with az acr login and runs it on AKS.

79 of 79 operations implemented

Operation ▲Implemented ▼
Page 1 of 0
Was this page helpful?