Automated cleanup for Azure Container Registry repositories. Deploys a scheduled ACR task that retains only the last N images per repository and deletes the rest.
The ACR task uses the built-in acr purge command with:
| Flag | Value | Purpose |
|---|---|---|
--filter |
'demo/purge/.*:.*' |
Namespace wildcard — matches all repos under demo/purge/ |
--ago |
0d |
Consider all images regardless of age |
--keep |
3 |
Retain the 3 most recent images per repository |
Note:
--untaggedis intentionally omitted to avoid removing multi-arch sub-manifests.
| File | Description |
|---|---|
acr-purge-task.bicep |
Bicep template to deploy the scheduled purge task |
acr-purge-workflow.sh |
End-to-end bash script: seeds repos, creates task, runs & verifies |
# Deploy the purge task
az deployment group create \
--resource-group <RESOURCE_GROUP> \
--template-file acr-purge-task.bicep \
--parameters \
registryName=<REGISTRY_NAME> \
keepCount=3 \
repoFilter='demo/purge/.*:.*'
# Trigger a manual run to verify
az acr task run \
--name purge-keep-3 \
--registry <REGISTRY_NAME> \
--resource-group <RESOURCE_GROUP>| Parameter | Default | Description |
|---|---|---|
registryName |
(required) | Name of the existing ACR |
keepCount |
3 |
Number of images to retain per repo |
repoFilter |
demo/purge/.*:.* |
Regex filter for repositories and tags |
schedule |
0 0 * * * |
Cron schedule (default: daily at midnight UTC) |
taskName |
purge-keep-<N> |
Name of the ACR task |
# Namespace wildcard — single filter covers all repos under a prefix
az acr task create \
--name purge-keep-3 \
--registry <REGISTRY_NAME> \
--resource-group <RESOURCE_GROUP> \
--cmd "acr purge --filter 'demo/purge/.*:.*' --ago 0d --keep 3" \
--schedule "0 0 * * *" \
--context /dev/null
# Per-repo filters — use when repos don't share a prefix
az acr task create \
--name purge-keep-3 \
--registry <REGISTRY_NAME> \
--resource-group <RESOURCE_GROUP> \
--cmd "acr purge \
--filter 'demo/purge/web:.*' \
--filter 'demo/purge/api:.*' \
--filter 'demo/purge/worker:.*' \
--ago 0d --keep 3" \
--schedule "0 0 * * *" \
--context /dev/nullAlways test before executing:
az acr run \
--registry <REGISTRY_NAME> \
--resource-group <RESOURCE_GROUP> \
--cmd "acr purge --filter 'demo/purge/.*:.*' --ago 0d --keep 3 --dry-run" \
/dev/nullThe acr-purge-workflow.sh script demonstrates the full lifecycle:
- Seeds 3 repositories (
demo/purge/web,demo/purge/api,demo/purge/worker) with 10 images eachwebandapiuseaz acr buildwith a minimal Dockerfileworkerusesoras copyto re-tag a single image (no build needed)
- Creates the scheduled purge task
- Dry-runs to preview what would be deleted
- Executes the purge
- Verifies that exactly 3 tags remain per repository
export REGISTRY_NAME="<your-registry>"
export RESOURCE_GROUP="<your-resource-group>"
bash acr-purge-workflow.sh| Pattern | Matches |
|---|---|
demo/purge/.*:.* |
All repos under demo/purge/ namespace, all tags |
myapp:.* |
All tags in the myapp repo |
myapp:^v\d+ |
Tags starting with v followed by digits in myapp |
.*:.* |
Every repo and every tag in the registry |