mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-13 20:59:12 +00:00
chore: publish from main
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: azure-container-registry-cli
|
||||
description: 'Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry.'
|
||||
---
|
||||
|
||||
# Azure Container Registry CLI
|
||||
|
||||
Manage Azure Container Registry (ACR) resources using the `az acr` command group of the Azure CLI.
|
||||
|
||||
**CLI:** `az acr` ships with core Azure CLI — no extension required (the `acrtransfer` extension is only needed for export/import pipelines).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
# Install Azure CLI
|
||||
brew install azure-cli # macOS
|
||||
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash # Linux
|
||||
winget install Microsoft.AzureCLI # Windows
|
||||
|
||||
# Sign in and select subscription
|
||||
az login
|
||||
az account set --subscription {subscription-id}
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Create a registry (SKU: Basic | Standard | Premium)
|
||||
az acr create --resource-group {rg} --name {registry} --sku Standard
|
||||
|
||||
# Authenticate Docker/Podman against the registry
|
||||
az acr login --name {registry}
|
||||
|
||||
# Build and push in the cloud — no local Docker needed
|
||||
az acr build --registry {registry} --image app:v1 .
|
||||
|
||||
# Copy an image from another registry without pull/push
|
||||
az acr import --name {registry} --source mcr.microsoft.com/hello-world:latest
|
||||
|
||||
# List repositories and tags
|
||||
az acr repository list --name {registry} --output table
|
||||
az acr repository show-tags --name {registry} --repository app --orderby time_desc
|
||||
|
||||
# Diagnose registry connectivity and configuration
|
||||
az acr check-health --name {registry} --yes
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Prefer `az acr build` / ACR Tasks** over local `docker build` + `docker push`: builds run in Azure, work without a local daemon, and integrate with triggers.
|
||||
- **Prefer `az acr import`** to move images between registries: it is server-side, faster, and requires no local storage.
|
||||
- **Never enable the admin user for production** — use Microsoft Entra identities (RBAC roles `AcrPull`/`AcrPush`, or `Container Registry Repository Reader`/`Writer` on ABAC-enabled registries), repository-scoped tokens, or managed identities.
|
||||
- **Premium-only features**: geo-replication, private endpoints, retention policies, connected registries, agent pools. (Repository-scoped tokens work in all tiers; zone redundancy is automatic in all tiers in supported regions.)
|
||||
|
||||
## CLI Structure
|
||||
|
||||
```
|
||||
az acr
|
||||
├── create / delete / list / show / update # Registry lifecycle
|
||||
├── login # Docker credential helper (or --expose-token)
|
||||
├── check-health / check-name / show-usage # Diagnostics & quota
|
||||
├── build # Cloud image build (quick task)
|
||||
├── run # Run a command / multi-step task once
|
||||
├── task # ACR Tasks (triggers, timers, logs, runs)
|
||||
├── agentpool # Dedicated task agent pools (Premium)
|
||||
├── import # Server-side image copy into the registry
|
||||
├── repository # List/show/delete/untag repos & tags, lock images
|
||||
├── manifest # Manifest metadata, delete, OCI referrers
|
||||
├── credential # Admin user credentials (avoid in production)
|
||||
├── token / scope-map # Repository-scoped tokens (Premium)
|
||||
├── replication # Geo-replication (Premium)
|
||||
├── network-rule # IP network rules
|
||||
├── private-endpoint-connection # Private Link approvals
|
||||
├── config # content-trust, retention, soft-delete, ...
|
||||
├── cache / credential-set # Artifact cache (pull-through cache) rules
|
||||
├── webhook # Push/delete event webhooks
|
||||
├── connected-registry # On-premises / IoT connected registries
|
||||
└── export-pipeline / import-pipeline / pipeline-run # acrtransfer extension
|
||||
```
|
||||
|
||||
## Reference Files
|
||||
|
||||
Read the relevant reference file based on the user's task. Each file contains complete command syntax and examples for its domain.
|
||||
|
||||
| File | When to read | Covers |
|
||||
|---|---|---|
|
||||
| `references/auth-and-security.md` | Login failures, permissions, CI/CD or AKS pull access | `az acr login` (incl. `--expose-token`), Entra RBAC roles, service principals, managed identities, `--attach-acr` for AKS, repository-scoped tokens & scope maps, admin user, content trust |
|
||||
| `references/build-and-tasks.md` | Building images in Azure, automation, CI triggers | `az acr build`, `az acr run`, multi-step task YAML, `az acr task` (git/base-image/timer triggers, logs, runs), agent pools |
|
||||
| `references/images-and-artifacts.md` | Managing repos, tags, cleanup, storage costs | `az acr import`, repository & manifest commands, untag vs delete, purge (`acr purge`), image locking, retention policy, soft delete, artifact cache, `show-usage` |
|
||||
| `references/networking-and-geo.md` | Multi-region, private access, edge scenarios | Geo-replication, zone redundancy, private endpoints, network rules, dedicated data endpoints, connected registries, registry transfer pipelines |
|
||||
@@ -0,0 +1,174 @@
|
||||
# Authentication & Security
|
||||
|
||||
## Table of Contents
|
||||
- [Individual Login](#individual-login)
|
||||
- [Microsoft Entra RBAC Roles](#microsoft-entra-rbac-roles)
|
||||
- [Service Principals](#service-principals)
|
||||
- [Managed Identities](#managed-identities)
|
||||
- [AKS Integration](#aks-integration)
|
||||
- [Repository-Scoped Tokens](#repository-scoped-tokens)
|
||||
- [Admin User](#admin-user)
|
||||
- [Content Trust](#content-trust)
|
||||
|
||||
---
|
||||
|
||||
## Individual Login
|
||||
|
||||
```bash
|
||||
# Standard login — wires Docker/Podman credentials via your az login identity
|
||||
az acr login --name {registry}
|
||||
|
||||
# Without a Docker daemon: get an Entra access token and pipe it to docker login
|
||||
LOGIN_SERVER=$(az acr show --name {registry} --query loginServer --output tsv)
|
||||
az acr login --name {registry} --expose-token --query accessToken --output tsv | \
|
||||
docker login $LOGIN_SERVER --username 00000000-0000-0000-0000-000000000000 --password-stdin
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `az acr login` tokens are valid for 3 hours; re-run on expiry.
|
||||
- Resolve the login server with `az acr show --name {registry} --query loginServer --output tsv` rather than hardcoding it: it is usually `{registry}.azurecr.io`, but sovereign clouds use other suffixes and registries with a domain name label scope get a hash suffix.
|
||||
|
||||
## Microsoft Entra RBAC Roles
|
||||
|
||||
The applicable data-plane roles depend on the registry's **role assignment permissions mode** — check it first:
|
||||
|
||||
```bash
|
||||
az acr show --name {registry} --query roleAssignmentMode --output tsv
|
||||
# LegacyRegistryPermissions -> use AcrPull/AcrPush/AcrDelete
|
||||
# AbacRepositoryPermissions -> use Container Registry Repository Reader/Writer/Contributor
|
||||
```
|
||||
|
||||
**Legacy mode (RBAC Registry Permissions):**
|
||||
|
||||
| Role | Permissions |
|
||||
|---|---|
|
||||
| `AcrPull` | Pull images |
|
||||
| `AcrPush` | Pull + push images |
|
||||
| `AcrDelete` | Delete images |
|
||||
| `AcrImageSigner` | Sign images (content trust) |
|
||||
| `Contributor`/`Owner` | Full control-plane management + push/pull |
|
||||
|
||||
**ABAC-enabled mode (RBAC Registry + ABAC Repository Permissions):** `AcrPull`/`AcrPush`/`AcrDelete` are **not honored**, and `Owner`/`Contributor`/`Reader` grant control-plane only. Use instead:
|
||||
|
||||
| Role | Permissions |
|
||||
|---|---|
|
||||
| `Container Registry Repository Reader` | Read images, tags, metadata (add ABAC conditions to scope to repositories) |
|
||||
| `Container Registry Repository Writer` | Read + write/update |
|
||||
| `Container Registry Repository Contributor` | Read + write + delete |
|
||||
| `Container Registry Repository Catalog Lister` | List repositories — assign only when the identity must enumerate the catalog (e.g., `az acr repository list`); not needed for pull/push of known repositories |
|
||||
|
||||
```bash
|
||||
# Get the registry resource ID
|
||||
ACR_ID=$(az acr show --name {registry} --query id --output tsv)
|
||||
|
||||
# Grant pull access to a user, group, service principal, or managed identity
|
||||
az role assignment create --assignee {principal-id} --scope $ACR_ID --role AcrPull
|
||||
|
||||
# List who has access
|
||||
az role assignment list --scope $ACR_ID --output table
|
||||
```
|
||||
|
||||
## Service Principals
|
||||
|
||||
For CI/CD systems that cannot use OIDC/managed identity:
|
||||
|
||||
```bash
|
||||
# Create an SP scoped to pull only
|
||||
ACR_ID=$(az acr show --name {registry} --query id --output tsv)
|
||||
az ad sp create-for-rbac --name {sp-name} --scopes $ACR_ID --role AcrPull
|
||||
|
||||
# Docker login with the SP — pipe the secret via stdin, never pass it as an argument
|
||||
# (printf with a quoted variable preserves whitespace/glob characters exactly)
|
||||
printf '%s' "$SP_PASSWORD" | docker login $LOGIN_SERVER --username {appId} --password-stdin
|
||||
```
|
||||
|
||||
Prefer federated credentials (OIDC) over SP passwords in GitHub Actions / Azure DevOps when possible.
|
||||
|
||||
## Managed Identities
|
||||
|
||||
For Azure compute (VM, App Service, Container Apps, Functions):
|
||||
|
||||
```bash
|
||||
# Assign a system-assigned identity and grant it pull
|
||||
az vm identity assign --name {vm} --resource-group {rg}
|
||||
PRINCIPAL_ID=$(az vm show --name {vm} --resource-group {rg} --query identity.principalId --output tsv)
|
||||
az role assignment create --assignee $PRINCIPAL_ID --scope $ACR_ID --role AcrPull
|
||||
```
|
||||
|
||||
App Service / Container Apps then pull with `--assign-identity` + `--acr-identity` style flags of their own CLIs — no registry password needed.
|
||||
|
||||
## AKS Integration
|
||||
|
||||
```bash
|
||||
# Attach at cluster creation
|
||||
az aks create --name {cluster} --resource-group {rg} --attach-acr {registry}
|
||||
|
||||
# Attach/detach an existing cluster (grants AcrPull to the kubelet identity)
|
||||
az aks update --name {cluster} --resource-group {rg} --attach-acr {registry}
|
||||
az aks update --name {cluster} --resource-group {rg} --detach-acr {registry}
|
||||
|
||||
# Validate the cluster can reach the registry
|
||||
az aks check-acr --name {cluster} --resource-group {rg} --acr {registry}.azurecr.io
|
||||
```
|
||||
|
||||
`--attach-acr` requires Owner or User Access Administrator on the registry. Cross-subscription attach works by passing the full ACR resource ID.
|
||||
|
||||
⚠️ `--attach-acr` assigns `AcrPull`, which is **not honored on ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`). For those, assign the ABAC roles to the kubelet identity manually:
|
||||
|
||||
```bash
|
||||
ACR_ID=$(az acr show --name {registry} --query id --output tsv)
|
||||
KUBELET_ID=$(az aks show --name {cluster} --resource-group {rg} \
|
||||
--query identityProfile.kubeletidentity.objectId --output tsv)
|
||||
az role assignment create --assignee $KUBELET_ID --scope $ACR_ID \
|
||||
--role "Container Registry Repository Reader"
|
||||
# "Container Registry Repository Catalog Lister" is NOT needed for pulls —
|
||||
# only add it if the identity must list repositories
|
||||
```
|
||||
|
||||
## Repository-Scoped Tokens
|
||||
|
||||
Available in all service tiers. Fine-grained, non-Entra credentials (e.g., external partners, IoT devices):
|
||||
|
||||
```bash
|
||||
# 1. Create a scope map (actions: content/read, content/write, content/delete, metadata/read, metadata/write)
|
||||
az acr scope-map create --name {scope-map} --registry {registry} \
|
||||
--repository app content/read metadata/read \
|
||||
--description "Pull-only access to app"
|
||||
|
||||
# 2. Create a token bound to the scope map
|
||||
az acr token create --name {token} --registry {registry} --scope-map {scope-map}
|
||||
|
||||
# 3. Generate/rotate passwords (up to 2, optional expiry)
|
||||
az acr token credential generate --name {token} --registry {registry} --password1 --expiration-in-days 30
|
||||
|
||||
# Login with the token — pipe the password via stdin, never pass it as an argument
|
||||
printf '%s' "$TOKEN_PWD" | docker login $LOGIN_SERVER --username {token} --password-stdin
|
||||
|
||||
# Disable or delete
|
||||
az acr token update --name {token} --registry {registry} --status disabled
|
||||
az acr token delete --name {token} --registry {registry} --yes
|
||||
```
|
||||
|
||||
## Admin User
|
||||
|
||||
Single account, full push/pull on the whole registry, not auditable per user — **keep disabled in production**:
|
||||
|
||||
```bash
|
||||
az acr update --name {registry} --admin-enabled false # recommended
|
||||
az acr credential show --name {registry} # view username/passwords (if enabled)
|
||||
az acr credential renew --name {registry} --password-name password2 # rotate
|
||||
```
|
||||
|
||||
Legitimate uses: quick local tests, services that only accept username/password and cannot use tokens.
|
||||
|
||||
## Content Trust (deprecated)
|
||||
|
||||
Docker Content Trust (DCT) is being retired: **since May 31, 2026 it cannot be enabled on new registries** (or on registries that never enabled it), and it will be removed entirely on March 31, 2028. Do not set up DCT — sign images with **Notation (Notary Project)** and store signatures as OCI artifacts instead; see "Transition from Docker Content Trust to Notary Project" in the ACR docs.
|
||||
|
||||
```bash
|
||||
# Registries with legacy DCT only — inspect or disable the existing configuration
|
||||
az acr config content-trust show --registry {registry}
|
||||
az acr config content-trust update --registry {registry} --status disabled
|
||||
```
|
||||
|
||||
Legacy DCT signers needed `AcrImageSigner` in addition to `AcrPush`.
|
||||
@@ -0,0 +1,147 @@
|
||||
# Builds & ACR Tasks
|
||||
|
||||
## Table of Contents
|
||||
- [Quick Build (az acr build)](#quick-build-az-acr-build)
|
||||
- [Run a Command or Multi-Step Task Once (az acr run)](#run-a-command-or-multi-step-task-once-az-acr-run)
|
||||
- [ACR Tasks (az acr task)](#acr-tasks-az-acr-task)
|
||||
- [Triggers](#triggers)
|
||||
- [Multi-Step Task YAML](#multi-step-task-yaml)
|
||||
- [Agent Pools](#agent-pools)
|
||||
|
||||
---
|
||||
|
||||
## Quick Build (az acr build)
|
||||
|
||||
Builds in Azure and pushes to the registry — no local Docker daemon required:
|
||||
|
||||
```bash
|
||||
# Build from the current directory and push
|
||||
az acr build --registry {registry} --image app:v1 .
|
||||
|
||||
# Custom Dockerfile, build args, target platform
|
||||
az acr build --registry {registry} --image app:v1 \
|
||||
--file docker/Dockerfile.prod \
|
||||
--build-arg VERSION=1.2.3 \
|
||||
--platform linux/amd64 .
|
||||
|
||||
# Cross-platform: each build produces ONE single-architecture image for the target platform
|
||||
az acr build --registry {registry} --image app:v1-arm64 --platform linux/arm64 .
|
||||
# For a true multi-arch image, build once per platform under arch-specific tags, then
|
||||
# assemble and push a manifest list (docker manifest create/push, or docker buildx locally)
|
||||
|
||||
# Build directly from a Git repo (no local clone)
|
||||
az acr build --registry {registry} --image app:v1 https://github.com/{org}/{repo}.git#{branch}:{folder}
|
||||
|
||||
# Build without pushing (validation only)
|
||||
az acr build --registry {registry} --image app:test --no-push .
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The build context is uploaded; use a `.dockerignore` to keep it small.
|
||||
- Tag with a unique value per build (git SHA, run ID) — avoid relying on `latest`.
|
||||
|
||||
## Run a Command or Multi-Step Task Once (az acr run)
|
||||
|
||||
```bash
|
||||
# Run a container command in the registry's task runner (context /dev/null = no upload)
|
||||
az acr run --registry {registry} --cmd '{registry}.azurecr.io/app:v1' /dev/null
|
||||
|
||||
# Execute a multi-step task file against the current directory
|
||||
az acr run --registry {registry} --file acb.yaml .
|
||||
```
|
||||
|
||||
## ACR Tasks (az acr task)
|
||||
|
||||
Persistent, triggerable build definitions:
|
||||
|
||||
```bash
|
||||
# Create a task that builds on every commit to main
|
||||
az acr task create --registry {registry} --name build-app \
|
||||
--image "app:{{.Run.ID}}" \
|
||||
--context https://github.com/{org}/{repo}.git#main \
|
||||
--file Dockerfile \
|
||||
--git-access-token {pat} \
|
||||
--commit-trigger-enabled true \
|
||||
--base-image-trigger-enabled true
|
||||
|
||||
# Manually trigger, list, inspect
|
||||
az acr task run --registry {registry} --name build-app
|
||||
az acr task list --registry {registry} --output table
|
||||
az acr task list-runs --registry {registry} --name build-app --output table
|
||||
az acr task logs --registry {registry} --name build-app # latest run
|
||||
az acr task logs --registry {registry} --run-id {run-id}
|
||||
|
||||
# Update / disable / delete
|
||||
az acr task update --registry {registry} --name build-app --image "app:{{.Run.ID}}"
|
||||
az acr task update --registry {registry} --name build-app --status Disabled
|
||||
az acr task delete --registry {registry} --name build-app --yes
|
||||
```
|
||||
|
||||
Useful run variables for `--image`: `{{.Run.ID}}`, `{{.Run.Commit}}`, `{{.Run.Branch}}`, `{{.Run.Date}}`.
|
||||
|
||||
⚠️ On **ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`), tasks and quick builds/runs have no default access to the source registry. Pass `--source-acr-auth-id [caller]` to `az acr build`/`az acr run`, and `--source-acr-auth-id [system]` (or a user-assigned identity resource ID) to `az acr task create`/`update`, then grant that identity the `Container Registry Repository ...` roles. Ensure the task actually has that identity — add `--assign-identity [system]` at creation, or run `az acr task identity assign` on an existing task, before referencing it.
|
||||
|
||||
## Triggers
|
||||
|
||||
```bash
|
||||
# Timer trigger (cron in UTC) — e.g., nightly rebuild
|
||||
az acr task timer add --registry {registry} --name build-app \
|
||||
--timer-name nightly --schedule "0 2 * * *"
|
||||
az acr task timer list --registry {registry} --name build-app
|
||||
az acr task timer remove --registry {registry} --name build-app --timer-name nightly
|
||||
```
|
||||
|
||||
- **Commit trigger**: rebuild on push to the tracked branch (`--commit-trigger-enabled`).
|
||||
- **Base image trigger**: rebuild automatically when the base image (e.g., a patched `mcr.microsoft.com` image) is updated (`--base-image-trigger-enabled`) — key for OS/framework patching.
|
||||
- **Timer trigger**: cron schedules; also the standard way to schedule `acr purge` cleanup (see `images-and-artifacts.md`).
|
||||
|
||||
Tasks that access other registries or Azure resources can use an identity:
|
||||
|
||||
```bash
|
||||
az acr task identity assign --registry {registry} --name build-app # system-assigned
|
||||
az acr task credential add --registry {registry} --name build-app \
|
||||
--login-server {other-registry}.azurecr.io --use-identity [system]
|
||||
```
|
||||
|
||||
## Multi-Step Task YAML
|
||||
|
||||
`acb.yaml` — build, test, then push only on success:
|
||||
|
||||
```yaml
|
||||
version: v1.1.0
|
||||
steps:
|
||||
- build: -t $Registry/app:{{.Run.ID}} -f Dockerfile .
|
||||
- cmd: $Registry/app:{{.Run.ID}} run-tests
|
||||
- push:
|
||||
- $Registry/app:{{.Run.ID}}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Run once
|
||||
az acr run --registry {registry} --file acb.yaml .
|
||||
|
||||
# Or create a triggered task from the YAML
|
||||
az acr task create --registry {registry} --name build-test-push \
|
||||
--file acb.yaml \
|
||||
--context https://github.com/{org}/{repo}.git#main \
|
||||
--git-access-token {pat}
|
||||
```
|
||||
|
||||
## Agent Pools
|
||||
|
||||
Premium SKU. Dedicated task compute — for more CPU, or one of the two supported ways to run tasks against a network-restricted registry (the other being trusted services + the task network bypass policy, see `networking-and-geo.md`):
|
||||
|
||||
```bash
|
||||
az acr agentpool create --registry {registry} --name pool1 --tier S2 # S1/S2/S3/I6
|
||||
|
||||
# For the firewall/VNet scenario, the pool MUST be attached to a subnet that can
|
||||
# reach the registry's private endpoint — without --subnet-id it runs outside the VNet
|
||||
az acr agentpool create --registry {registry} --name pool1 --tier S2 \
|
||||
--subnet-id /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}
|
||||
|
||||
az acr agentpool list --registry {registry} --output table
|
||||
|
||||
# Target the pool
|
||||
az acr build --registry {registry} --agent-pool pool1 --image app:v1 .
|
||||
az acr task create --registry {registry} --name build-app --agent-pool pool1 ...
|
||||
```
|
||||
@@ -0,0 +1,170 @@
|
||||
# Images & Artifacts
|
||||
|
||||
## Table of Contents
|
||||
- [Import Images (Server-Side Copy)](#import-images-server-side-copy)
|
||||
- [Repositories & Tags](#repositories--tags)
|
||||
- [Manifests](#manifests)
|
||||
- [Untag vs Delete](#untag-vs-delete)
|
||||
- [Purge Old Images (acr purge)](#purge-old-images-acr-purge)
|
||||
- [Lock Images](#lock-images)
|
||||
- [Retention Policy & Soft Delete](#retention-policy--soft-delete)
|
||||
- [Artifact Cache (Pull-Through Cache)](#artifact-cache-pull-through-cache)
|
||||
- [Storage Usage](#storage-usage)
|
||||
|
||||
---
|
||||
|
||||
## Import Images (Server-Side Copy)
|
||||
|
||||
Preferred over `docker pull` + `docker push` — no local storage, keeps multi-arch manifests intact:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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`):
|
||||
|
||||
```bash
|
||||
# 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):
|
||||
|
||||
```bash
|
||||
# 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.
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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.
|
||||
@@ -0,0 +1,147 @@
|
||||
# Networking & Geo-Replication
|
||||
|
||||
## Table of Contents
|
||||
- [Geo-Replication](#geo-replication)
|
||||
- [Zone Redundancy](#zone-redundancy)
|
||||
- [Private Endpoints (Private Link)](#private-endpoints-private-link)
|
||||
- [Public Network Rules](#public-network-rules)
|
||||
- [Dedicated Data Endpoints](#dedicated-data-endpoints)
|
||||
- [Connected Registry](#connected-registry)
|
||||
- [Registry Transfer Pipelines](#registry-transfer-pipelines)
|
||||
|
||||
Geo-replication, private endpoints, public IP network rules, dedicated data endpoints, connected registries, and transfer pipelines require the **Premium** SKU. Zone redundancy is automatic in every tier.
|
||||
|
||||
---
|
||||
|
||||
## Geo-Replication
|
||||
|
||||
One registry, one login server, images served from the nearest region:
|
||||
|
||||
```bash
|
||||
az acr replication create --registry {registry} --location westeurope
|
||||
az acr replication list --registry {registry} --output table
|
||||
az acr replication show --registry {registry} --name westeurope
|
||||
az acr replication delete --registry {registry} --name westeurope
|
||||
|
||||
# Regional endpoint status (useful for webhook/replication debugging)
|
||||
az acr replication update --registry {registry} --name westeurope --region-endpoint-enabled true
|
||||
```
|
||||
|
||||
Pushes replicate automatically; clients keep pulling `{registry}.azurecr.io` and Traffic Manager routes to the closest replica.
|
||||
|
||||
## Zone Redundancy
|
||||
|
||||
Zone redundancy is **enabled automatically for all registries, in all tiers (Basic/Standard/Premium), in regions that support availability zones** — no flag, SKU, or action required, and it cannot be disabled. Geo-replicas in supported regions are also zone-redundant by default.
|
||||
|
||||
Do not rely on the `zoneRedundancy` property or the legacy `--zone-redundancy` flag: the property is a deprecated artifact that may display `Disabled` even though the registry is fully zone-redundant. Registries in regions without availability-zone support are the only exception — migrate them (via `az acr import` or a transfer pipeline) to a supported region.
|
||||
|
||||
## Private Endpoints (Private Link)
|
||||
|
||||
```bash
|
||||
# 1. Disable network policies on the endpoint subnet if needed, then create the endpoint
|
||||
az network private-endpoint create --resource-group {rg} --name {registry}-pe \
|
||||
--vnet-name {vnet} --subnet {subnet} \
|
||||
--private-connection-resource-id $(az acr show --name {registry} --query id --output tsv) \
|
||||
--group-ids registry \
|
||||
--connection-name {registry}-pe-conn
|
||||
|
||||
# 2. Private DNS so {registry}.azurecr.io resolves to the private IP
|
||||
az network private-dns zone create --resource-group {rg} --name privatelink.azurecr.io
|
||||
az network private-dns link vnet create --resource-group {rg} \
|
||||
--zone-name privatelink.azurecr.io --name {registry}-dns-link --virtual-network {vnet} --registration-enabled false
|
||||
az network private-endpoint dns-zone-group create --resource-group {rg} \
|
||||
--endpoint-name {registry}-pe --name default \
|
||||
--private-dns-zone privatelink.azurecr.io --zone-name registry
|
||||
|
||||
# 3. Optionally shut off public access entirely
|
||||
az acr update --name {registry} --public-network-enabled false
|
||||
|
||||
# Manage connection approvals
|
||||
az acr private-endpoint-connection list --registry-name {registry} --output table
|
||||
az acr private-endpoint-connection approve --registry-name {registry} --name {connection}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Each private endpoint creates records for the registry **and** its data endpoint(s) (`{registry}.{region}.data.azurecr.io`) — geo-replicated registries need one data record per region.
|
||||
- With public access disabled, standard ACR Tasks agents cannot reach the registry — use a dedicated agent pool attached to a subnet in the VNet, or enable trusted services **and** the task network bypass policy (see below).
|
||||
|
||||
## Public Network Rules
|
||||
|
||||
Restrict public access to specific IPs instead of (or before) going fully private:
|
||||
|
||||
```bash
|
||||
# Default-deny, then allow specific ranges
|
||||
az acr update --name {registry} --default-action Deny
|
||||
az acr network-rule add --name {registry} --ip-address 203.0.113.0/24
|
||||
az acr network-rule list --name {registry}
|
||||
az acr network-rule remove --name {registry} --ip-address 203.0.113.0/24
|
||||
|
||||
# Let trusted Azure services (e.g., Defender, ACI, image import) through the firewall
|
||||
az acr update --name {registry} --allow-trusted-services true
|
||||
```
|
||||
|
||||
⚠️ **Since June 1, 2025, `--allow-trusted-services` alone is NOT enough for ACR Tasks using a system-assigned managed identity** — without the task network bypass policy, their runs get 403 errors on a network-restricted registry. Enable it explicitly:
|
||||
|
||||
```bash
|
||||
az resource update \
|
||||
--namespace Microsoft.ContainerRegistry --resource-type registries \
|
||||
--name {registry} --resource-group {rg} \
|
||||
--api-version 2025-06-01-preview \
|
||||
--set properties.networkRuleBypassAllowedForTasks=true
|
||||
```
|
||||
|
||||
Alternatives that avoid the bypass entirely: run tasks in a VNet-attached agent pool, or run `acr purge` locally with the [acr-cli binary](https://github.com/azure/acr-cli). Tasks using a user-assigned identity are not affected.
|
||||
|
||||
## Dedicated Data Endpoints
|
||||
|
||||
Give layer downloads stable, registry-specific FQDNs (`{registry}.{region}.data.azurecr.io`) instead of shared storage endpoints — simplifies client-side firewall rules:
|
||||
|
||||
```bash
|
||||
az acr update --name {registry} --data-endpoint-enabled true
|
||||
az acr show-endpoints --name {registry}
|
||||
```
|
||||
|
||||
## Connected Registry
|
||||
|
||||
On-premises / IoT edge mirror of a cloud registry:
|
||||
|
||||
```bash
|
||||
# Parent registry must have a dedicated data endpoint
|
||||
az acr update --name {registry} --data-endpoint-enabled true
|
||||
|
||||
az acr connected-registry create --registry {registry} --name {connected-name} \
|
||||
--repository "app" "hello-world" \
|
||||
--mode ReadOnly # or ReadWrite
|
||||
|
||||
az acr connected-registry list --registry {registry} --output table
|
||||
az acr connected-registry get-settings --registry {registry} --name {connected-name} \
|
||||
--parent-protocol https --generate-password 1
|
||||
az acr connected-registry deactivate --registry {registry} --name {connected-name}
|
||||
```
|
||||
|
||||
## Registry Transfer Pipelines
|
||||
|
||||
Move images between disconnected clouds/tenants via storage blobs (extension `acrtransfer`):
|
||||
|
||||
```bash
|
||||
az extension add --name acrtransfer
|
||||
|
||||
# Export from source registry to a storage container (SAS token in Key Vault)
|
||||
az acr export-pipeline create --resource-group {rg} --registry {src-registry} \
|
||||
--name export-pipe \
|
||||
--secret-uri https://{vault}.vault.azure.net/secrets/{sas-secret} \
|
||||
--storage-container-uri https://{account}.blob.core.windows.net/{container}
|
||||
|
||||
# Import on the target side
|
||||
az acr import-pipeline create --resource-group {rg} --registry {dst-registry} \
|
||||
--name import-pipe \
|
||||
--secret-uri https://{vault}.vault.azure.net/secrets/{sas-secret} \
|
||||
--storage-container-uri https://{account}.blob.core.windows.net/{container}
|
||||
|
||||
# Run an export
|
||||
az acr pipeline-run create --resource-group {rg} --registry {src-registry} \
|
||||
--pipeline export-pipe --name run1 --pipeline-type export \
|
||||
--artifacts app:v1 app:v2 --storage-blob transfer-blob-1
|
||||
```
|
||||
|
||||
For simple same-cloud copies prefer `az acr import` (see `images-and-artifacts.md`).
|
||||
Reference in New Issue
Block a user