Azure Developer CLI (azd) 已扩展为支持部署Aspire项目。 使用本指南逐步完成创建和部署 Aspire 项目到 Azure Container Apps 的过程,并使用 Azure Developer CLI。 在本教程中,你将了解以下概念:
- 探索
azd如何与Aspire项目集成工作 - 使用
azd在 Azure 上为 Aspire 项目配置和部署资源 - 使用
azd生成 Bicep 基础结构和其他模板文件
先决条件
若要使用 Aspire,需要在本地安装以下各项:
-
.NET 8.0 或 .NET 9.0。
- 从 Aspire 9.4 开始,支持 .NET 10 Preview 5 或更高版本。
- 符合 OCI 的容器运行时环境,例如:
- 集成开发人员环境(IDE)或代码编辑器,例如:
- Visual Studio 2022 17.9 或更高版本(可选)
-
Visual Studio Code (可选)
- C# Dev Kit:扩展(可选)
- JetBrains Rider 与 Aspire 插件 (可选)
有关详细信息,请参阅 Aspire 设置和工具以及 Aspire SDK。
你还需要在本地安装
winget install microsoft.azd
Azure Developer CLI集成的工作原理
工作流 azd init 为 Aspire 项目提供自定义支持。 下图说明了此流程的概念以及azd和Aspire的集成方式:
- 当
azd针对 Aspire 项目时,它会通过特殊命令(dotnet run --project AppHost.csproj --output-path manifest.json --publisher manifest)启动 AppHost,从而生成 Aspire 清单文件。 - 清单文件通过
azd provision子命令逻辑处理,以仅在内存中生成 Bicep 文件(默认情况下)。 - 生成 Bicep 文件后,将使用 ARM API 触发部署,目标是前面提供的订阅和资源组。
- 配置基础 Azure 资源后,
azd deploy将执行子命令逻辑,该逻辑使用相同的 Aspire 清单文件。 - 作为部署
azd的一部分,调用dotnet publish使用 .NET内置容器发布支持来生成容器映像。 - 生成容器映像后
azd,它会将它们推送到预配阶段创建的 ACR 注册表。 - 最后,在容器映像位于 ACR 中后,
azd使用 ARM 更新资源以开始使用新版本的容器映像。
注释
azd 此外,还可以将生成的 Bicep 输出到项目的 infra 文件夹中,相关信息可在 从 Aspire 应用模型生成 Bicep 部分了解。
配置和部署 Aspire 入门应用
本部分中的步骤演示如何创建 Aspire 启动应用并处理预配以及将应用资源部署到 Azure 使用 azd。
创建Aspire起始应用
使用Aspire命令创建新dotnet new项目。 还可以使用Visual Studio创建项目。
dotnet new aspire-starter --use-redis-cache -o AspireSample
cd AspireSample
dotnet run --project AspireSample.AppHost\AspireSample.AppHost.csproj
前面的命令基于Aspire模板创建新aspire-starter项目,其中包含对缓存的Redis依赖项。 它运行 Aspire 项目,验证一切是否正常工作。
初始化模板
打开新的终端窗口,并
cd进入解决方案的 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 Create a minimal project扫描目录后,
azd提示你确认它找到了正确的 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:描述应用的服务,例如 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。
初始部署
若要部署 Aspire 项目,请向 Azure AD 进行身份验证以调用 Azure 资源管理 API。
azd auth login上一个命令将启动浏览器以对命令行会话进行身份验证。
进行身份验证后,从 AppHost 项目目录运行以下命令来预配和部署应用程序。
azd up重要
若要将容器映像推送到 Azure 容器注册表(ACR),需要具有
Microsoft.Authorization/roleAssignments/write访问权限。 这可以通过在注册表上启用 管理员用户 来实现。 打开 Azure 门户,导航到 ACR 资源/设置/访问密钥,然后选择 “管理员用户 ”复选框。 有关详细信息,请参阅 “启用管理员用户”。出现提示时,请选择应将资源部署到的订阅和位置。 选择这些选项后, 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 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。
有关项目如何处理 Aspire 连接字符串和服务发现的详细信息,请参阅 Aspire 业务流程概述。
部署应用程序更新
azd up执行命令时,底层Azure资源被预配,生成容器映像,并将其部署到托管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 Aspire DASHBOARD>
无需每次部署所有服务。
azd 了解 Aspire 项目模型,只需使用以下命令部署指定的服务之一:
azd deploy webfrontend
有关详细信息,请参阅 Azure Developer CLI 文档:azd deploy。
部署基础设施更新
每当项目内的 Aspire 依赖项结构发生更改时, azd 都必须重新预配基础 Azure 资源。 该 azd provision 命令用于将这些更改应用到基础结构。
若要查看实际效果,请将 AppHost 项目中的AppHost.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.
从 Aspire 项目模型生成 Bicep
尽管开发团队可以自由使用 azd up (或 azd provision ) azd deploy命令进行开发和生产目的的部署,但一些团队可能会选择生成 Bicep 文件,这些文件可以作为版本控制的一部分进行查看和管理(这也允许将这些 Bicep 文件作为更大复杂 Azure 部署的一部分引用)。
有关为生产方案自定义生成的基础结构的综合指南,请参阅 “自定义 AspireAzure 部署”。
azd 包括通过以下命令输出用于预配的 Bicep 的功能:
azd config set alpha.infraSynth on
azd infra gen
在本指南中使用的初学者模板示例中执行此命令后,会在 AppHost 项目目录中创建以下文件:
- infra/main.bicep:表示部署的主要入口点。
- infra/main.parameters.json:用作主 Bicep 的参数(映射到 .azure 文件夹中定义的环境变量)。
- infra/resources.bicep:定义 Azure 支持 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。
服务项目中容器应用.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 gen 命令后,当调用 azd provision 和 azd deploy 时,它们会使用 Bicep 及生成的支持文件。
重要
如果 azd infra gen 再次调用,它将将任何修改的文件替换为新生成的文件,并在执行此作之前提示你进行确认。
用于调试的独立环境
由于 azd 可以轻松预配新环境,因此每个团队成员都可以使用独立的云托管环境来调试与生产紧密匹配的设置中的代码。 执行此作时,每个团队成员应使用以下命令创建自己的环境:
azd env new
这将再次提示用户输入订阅和资源组信息,后续的azd up、azd provision和azd deploy调用将默认使用此新环境。
--environment开关可以用于这些命令来切换环境。
清理资源
运行以下 Azure CLI 命令,在不再需要创建的 Azure 资源时删除资源组。 删除资源组也会删除其中包含的资源。
az group delete --name <your-resource-group-name>
有关详细信息,请参阅 清理 Azure中的资源。