使用 .NET Aspire 将 Azure Container Apps 项目部署到 Azure Developer CLI(深入指南)
Azure Developer CLI(azd
)已扩展,以支持部署 .NET.NET Aspire 项目。 使用本指南逐步指导您如何使用 .NET Aspire创建并将 Azure Container Apps 项目部署到 Azure Developer CLI。 在本教程中,你将了解以下概念:
- 了解
azd
集成如何与 .NET.NET Aspire 项目配合使用 - 使用 Azure 在 .NET Aspire 项目的
azd
上配置和部署资源 - 使用
azd
生成 Bicep 基础结构和其他模板文件
先决条件
若要使用 .NET.NET Aspire,需要在本地安装以下各项:
- .NET 8.0 或 .NET 9.0
- 符合 OCI 的容器运行时环境,例如:
- 集成开发人员环境(IDE)或代码编辑器,例如:
- Visual Studio 2022 17.9 或更高版本(可选)
-
Visual Studio Code (可选)
- C# Dev Kit:扩展(可选)
- JetBrains Rider 使用 .NET.NET Aspire 插件 (可选)
有关详细信息,请参阅 .NET.NET Aspire 设置和工具,以及 .NET.NET Aspire SDK。
还需要在本地安装 Azure Developer CLI。 常见的安装选项包括:
Azure Developer CLI 的集成工作原理
azd init
工作流为 .NET.NET Aspire 项目提供自定义支持。 下图说明了此流在概念上的工作原理,以及如何集成 azd
和 .NET.NET Aspire:
- 当
azd
面向 .NET.NET Aspire 项目时,它将使用特殊命令(dotnet run --project AppHost.csproj --output-path manifest.json --publisher manifest
)启动 AppHost,这将生成 Aspire清单文件。 - 清单文件由
azd provision
子命令逻辑分析,以仅在内存中生成 Bicep 文件,默认情况下。 - 生成 Bicep 文件后,将使用 Azure的 ARM API 针对前面提供的订阅和资源组触发部署。
- 配置基础 Azure 资源后,将执行
azd deploy
子命令逻辑,该逻辑使用相同的 Aspire 清单文件。 - 作为部署
azd
的一部分,使用dotnet publish
的内置容器发布支持来生成容器映像,并调用 .NET。 -
azd
生成容器映像后,它会将它们推送到预配阶段创建的 ACR 注册表。 - 最后,在容器映像位于 ACR 中后,
azd
使用 ARM 更新资源,以开始使用新版本的容器映像。
注意
azd
还使你能够将生成的 Bicep 输出到项目中的 infra
文件夹中,可以在 从 .NET.NET Aspire 应用模型生成 Bicep 部分阅读详细信息。
配置和部署 .NET.NET Aspire 入门应用
本节中的步骤演示了如何创建一个 .NET Aspire 起始应用,并处理应用资源的配置和部署,以便在 Azure 使用 azd
。
创建 .NET.NET Aspire 初学者应用
使用 .NET 命令创建新的 .NET Aspiredotnet new
项目。 还可以使用 Visual Studio创建项目。
dotnet new aspire-starter --use-redis-cache -o AspireSample
cd AspireSample
dotnet run --project AspireSample.AppHost\AspireSample.AppHost.csproj
上述命令基于 .NET 模板创建新的 .NET Aspireaspire-starter
项目,其中包含对 Redis 缓存的依赖项。 它运行 .NET.NET Aspire 项目,它验证一切是否正常工作。
初始化模板
打开新的终端窗口,并
cd
到 .NET 解决方案的 .NET Aspire 项目目录。执行
azd init
命令以使用azd
初始化项目,这将检查本地目录结构并确定应用的类型。azd init
有关
azd init
命令的详细信息,请参阅 azd init。当 提示你使用两个应用初始化选项时,选择
azd
。? How do you want to initialize your app? [Use arrows to move, type to filter] > Use code in the current directory Select a template
扫描目录后,
azd
会提示你确认它找到正确的 .NET.NET AspireAppHost 项目。 选择 确认并继续初始化我的应用 选项。Detected services: .NET (Aspire) Detected in: D:\source\repos\AspireSample\AspireSample.AppHost\AspireSample.AppHost.csproj azd will generate the files necessary to host your app on Azure using Azure Container Apps. ? Select an option [Use arrows to move, type to filter] > Confirm and continue initializing my app Cancel and exit
输入环境名称,该名称用于命名 Azure 中预配的资源,并管理不同的环境,例如
dev
和prod
。Generating files to run your app on Azure: (✓) Done: Generating ./azure.yaml (✓) Done: Generating ./next-steps.md SUCCESS: Your app is ready for the cloud! You can provision and deploy your app to Azure by running the azd up command in this directory. For more information on configuring your app, see ./next-steps.md
azd
生成多个文件并将其放入工作目录中。 这些文件包括:
- azure.yaml:描述应用的服务,例如 .NET Aspire AppHost 项目,并将其映射到 Azure 资源。
-
/azure/config/json:用于告知
azd
当前活动环境的配置文件。 - 。azure/aspireazddev/.env:包含特定于环境的替代。
azure.yaml 文件包含以下内容:
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
name: AspireSample
services:
app:
language: dotnet
project: .\AspireSample.AppHost\AspireSample.AppHost.csproj
host: containerapp
资源命名
创建新的 Azure 资源时,请务必遵循命名要求。 对于 Azure Container Apps,名称长度必须为 2-32 个字符,由小写字母、数字和连字符组成。 名称必须以字母开头,以字母数字字符结尾。
有关详细信息,请参阅 Azure 资源的命名规则和限制。
初始部署
若要部署 .NET Aspire 项目,请向 Azure AD 进行身份验证,以调用 Azure 资源管理 API。
azd auth login
上一个命令将启动浏览器以对命令行会话进行身份验证。
进行身份验证后,从 AppHost 项目目录运行以下命令来预配和部署应用程序。
azd up
重要
若要将容器映像推送到 Azure 容器注册表(ACR),需要具有
Microsoft.Authorization/roleAssignments/write
访问权限。 这可以通过在注册表上启用 管理员用户 来实现。 打开 Azure 门户,导航到 ACR 资源/设置/访问密钥,然后选择 管理员用户 复选框。 有关详细信息,请参阅 启用管理员用户。出现提示时,请选择应将资源部署到的订阅和位置。 选择这些选项后,将部署 .NET.NET Aspire 项目。
By default, a service can only be reached from inside the Azure Container Apps environment it is running in. Selecting a service here will also allow it to be reached from the Internet. ? Select which services to expose to the Internet webfrontend ? Select an Azure Subscription to use: 1. <YOUR SUBSCRIPTION> ? Select an Azure location to use: 1. <YOUR LOCATION> Packaging services (azd package) Provisioning Azure resources (azd provision) Provisioning Azure resources can take some time. Subscription: <YOUR SUBSCRIPTION> Location: <YOUR LOCATION> You can view detailed progress in the Azure Portal: <LINK TO DEPLOYMENT> (✓) Done: Resource group: <YOUR RESOURCE GROUP> (✓) Done: Container Registry: <ID> (✓) Done: Log Analytics workspace: <ID> (✓) Done: Container Apps Environment: <ID> SUCCESS: Your application was provisioned in Azure in 1 minute 13 seconds. You can view the resources created under the resource group <YOUR RESOURCE GROUP> in Azure Portal: <LINK TO RESOURCE GROUP OVERVIEW> Deploying services (azd deploy) (✓) Done: Deploying service apiservice - Endpoint: <YOUR UNIQUE apiservice APP>.azurecontainerapps.io/ (✓) Done: Deploying service webfrontend - Endpoint: <YOUR UNIQUE webfrontend APP>.azurecontainerapps.io/ Aspire Dashboard: <LINK TO DEPLOYED .NET ASPIRE DASHBOARD> SUCCESS: Your up workflow to provision and deploy to Azure completed in 3 minutes 50 seconds.
azd
命令的最后一行输出是指向 Azure 门户的链接,其中显示了已部署的所有 Azure 资源:
此应用程序中部署了三个容器:
-
webfrontend
:包含入门模板中的 Web 项目代码。 -
apiservice
:包含初学者模板中 API 服务项目中的代码。 -
cache
:用于向前端提供缓存的 Redis 容器映像。
就像在本地开发中一样,已自动处理连接字符串的配置。 在这种情况下,azd
负责解释应用程序模型并将其转换为相应的部署步骤。 例如,请考虑注入到 webfrontend
容器中的连接字符串和服务发现变量,以便知道如何连接到 Redis 缓存和 apiservice
。
有关如何 .NET.NET Aspire 项目处理连接字符串和服务发现的详细信息,请参阅 .NET.NET Aspire 业务流程概述。
部署应用程序更新
执行 azd up
命令时,基础 Azure 资源被 预配,接着生成容器映像,并将其部署到托管.NET 项目的容器应用 .NET Aspire。 通常,一旦开发正在进行并且部署 Azure 资源,则每次更新代码时,都不需要预配 Azure 资源,这对于开发人员内部循环尤其如此。
为了加快代码更改的部署速度,azd
支持在容器映像中部署代码更新。 这是使用 azd deploy
命令完成的:
azd deploy
Deploying services (azd deploy)
(✓) Done: Deploying service apiservice
- Endpoint: <YOUR UNIQUE apiservice APP>.azurecontainerapps.io/
(✓) Done: Deploying service webfrontend
- Endpoint: <YOUR UNIQUE webfrontend APP>.azurecontainerapps.io/
Aspire Dashboard: <LINK TO DEPLOYED .NET ASPIRE DASHBOARD>
无需每次部署所有服务。
azd
理解 .NET.NET Aspire 项目模型,可以使用以下命令只部署指定的服务之一:
azd deploy webfrontend
有关详细信息,请参阅 Azure Developer CLI 参考:azd deploy。
部署基础设施更新
每当 .NET.NET Aspire 项目中的依赖项结构发生更改时,azd
必须重新预配基础 Azure 资源。
azd provision
命令用于将这些更改应用于基础结构。
若要查看此操作,请将 AppHost 项目中 Program.cs 文件更新为以下内容:
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
// Add the locations database.
var locationsdb = builder.AddPostgres("db").AddDatabase("locations");
// Add the locations database reference to the API service.
var apiservice = builder.AddProject<Projects.AspireSample_ApiService>("apiservice")
.WithReference(locationsdb);
builder.AddProject<Projects.AspireSample_Web>("webfrontend")
.WithReference(cache)
.WithReference(apiservice);
builder.Build().Run();
保存文件并发出以下命令:
azd provision
azd provision
命令通过创建容器应用来托管 Postgres 数据库来更新基础结构。
azd provision
命令未更新 apiservice
容器的连接字符串。 若要更新连接字符串以指向新预配 Postgres 数据库,需要再次调用 azd deploy
命令。 如有疑问,请同时使用 azd up
进行预配和部署。
清理资源
请记得清理你在此演示中创建的 Azure 资源。 因为 azd 知道它在哪个资源组中创建了资源,因此可以使用以下命令关闭环境:
azd down
上一个命令可能需要一些时间才能执行,但完成资源组及其所有资源时,应将其删除。
Deleting all resources and deployed code on Azure (azd down)
Local application code is not deleted when running 'azd down'.
Resource group(s) to be deleted:
• <YOUR RESOURCE GROUP>: <LINK TO RESOURCE GROUP OVERVIEW>
? Total resources to delete: 7, are you sure you want to continue? Yes
Deleting your resources can take some time.
(✓) Done: Deleting resource group: <YOUR RESOURCE GROUP>
SUCCESS: Your application was removed from Azure in 9 minutes 59 seconds.
基于 .NET.NET Aspire 项目模型生成 Bicep
尽管开发团队可以自由使用 azd up
(或 azd provision
和 azd deploy
)命令进行开发和生产目的的部署,但一些团队可能会选择生成 Bicep 文件,这些文件可以作为版本控制的一部分进行评审和管理(这也允许将这些 Bicep 文件作为较复杂的 Azure 部署的一部分引用)。
azd
包括通过以下命令输出其用于配置的 Bicep 脚本的能力:
azd config set alpha.infraSynth on
azd infra synth
在本指南中使用的初学者模板示例中执行此命令后,会在 AppHost 项目目录中创建以下文件:
- infra/main.bicep:表示部署的主要入口点。
- infra/main.parameters。json:作为主要 Bicep 的参数使用(映射到 .azure 文件夹中定义的环境变量)。
- infra/resources.bicep:定义支持 Azure 项目模型所需的.NET Aspire 资源。
-
AspireSample.Web/manifests/containerApp.tmpl.yaml:
webfrontend
的容器应用定义。 -
AspireSample.ApiService/manifests/containerApp.tmpl.yaml:
apiservice
的容器应用定义。
基础结构\resources.bicep 文件不包含容器应用本身的任何定义(容器应用除外),这些应用是依赖项(如 Redis 和 Postgres):
@description('The location used for all deployed resources')
param location string = resourceGroup().location
@description('Tags that will be applied to all resources')
param tags object = {}
var resourceToken = uniqueString(resourceGroup().id)
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: 'mi-${resourceToken}'
location: location
tags: tags
}
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: replace('acr-${resourceToken}', '-', '')
location: location
sku: {
name: 'Basic'
}
tags: tags
}
resource caeMiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerRegistry.id, managedIdentity.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
scope: containerRegistry
properties: {
principalId: managedIdentity.properties.principalId
principalType: 'ServicePrincipal'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
}
}
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: 'law-${resourceToken}'
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
tags: tags
}
resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = {
name: 'cae-${resourceToken}'
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalyticsWorkspace.properties.customerId
sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
}
}
}
tags: tags
}
resource cache 'Microsoft.App/containerApps@2023-05-02-preview' = {
name: 'cache'
location: location
properties: {
environmentId: containerAppEnvironment.id
configuration: {
service: {
type: 'redis'
}
}
template: {
containers: [
{
image: 'redis'
name: 'redis'
}
]
}
}
tags: union(tags, {'aspire-resource-name': 'cache'})
}
resource locations 'Microsoft.App/containerApps@2023-05-02-preview' = {
name: 'locations'
location: location
properties: {
environmentId: containerAppEnvironment.id
configuration: {
service: {
type: 'postgres'
}
}
template: {
containers: [
{
image: 'postgres'
name: 'postgres'
}
]
}
}
tags: union(tags, {'aspire-resource-name': 'locations'})
}
output MANAGED_IDENTITY_CLIENT_ID string = managedIdentity.properties.clientId
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.properties.loginServer
output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = managedIdentity.id
output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = containerAppEnvironment.id
output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = containerAppEnvironment.properties.defaultDomain
有关使用 Bicep 自动将部署到 Azure 的详细信息,请参阅 什么是 Bicep?
来自 .NET 服务项目的容器应用的定义分别包含在每个项目中 目录中 manifests
文件中。 下面是 webfrontend
项目中的示例:
location: {{ .Env.AZURE_LOCATION }}
identity:
type: UserAssigned
userAssignedIdentities:
? "{{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}"
: {}
properties:
environmentId: {{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_ID }}
configuration:
activeRevisionsMode: single
ingress:
external: true
targetPort: 8080
transport: http
allowInsecure: false
registries:
- server: {{ .Env.AZURE_CONTAINER_REGISTRY_ENDPOINT }}
identity: {{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}
template:
containers:
- image: {{ .Env.SERVICE_WEBFRONTEND_IMAGE_NAME }}
name: webfrontend
env:
- name: AZURE_CLIENT_ID
value: {{ .Env.MANAGED_IDENTITY_CLIENT_ID }}
- name: ConnectionStrings__cache
value: {{ connectionString "cache" }}
- name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES
value: "true"
- name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES
value: "true"
- name: services__apiservice__0
value: http://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
- name: services__apiservice__1
value: https://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
tags:
azd-service-name: webfrontend
aspire-resource-name: webfrontend
执行 azd infra synth
命令后,调用 azd provision
和 azd deploy
时,它们使用 Bicep 和生成的支持文件。
重要
如果再次调用 azd infra synth
,它会用新生成的文件替换任何修改的文件,并在执行此操作之前提示你进行确认。
用于调试的隔离环境
由于 azd
可以轻松预配新环境,因此每个团队成员都可以使用独立的云托管环境来调试与生产紧密匹配的设置中的代码。 执行此操作时,每个团队成员应使用以下命令创建自己的环境:
azd env new
这将再次提示用户输入订阅和资源组信息,后续 azd up
、azd provision
,azd deploy
调用将默认使用此新环境。
--environment
开关可以应用于这些命令,以在环境之间切换。
清理资源
运行以下 Azure CLI 命令,在不再需要创建的 Azure 资源时删除资源组。 删除资源组也会删除其中包含的资源。
az group delete --name <your-resource-group-name>
有关详细信息,请参阅 清理 Azure中的资源。