Files
awesome-copilot/skills/azure-container-registry-cli/references/images-and-artifacts.md
T
github-actions[bot] 8df98cb45e chore: publish from main
2026-07-30 01:53:16 +00:00

6.4 KiB

Images & Artifacts

Table of Contents


Import Images (Server-Side Copy)

Preferred over docker pull + docker push — no local storage, keeps multi-arch manifests intact:

# From a public registry
az acr import --name {registry} --source mcr.microsoft.com/hello-world:latest
az acr import --name {registry} --source docker.io/library/nginx:1.27 --image nginx:1.27

# From another ACR in the same tenant (by resource ID, no credentials needed)
az acr import --name {registry} \
  --source app:v1 \
  --registry /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ContainerRegistry/registries/{src-registry}

# From a private registry with credentials
az acr import --name {registry} --source private.example.com/app:v1 \
  --username {user} --password {password}

# Overwrite an existing tag
az acr import --name {registry} --source docker.io/library/nginx:1.27 --image nginx:1.27 --force

Repositories & Tags

az acr repository list --name {registry} --output table

# Tags, newest first, with digest and timestamps
az acr repository show-tags --name {registry} --repository app \
  --orderby time_desc --detail --output table

az acr repository show --name {registry} --image app:v1        # tag attributes
az acr repository show --name {registry} --repository app      # repo attributes

Manifests

# Metadata for all manifests in a repo (digest, tags, size, timestamps)
az acr manifest list-metadata --registry {registry} --name app --output table

# One manifest's metadata / raw content
az acr manifest show-metadata --registry {registry} --name app:v1
az acr manifest show --registry {registry} --name app@sha256:{digest}

# Find untagged (orphaned) manifests
az acr manifest list-metadata --registry {registry} --name app \
  --query "[?tags==null].digest" --output tsv

Untag vs Delete

# Untag: removes only the tag; manifest + layers remain (still pullable by digest)
az acr repository untag --name {registry} --image app:v1

# Delete by tag: deletes the whole manifest and ALL other tags pointing to it
az acr repository delete --name {registry} --image app:v1 --yes

# Delete by digest (precise)
az acr repository delete --name {registry} --image app@sha256:{digest} --yes

# Delete an entire repository
az acr repository delete --name {registry} --repository app --yes

⚠️ Deleting by tag deletes the underlying manifest — other tags on the same image disappear too. Untag first if you only want to retire a tag name.

Purge Old Images (acr purge)

acr purge runs as an ACR Task (container mcr.microsoft.com/acr/acr-cli):

# Dry run first — ALWAYS
az acr run --registry {registry} \
  --cmd "acr purge --filter 'app:.*' --ago 30d --untagged --dry-run" /dev/null

# Delete tags older than 30 days matching the regex, plus untagged manifests
az acr run --registry {registry} \
  --cmd "acr purge --filter 'app:.*' --ago 30d --untagged" /dev/null

# Keep the 5 most recent tags regardless of age
az acr run --registry {registry} \
  --cmd "acr purge --filter 'app:.*' --ago 0d --keep 5 --untagged" /dev/null

# Schedule as a nightly task
az acr task create --registry {registry} --name purge-old-images \
  --cmd "acr purge --filter 'app:.*' --ago 30d --untagged" \
  --context /dev/null --schedule "0 3 * * *"

--filter takes repository:tag-regex and can be repeated for multiple repos.

⚠️ --untagged ignores --ago: it deletes every untagged manifest, including ones created moments ago (mid-push images, referrer artifacts). Omit --untagged if recent untagged manifests must survive — the age cutoff only applies to tagged images matched by --filter.

Lock Images

Prevent overwrite or deletion of critical tags (e.g., released versions):

# Read-only: cannot be overwritten or deleted
az acr repository update --name {registry} --image app:v1 --write-enabled false

# Undeletable but still overwritable
az acr repository update --name {registry} --image app:v1 --delete-enabled false

# Unlock
az acr repository update --name {registry} --image app:v1 --write-enabled true --delete-enabled true

Retention Policy & Soft Delete

Two distinct policies that cannot be enabled at the same time. Retention policy requires Premium; soft delete (preview) is available in all tiers but doesn't support geo-replicated or artifact-cache-enabled registries.

# Retention policy (Premium): auto-delete untagged manifests after N days (0 = immediately)
az acr config retention update --registry {registry} \
  --status enabled --days 7 --type UntaggedManifests
az acr config retention show --registry {registry}

# Soft delete (preview, all tiers): recover deleted artifacts within 1-90 days
az acr config soft-delete update --registry {registry} --status enabled --days 7
az acr repository list-deleted --name {registry}
az acr manifest restore --registry {registry} --name app:v1

Artifact Cache (Pull-Through Cache)

Cache upstream images (Docker Hub, MCR, GHCR, quay.io, ECR Public) in your registry — avoids rate limits and centralizes provenance:

# Optional: credentials for authenticated upstream (secrets live in Key Vault)
az acr credential-set create --registry {registry} --name dockerhub-creds \
  --login-server docker.io \
  --username-id https://{vault}.vault.azure.net/secrets/dh-user \
  --password-id https://{vault}.vault.azure.net/secrets/dh-pass

# Cache rule: docker.io/library/* -> {registry}.azurecr.io/dockerhub/*
az acr cache create --registry {registry} --name dockerhub-cache \
  --source-repo "docker.io/library/*" --target-repo "dockerhub/*" \
  --cred-set dockerhub-creds

az acr cache list --registry {registry} --output table

Then docker pull {registry}.azurecr.io/dockerhub/nginx:1.27 fetches through the cache.

Storage Usage

# Consumed storage vs SKU quota (Basic 10 GB / Standard 100 GB / Premium 500 GB included)
az acr show-usage --name {registry} --output table

Layers are deduplicated and shared across repositories; show-usage reports actual billable storage.