Allow an ACR to be deployed with placeholder images at user-chosen tags, sourced from a curated set of Microsoft quick-start images
- Dominant language
- No language data
- Stars
- 177
- Forks
- 137
- PR merge metrics
- No merged PRs in 30d
Description
## What is the problem you're trying to solve
Several Azure services that consume container images from an ACR require the referenced image to exist **at the moment the consuming resource is deployed**. Azure Container Apps is the clearest example: deploying a Container App that points at `myacr.azurecr.io/my-image:latest` fails if `my-image:latest` is not already in the registry. This is a known and long-standing pain point (see `microsoft/azure-container-apps#646`).
The realistic workflow is:
1. **Day 0 - infrastructure deployment.** Bicep / ARM / Terraform creates the ACR, the Container App environment, the Container App, networking, identity, etc. The application image (`my-image:latest`) does not exist yet because there is nothing in the pipeline that has built and pushed it.
2. **Day 0+1 - CI/CD.** The application's build pipeline produces the real `my-image:latest` and pushes it into the ACR. From then on, every revision update is a normal `containerapp update --image`.
Step 1 cannot complete today, because the Container App resource refuses to provision against an image path that does not resolve. The infra deploy fails, even though everything downstream of "image gets pushed" would work.
The current workarounds all break the pure-IaC story:
1. Two-stage deployment - deploy ACR, run an out-of-band `docker push` of a dummy image, then deploy the consumers. Requires orchestration outside the template.
2. The community `br/public:deployment-scripts/import-acr` module, which provisions a `Microsoft.Resources/deploymentScripts` resource that spins up an Azure Container Instance, assigns it a managed identity, grants it `AcrPush`, runs the Azure CLI to import a public image and re-tag it, and tears itself down. It works, but it adds a UAMI, a role assignment, an ACI, and a storage account to every deployment, takes minutes per import, and is a script wrapped around what should be a first-class RP capability.
3. `Microsoft.ContainerRegistry/registries/importImage/action` - exists, but it's an imperative POST action, not a declarative child resource that can sit in a Bicep / ARM template alongside the registry.
4. ACR Transfer (`importPipelines` / `exportPipelines` / `pipelineRuns`) - declarative but designed for ACR-to-ACR transfer with a backing storage account; not appropriate for "make sure `my-image:latest` exists in this empty registry."
The result is that the most common "Container Apps + ACR" quick-start cannot be expressed as a single Bicep file, despite both services supporting Bicep individually.
## Describe the solution you'd like
Let the ACR resource declare a list of **placeholder images at user-chosen `repository:tag` paths**, where the **content** comes from a curated set of small Microsoft-published quick-start images (e.g. `aci-helloworld`). The user picks the destination name to match what their CI/CD will push later; the content is just a stand-in so the path resolves.
A possible shape:
```bicep
resource acr 'Microsoft.ContainerRegistry/registries@2026-xx-xx' = {
name: acrName
location: location
sku: { name: 'Basic' }
properties: {
adminUserEnabled: false
placeholderImages: [
{
// The user-chosen path that downstream resources will reference.
// CI/CD will overwrite this tag later with the real image.
target: 'my-image:latest'
// Curated, Microsoft-published stand-in content. Small, safe,
// already on MAR, no licensing or external egress concerns.
source: 'aci-helloworld'
}
{
target: 'my-api:v1'
source: 'aci-helloworld'
}
]
}
}
resource app 'Microsoft.App/containerApps@2025-xx-xx' = {
name: 'my-app'
// ...
properties: {
template: {
containers: [
{
name: 'my-app'
// Resolves on day 0 because the placeholder exists.
// Resolves correctly on day 1+ because CI/CD has overwritten the tag.
image: '${acr.properties.loginServer}/my-image:latest'
}
]
}
}
}
```
The mental model is deliberately narrow:
- **The user picks the destination `repository:tag`** - it must match what their pipeline will push later, otherwise the placeholder is useless.
- **The content is a Microsoft-curated stand-in** - chosen from a short list (`aci-helloworld`, `nginx-hello`, an empty scratch image, etc.) that ACR knows how to materialise without the customer providing credentials, configuring network access to MAR / Docker Hub, or running any compute.
- **It's a one-shot seed, not a sync.** Once CI/CD pushes the real image, the placeholder is gone. Re-running the template should be a no-op if the tag already exists (i.e. don't clobber the real image with the placeholder).
For a more general version, an additional `imports` child resource that targets arbitrary public sources (covered by `Microsoft.ContainerRegistry/registries/importImage/action` today) would also be welcome, but the **placeholder-with-curated-content** variant is the minimum needed to unblock the Container Apps + ACR + Bicep flow.
### Acceptance criteria
- A new declarative property (or child resource) under `Microsoft.ContainerRegistry/registries` that creates one or more placeholder images at user-specified `repository:tag` paths.
- Source content drawn from a small, Microsoft-published catalog so no customer credentials, outbound network egress, managed identity, or role assignments are required.
- Idempotent: if the target tag already exists (e.g. CI/CD has already pushed the real image), the placeholder is not written. Re-deployments do not regress the registry to the placeholder.
- Surfaces in the auto-generated Bicep / ARM / AzAPI / Terraform schemas via the normal REST spec pipeline (`Azure/azure-rest-api-specs` -> `Azure/bicep-types-az`).
- Compatible with private endpoints and ABAC-enabled registries (the seeding happens server-side inside ACR, so no client-side network reachability is required).
## Additional context
- Related, but does not solve this:
- `Microsoft.ContainerRegistry/registries/importImage/action` - imperative, not part of the deployment graph, requires a source URL and credentials, not a curated catalog.
- `Microsoft.ContainerRegistry/registries/importPipelines` + `exportPipelines` + `pipelineRuns` - aimed at ACR-to-ACR transfer with a backing storage account, not at seeding from a curated catalog.
- Current community workaround: `br/public:deployment-scripts/import-acr` in `Azure/bicep-registry-modules`.
- Downstream pain points this would close:
- `microsoft/azure-container-apps#646` - Container Apps deployment fails when the image is not yet in the registry.
- The standard "Container Apps + ACR" quick-start cannot be expressed as a single Bicep file today.
- Reasonable catalog of curated stand-in images (already Microsoft-published on MAR, small, and harmless):
- `mcr.microsoft.com/azuredocs/aci-helloworld`
- `mcr.microsoft.com/azuredocs/containerapps-helloworld`
- `mcr.microsoft.com/k8se/quickstart`
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reviewing the existing Microsoft.ContainerRegistry registries resource and importImage/action definitions, then trace how Azure/azure-rest-api-specs flows into azure/bicep-types-az. Compare a declarative property or child resource with the stated acceptance criteria: curated sources, user-chosen repository:tag targets, idempotency, and compatibility with private endpoints and ABAC.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, terraform
- Domain
- backend-api-design, cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100