Skip to content

Commit 535bef6

Browse files
authored
Add ACR hosting integration content. (#3383)
* Add ACR hosting integration content. Fixes #3222 * Fix code ref * Address feedback * Add TOC preview * Adjust code bit
1 parent a4f2cfa commit 535bef6

File tree

13 files changed

+511
-1
lines changed

13 files changed

+511
-1
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
title: Azure Container Registry integration (Preview)
3+
description: Learn how to integrate Azure Container Registry with .NET Aspire for secure container image management.
4+
ms.date: 05/09/2025
5+
---
6+
7+
# .NET Aspire Azure Container Registry integration (Preview)
8+
9+
[!INCLUDE [includes-hosting](../includes/includes-hosting.md)]
10+
11+
> [!IMPORTANT]
12+
> The .NET Aspire Azure Functions integration is currently in preview and is subject to change.
13+
14+
[Azure Container Registry (ACR)](/azure/container-registry) is a managed Docker container registry service that simplifies the storage, management, and deployment of container images. The .NET Aspire integration allows you to provision or reference an existing Azure Container Registry and seamlessly integrate it with your app's compute environments.
15+
16+
## Overview
17+
18+
.NET Aspire apps often build and run container images locally but require secure registries for staging and production environments. The Azure Container Registry integration provides the following capabilities:
19+
20+
- Provision or reference an existing Azure Container Registry.
21+
- Attach the registry to any compute-environment resource (for example, Azure Container Apps, Docker, Kubernetes) to ensure proper credential flow.
22+
- Grant fine-grained ACR role assignments to other Azure resources.
23+
24+
## Supported scenarios
25+
26+
The Azure Container Registry integration supports the following scenarios:
27+
28+
- **Provisioning a new registry**: Automatically create a new Azure Container Registry for your app.
29+
- **Referencing an existing registry**: Use an existing Azure Container Registry by providing its name and resource group.
30+
- **Credential management**: Automatically flow credentials to compute environments for secure image pulls.
31+
- **Role assignments**: Assign specific roles (for example, `AcrPush`) to enable services to push images to the registry.
32+
33+
## Hosting integration
34+
35+
The Azure Container Registry integration is part of the .NET Aspire hosting model. It allows you to define and manage your app's resources in a declarative manner. The integration is available in the [📦 Aspire.Hosting.Azure.ContainerRegistry](https://www.nuget.org/packages/Aspire.Hosting.Azure.ContainerRegistry) NuGet package.
36+
37+
### [.NET CLI](#tab/dotnet-cli)
38+
39+
```dotnetcli
40+
dotnet add package Aspire.Hosting.Azure.ContainerRegistry
41+
```
42+
43+
### [PackageReference](#tab/package-reference)
44+
45+
```xml
46+
<PackageReference Include="Aspire.Hosting.Azure.ContainerRegistry"
47+
Version="*" />
48+
```
49+
50+
---
51+
52+
For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies).
53+
54+
### Provision a new container registry
55+
56+
The following example demonstrates how to provision a new Azure Container Registry and attach it to a container app environment:
57+
58+
:::code source="snippets/acr//AspireAcr.AppHost/AspireAcr.AppHost/Program.cs":::
59+
60+
The preceding code:
61+
62+
- Creates a new Azure Container Registry named `my-acr`.
63+
- Attaches the registry to an Azure Container Apps environment named `env`.
64+
- Optionally grants the `AcrPush` role to a project resource named `api`, allowing it to push images to the registry.
65+
66+
For more information, see [Configure Azure Container Apps environments](configure-aca-environments.md).
67+
68+
> [!IMPORTANT]
69+
> When you call `AddAzureContainerRegistry` or `AddAzureContainerAppEnvironment`, they implicitly call the idempotent <xref:Aspire.Hosting.AzureProvisionerExtensions.AddAzureProvisioning*>—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Local provisioning: Configuration](local-provisioning.md#configuration).
70+
71+
#### Provisioning-generated Bicep
72+
73+
If you're new to [Bicep](/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Container Registry resource, the following Bicep is generated:
74+
75+
:::code language="bicep" source="snippets/acr/AspireAcr.AppHost/AspireAcr.AppHost/my-acr.module.bicep":::
76+
77+
The preceding Bicep provisions an Azure Container Registry resource. Additionally, the added Azure Container App environment resource is also generated:
78+
79+
:::code language="bicep" source="snippets/acr/AspireAcr.AppHost/AspireAcr.AppHost/env.module.bicep":::
80+
81+
The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly are overwritten, so make changes through the C# provisioning APIs to ensure they're reflected in the generated files.
82+
83+
### Reference an existing container registry
84+
85+
To reference an existing Azure Container Registry, use the <xref:Aspire.Hosting.ExistingAzureResourceExtensions.PublishAsExisting*> method with the registry name and resource group:
86+
87+
:::code source="snippets/acr/AspireAcr.AppHost/AspireAcr.AppHost/Program.Existing.cs" id="existing":::
88+
89+
The preceding code:
90+
91+
- References an existing Azure Container Registry named `my-acr` in the specified resource group.
92+
- Attaches the registry to an Azure Container Apps environment named `env`.
93+
- Uses parameters to allow for dynamic configuration of the registry name and resource group.
94+
- Optionally grants the `AcrPush` role to a project resource named `api`, allowing it to push images to the registry.
95+
96+
### Key features
97+
98+
**Automatic credential flow**
99+
100+
When you attach an Azure Container Registry to a compute environment, Aspire automatically ensures that the correct credentials are available for secure image pulls.
101+
102+
**Fine-grained role assignments**
103+
104+
You can assign specific roles to Azure resources to control access to the container registry. For example, the `AcrPush` role allows a service to push images to the registry.
105+
106+
```csharp
107+
builder.AddProject("api", "../Api/Api.csproj")
108+
.WithRoleAssignments(acr, ContainerRegistryBuiltInRole.AcrPush);
109+
```
110+
111+
## See also
112+
113+
- [Azure Container Registry documentation](/azure/container-registry)
114+
- [.NET Aspire Azure integrations overview](integrations-overview.md)

docs/azure/integrations-overview.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Azure integrations overview
33
description: Overview of the Azure integrations available in the .NET Aspire.
4-
ms.date: 04/10/2025
4+
ms.date: 05/09/2025
55
uid: dotnet/aspire/integrations/azure-overview
66
---
77

@@ -323,6 +323,9 @@ The preceding code:
323323

324324
To configure the Azure Container App environment, see [Configure Azure Container Apps environments](configure-aca-environments.md). For more information, see <xref:Azure.Provisioning.AppContainers.ContainerApp> and <xref:Aspire.Hosting.AzureProvisioningResourceExtensions.AsProvisioningParameter*>.
325325

326+
> [!TIP]
327+
> If you're working with Azure Container Apps, you might also be interested in the [.NET Aspire Azure Container Registry integration](container-registry-integration.md).
328+
326329
## Infrastructure as code
327330

328331
The Azure SDK for .NET provides the [📦 Azure.Provisioning](https://www.nuget.org/packages/Azure.Provisioning) NuGet package and a suite of service-specific [Azure provisioning packages](https://www.nuget.org/packages?q=owner%3A+azure-sdk+description%3A+declarative+resource+provisioning&sortby=relevance). These Azure provisioning libraries make it easy to declaratively specify Azure infrastructure natively in .NET. Their APIs enable you to write object-oriented infrastructure in C#, resulting in Bicep. [Bicep is a domain-specific language (DSL)](/azure/azure-resource-manager/bicep/overview) for deploying Azure resources declaratively.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
4+
5+
<PropertyGroup>
6+
<OutputType>Exe</OutputType>
7+
<TargetFramework>net9.0</TargetFramework>
8+
<ImplicitUsings>enable</ImplicitUsings>
9+
<Nullable>enable</Nullable>
10+
<IsAspireHost>true</IsAspireHost>
11+
<UserSecretsId>4a4b5271-16e5-49fd-a7a1-ff2849aefc25</UserSecretsId>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3.0-preview.1.25251.14" />
16+
<PackageReference Include="Aspire.Hosting.Azure.AppContainers" Version="9.3.0-preview.1.25251.14" />
17+
<PackageReference Include="Aspire.Hosting.Azure.ContainerRegistry" Version="9.3.0-preview.1.25251.14" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Azure.Provisioning.ContainerRegistry;
2+
3+
internal static partial class Program
4+
{
5+
internal static void ReferenceExisting(string[] args)
6+
{
7+
// <existing>
8+
var builder = DistributedApplication.CreateBuilder(args);
9+
10+
var registryName = builder.AddParameter("registryName");
11+
var rgName = builder.AddParameter("rgName");
12+
13+
// Add (or reference) the registry
14+
var acr = builder.AddAzureContainerRegistry("my-acr")
15+
.PublishAsExisting(registryName, rgName);
16+
17+
// Wire an environment to that registry
18+
builder.AddAzureContainerAppEnvironment("env")
19+
.WithAzureContainerRegistry(acr);
20+
21+
builder.Build().Run();
22+
// </existing>
23+
}
24+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Azure.Provisioning.ContainerRegistry;
2+
3+
var builder = DistributedApplication.CreateBuilder(args);
4+
5+
// Add (or reference) the registry
6+
var acr = builder.AddAzureContainerRegistry("my-acr");
7+
8+
// Wire an environment to that registry
9+
builder.AddAzureContainerAppEnvironment("env")
10+
.WithAzureContainerRegistry(acr);
11+
12+
builder.Build().Run();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"https": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"launchBrowser": true,
8+
"applicationUrl": "https://localhost:17190;http://localhost:15027",
9+
"environmentVariables": {
10+
"ASPNETCORE_ENVIRONMENT": "Development",
11+
"DOTNET_ENVIRONMENT": "Development",
12+
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21284",
13+
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22130"
14+
}
15+
},
16+
"http": {
17+
"commandName": "Project",
18+
"dotnetRunMessages": true,
19+
"launchBrowser": true,
20+
"applicationUrl": "http://localhost:15027",
21+
"environmentVariables": {
22+
"ASPNETCORE_ENVIRONMENT": "Development",
23+
"DOTNET_ENVIRONMENT": "Development",
24+
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19098",
25+
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20225"
26+
}
27+
},
28+
"generate-manifest": {
29+
"commandName": "Project",
30+
"launchBrowser": false,
31+
"dotnetRunMessages": true,
32+
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
33+
}
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@description('The location for the resource(s) to be deployed.')
2+
param location string = resourceGroup().location
3+
4+
resource api_identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
5+
name: take('api_identity-${uniqueString(resourceGroup().id)}', 128)
6+
location: location
7+
}
8+
9+
output id string = api_identity.id
10+
11+
output clientId string = api_identity.properties.clientId
12+
13+
output principalId string = api_identity.properties.principalId
14+
15+
output principalName string = api_identity.name
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@description('The location for the resource(s) to be deployed.')
2+
param location string = resourceGroup().location
3+
4+
param my_acr_outputs_name string
5+
6+
param principalId string
7+
8+
resource my_acr 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = {
9+
name: my_acr_outputs_name
10+
}
11+
12+
resource my_acr_AcrPush 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
13+
name: guid(my_acr.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec'))
14+
properties: {
15+
principalId: principalId
16+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')
17+
principalType: 'ServicePrincipal'
18+
}
19+
scope: my_acr
20+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
@description('The location for the resource(s) to be deployed.')
2+
param location string = resourceGroup().location
3+
4+
param api_identity_outputs_id string
5+
6+
param api_identity_outputs_clientid string
7+
8+
param api_containerport string
9+
10+
param env_outputs_azure_container_apps_environment_default_domain string
11+
12+
param env_outputs_azure_container_apps_environment_id string
13+
14+
param env_outputs_azure_container_registry_endpoint string
15+
16+
param env_outputs_azure_container_registry_managed_identity_id string
17+
18+
param api_containerimage string
19+
20+
resource api 'Microsoft.App/containerApps@2024-03-01' = {
21+
name: 'api'
22+
location: location
23+
properties: {
24+
configuration: {
25+
activeRevisionsMode: 'Single'
26+
ingress: {
27+
external: false
28+
targetPort: api_containerport
29+
transport: 'http'
30+
}
31+
registries: [
32+
{
33+
server: env_outputs_azure_container_registry_endpoint
34+
identity: env_outputs_azure_container_registry_managed_identity_id
35+
}
36+
]
37+
}
38+
environmentId: env_outputs_azure_container_apps_environment_id
39+
template: {
40+
containers: [
41+
{
42+
image: api_containerimage
43+
name: 'api'
44+
env: [
45+
{
46+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES'
47+
value: 'true'
48+
}
49+
{
50+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES'
51+
value: 'true'
52+
}
53+
{
54+
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY'
55+
value: 'in_memory'
56+
}
57+
{
58+
name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED'
59+
value: 'true'
60+
}
61+
{
62+
name: 'HTTP_PORTS'
63+
value: api_containerport
64+
}
65+
{
66+
name: 'AZURE_CLIENT_ID'
67+
value: api_identity_outputs_clientid
68+
}
69+
]
70+
}
71+
]
72+
scale: {
73+
minReplicas: 1
74+
}
75+
}
76+
}
77+
identity: {
78+
type: 'UserAssigned'
79+
userAssignedIdentities: {
80+
'${api_identity_outputs_id}': { }
81+
'${env_outputs_azure_container_registry_managed_identity_id}': { }
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)