Aspire Azure Container Apps 托管集成:环境建模、计算资源编排与发布部署实战指南
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
导读
Aspire.Hosting.Azure.AppContainers是 Aspire 用于建模、配置和编排 Azure Container Apps 环境的托管集成。本文基于该集成在仓库中的 README.md 展开,并结合 AzureContainerAppExtensions.cs、AzureContainerAppContainerExtensions.cs 等源码实现与 AzureContainerAppEnvironmentExtensionsTests.cs 测试用例,系统讲解如何用一行 API 在 Aspire 解决方案中声明 Container Apps 环境、把 Dockerfile/项目/可执行程序发布为容器应用、定制入站流量与命名约定,并通过aspire publish/aspire deploy完成从 Bicep 生成到真实资源预配的完整链路。读完本文,你将掌握该集成的全部核心 API、默认基础设施模型、常见定制手段及部署/清理的实战方法。
一、集成概览:一条语句构建云原生应用环境
该集成允许在 Aspire AppHost 的编程模型中"声明式"地定义一个 Azure Container Apps 环境,并把解决方案中的计算资源(Dockerfile 容器、.NET 项目、可执行程序)自动映射为该环境内的 Container App。它位于 src/Aspire.Hosting.Azure.AppContainers/ 目录,核心类型包括:
| 文件 | 职责 |
|---|---|
| AzureContainerAppExtensions.cs | 环境资源的入口AddAzureContainerAppEnvironment,以及命名、Dashboard、日志、拉取身份等定制 API |
| AzureContainerAppEnvironmentResource.cs | 环境资源模型,实现IAzureComputeEnvironmentResource、IContainerRegistry等接口 |
| AzureContainerAppContainerExtensions.cs | 将容器资源发布为 Container App |
| AzureContainerAppProjectExtensions.cs | 将项目资源发布为 Container App |
| AzureContainerAppExecutableExtensions.cs | 将可执行程序资源发布为 Container App |
| ContainerAppContext.cs | 单个 Container App 的构建逻辑:端点、环境变量、密钥、卷、探针 |
| ContainerAppEnvironmentContext.cs | 环境级上下文:为每个计算资源创建 Container App |
| AzureContainerAppScaleConfig.cs | 缩放配置模型 |
| AzureContainerAppJobCustomizationAnnotation.cs | Container App Job 定制标注 |
从源码结构看,该集成基于 Azure.Provisioning(CDK)构建:环境资源继承自AzureProvisioningResource,通过回调把 Azure 资源(托管环境、容器注册表、Log Analytics 工作区、托管标识等)编译为 Bicep 模块,再交由 Aspire 的部署管线执行。
二、快速开始:前置条件与安装集成
2.1 前置条件
- 一个 Aspire AppHost 项目,以及可用的容器运行时(如 Docker),用于构建和运行容器镜像;
- 若要部署到 Azure:需要一个有权创建资源并分配角色的 Azure 订阅,并且已通过
az login完成 Azure CLI 登录。
2.2 添加集成
在 AppHost 目录下使用 Aspire CLI 添加集成包:
aspire add Aspire.Hosting.Azure.AppContainers添加完成后,AppHost 项目中即可引用Aspire.Hosting.Azure.AppContainers命名空间下(对外暴露于Aspire.Hosting命名空间)的扩展方法。
三、最小可用示例:一个环境 + 一个 Web 应用
README 给出的最小示例用核心AddDockerfileAPI 声明一个 HTTP 应用(监听8080端口),并放入一个名为env的 Container Apps 环境。前提是 AppHost 目录下存在web子目录,其中包含构建该 HTTP 应用的 Dockerfile。
C#(AppHost/Program.cs)
using Aspire.Hosting; var builder = DistributedApplication.CreateBuilder(args); builder.AddAzureContainerAppEnvironment("env"); builder.AddDockerfile("web", "web") .WithHttpEndpoint(targetPort: 8080) .WithExternalHttpEndpoints(); builder.Build().Run();TypeScript(apphost.mts)
import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); await builder.addAzureContainerAppEnvironment("env"); await builder.addDockerfile("web", "web") .withHttpEndpoint({ targetPort: 8080 }) .withExternalHttpEndpoints(); await builder.build().run();3.1 行为要点
- 自动归属:当解决方案中存在一个环境时,受支持的计算资源会被自动分配到该环境,无需显式指定;
PublishAsAzureContainerApp是可选的:它只用于"定制"生成的 Container App(见下文第五节)。如果无需定制,声明 Dockerfile/项目后就会自动以默认方式发布;- 默认内网:HTTP 端点默认是内部(internal)的,
WithExternalHttpEndpoints显式把该 Web 应用纳入公共入站(ingress)流量; - 本地运行不预配:本地
dotnet run时不会创建真实的 Container Apps 环境(源码中AddAzureContainerAppEnvironment在 Run 模式下仅返回资源构建器,不把资源加入模型,见 AzureContainerAppExtensions.cs)。
从实现看,AddAzureContainerAppEnvironment("env")会同步创建默认的 Azure Container Registry(命名为env-acr)并绑定到环境(AzureContainerAppExtensions.cs),后续发布的计算资源镜像都推送到该注册表。
四、AddAzureContainerAppEnvironment的默认基础设施模型
调用AddAzureContainerAppEnvironment(name)时,Aspire 会在生成 Bicep 时自动预配以下整套 Azure 基础设施(见 AzureContainerAppExtensions.cs):
| 资源 | 默认命名 | 说明 |
|---|---|---|
| Azure Container Registry | {env}-acr | 存放所有容器镜像,同时输出AZURE_CONTAINER_REGISTRY_NAME/AZURE_CONTAINER_REGISTRY_ENDPOINT |
| User-Assigned 托管标识 | {env}_mi | 用于从 ACR 拉取镜像(AcrPull),输出AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID |
| ACR AcrPull 角色分配 | — | 将ContainerRegistryBuiltInRole.AcrPull授予上述标识 |
| Log Analytics 工作区 | {env}_law | Sku 为PerGB2018,供环境日志收集,输出AZURE_LOG_ANALYTICS_WORKSPACE_NAME/AZURE_LOG_ANALYTICS_WORKSPACE_ID |
| Container App 托管环境 | {env} | Workload Profiles 默认仅含Consumption档;日志目标为 log-analytics |
| Aspire Dashboard 组件 | aspire-dashboard | 类型AspireDashboard,版本2025-10-02-preview,默认启用 |
4.1 关键输出参数
环境模块统一输出以下标准参数,供下游 Container App 与 azd 消费(见AddSharedContainerAppEnvironmentOutputs,AzureContainerAppExtensions.cs):
AZURE_CONTAINER_REGISTRY_NAMEAZURE_CONTAINER_REGISTRY_ENDPOINTAZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_IDAZURE_CONTAINER_APPS_ENVIRONMENT_NAMEAZURE_CONTAINER_APPS_ENVIRONMENT_IDAZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN(azd 输出 Dashboard 地址时使用)
4.2 每个 Container App 的构建流程
AzureContainerAppEnvironmentResource注册了两个管线步骤:prepare-azure-container-apps-{name}(在 BeforeStart 阶段为所有计算资源物化部署目标)和可选的print-dashboard-url-{name}(部署成功后打印 Dashboard 地址),见 AzureContainerAppEnvironmentResource.cs。
对每个计算资源,ContainerAppEnvironmentContext.CreateContainerAppAsync会创建对应的ContainerAppContext(ContainerAppEnvironmentContext.cs),随后在ContainerAppContext.BuildContainerApp中完成:
- 解析所有端点并生成 ingress 配置;
- 注入环境变量与命令行参数(含密钥映射);
- 若资源带有
AppIdentityAnnotation,为 Container App 附加用户分配的托管标识; - 挂载卷(Azure Files 存储);
- 映射探针(Startup/Readiness/Liveness);
- 最后执行用户通过
PublishAsAzureContainerApp提供的定制回调。
五、发布计算资源:Project / Container / Executable 三种载体
当解决方案中有多个环境,或需要对默认生成的 Container App 做定制时,使用PublishAsAzureContainerApp。该系列 API 有三个重载,分别面向不同类型的资源:
项目资源(ProjectResource)
builder.AddProject<Projects.Api>() .PublishAsAzureContainerApp((infrastructure, app) => { // 在这里定制生成的 ContainerApp });容器资源(ContainerResource)
builder.AddContainer("name", "image") .PublishAsAzureContainerApp((infrastructure, app) => { // 例如配置自定义环境变量、缩放规则等 });可执行程序资源(ExecutableResource,通常与 Dockerfile 配合)
builder.AddDockerfile("web", "web") .PublishAsAzureContainerApp((infrastructure, app) => { // 定制 ContainerApp });5.1 实现要点
从源码看,这三个扩展方法的行为完全一致(AzureContainerAppProjectExtensions.cs):
- 仅在发布模式生效:
if (!project.ApplicationBuilder.ExecutionContext.IsPublishMode) return project;——本地运行(run 模式)时调用该方法不会产生任何副作用; - 调用
AddAzureContainerAppsInfrastructureCore()注册基础设施(幂等,多次调用只注册一次全局校验步骤,见 AzureContainerAppExtensions.cs); - 把定制回调封装为
AzureContainerAppCustomizationAnnotation标注附加到资源上,最终在ContainerAppContext.BuildContainerApp末尾执行(ContainerAppContext.cs)。
5.2 项目资源的默认行为
- 对 .NET 项目,Aspire 默认启用
AutoConfigureDataProtection(需要2025-10-02-preview资源版本),见 ContainerAppContext.cs; - 对带
AzureFunctionsAnnotation的资源,默认将Kind设为Functionapp,适配 Azure Functions 部署。
六、端点与入站流量控制
6.1 HTTP 端点默认升级为 HTTPS
默认情况下,环境会把所有 HTTP 端点升级为 HTTPS(443 端口)。原因在源码注释中说明:HTTP 到 HTTPS 的重定向会破坏 WebSocket 升级(ContainerAppContext.cs)。部署时日志会汇总被升级的端点(如web:http),提示可通过.WithHttpsUpgrade(false)关闭(ContainerAppEnvironmentContext.cs)。
关闭 HTTPS 升级(保留 HTTP 80)
builder.AddAzureContainerAppEnvironment("env") .WithHttpsUpgrade(upgrade: false);注意:即便关闭升级,显式指定的开发端口(如 8080)仍会按 Azure Container Apps 的要求规范化为标准端口 80/443(见 AzureContainerAppExtensions.cs 的 XML 注释)。
6.2 端点类型约束
ContainerAppContext.ProcessEndpoints会校验端点定义(ContainerAppContext.cs):
- 仅支持
http、http2、tcp三种传输层协议,其他传输会抛出NotSupportedException; - 最多一个外部端点,且外部端点必须为 HTTP(S)(外部 TCP 端点不支持);
- 同一目标端口上不允许混用 HTTP 与 TCP;
- 有多个 HTTP 端点时,优先选择外部端点作为 ingress,其余作为附加 TCP 端口映射(
AdditionalPortMappings,内网); - 附加端口超过 5 个时会输出警告(参考 Azure 关于 TCP ingress 的文档)。
6.3 内部/外部地址表达式
环境实现了GetHostAddressExpression,为内部端点生成<name>.internal.<domain>形式的地址、外部端点生成<name>.<domain>形式(AzureContainerAppEnvironmentResource.cs),应用之间可通过标准 Aspire 端点引用互访。
七、命名约定:azd 对齐、唯一命名与紧凑命名
当应用最初由 azd 部署、或需要把多个环境部署到同一资源组时,命名策略至关重要。源码中针对 managed environment 名称做了专门的碰撞防护(详见 AzureContainerAppExtensions.cs 及 ManagedEnvironmentNameResolver)。
7.1 WithAzdResourceNaming
让环境资源与 azd 使用完全相同的命名约定,从而复用 azd 已部署的资源:
builder.AddAzureContainerAppEnvironment("env") .WithAzdResourceNaming();启用后,托管环境命名为cae-${uniqueString(resourceGroup().id)},标识为mi-${resourceToken}、注册表为acr-…、Log Analytics 为law-${resourceToken}(AzureContainerAppExtensions.cs)。
7.2 WithUniqueResourceNaming
解决同一资源组内多个环境命名塌缩的问题。默认情况下 Azure.Provisioning 对ContainerAppManagedEnvironment只保留小写字母,cae1与cae2会被清洗成同一个cae,进而碰撞到同一个物理环境(对应 issue #18722)。启用该方法后,名称算法改为"清洗后的资源名 + 连字符 + uniqueString,截断到 60 字符",例如cae1生成take('cae1-${uniqueString(resourceGroup().id)}', 60),保留数字从而区分彼此:
var env1 = builder.AddAzureContainerAppEnvironment("cae1").WithUniqueResourceNaming(); var env2 = builder.AddAzureContainerAppEnvironment("cae2").WithUniqueResourceNaming();该方法为可选(opt-in),因为它会改变已部署单环境的名称并导致 Azure 重建环境;通常只对"多个环境共享一个资源组"的部署使用,或用于全新部署。若两个环境最终解析到相同名称,publish/deploy 阶段会以明确的错误提示要求调用此方法。
7.3 WithCompactResourceNaming
针对卷相关存储资源(Storage Account / File Share)的命名优化。默认生成的名称使用较长的静态后缀(如storageVolume、managedStorage),会吃掉存储账号 24 字符名称上限的大部分空间,截断提供跨部署唯一性的uniqueString。启用后缩短静态部分,完整保留 13 字符的uniqueString,避免向不同资源组部署多个环境时发生命名冲突:
builder.AddAzureContainerAppEnvironment("env") .WithCompactResourceNaming();该方法仅影响卷相关存储资源的命名,不改变托管环境、注册表、Log Analytics 或托管标识的名称;该 API 带有Experimental("ASPIREACANAMING001")实验性标记,接口可能在未来版本调整。
八、高级定制选项
8.1 控制 Aspire Dashboard
环境中默认附带 Aspire Dashboard(aspire-dashboard组件,2025-10-02-preview)。可通过以下方式开关:
builder.AddAzureContainerAppEnvironment("env") .WithDashboard(enable: false); // 默认 true部署后 Dashboard 地址为https://aspire-dashboard.ext.<default-domain>,仅在 Dashboard 启用时才会注册打印 URL 的摘要步骤(AzureContainerAppEnvironmentResource.cs)。
8.2 使用现有的 Log Analytics 工作区
默认环境会新建{env}_law工作区。若希望复用已有工作区:
builder.AddAzureLogAnalyticsWorkspace("logs"); builder.AddAzureContainerAppEnvironment("env") .WithAzureLogAnalyticsWorkspace(logsBuilder);实现上通过AzureLogAnalyticsWorkspaceReferenceAnnotation标注引用现有工作区(AzureContainerAppExtensions.cs)。
8.3 自定义 ACR 拉取身份(WithAcrPullIdentity)
默认环境会创建新的用户分配标识并授予 AcrPull。若希望使用自己提供的用户分配标识(例如配合AsExisting复用既有资源,且不产生任何新的标识/角色资源):
builder.AddAzureUserAssignedIdentity("acrPullIdentity") .WithRoleAssignments(acr, ContainerRegistryBuiltInRole.AcrPull); builder.AddAzureContainerAppEnvironment("env") .WithAcrPullIdentity(acrPullIdentityBuilder);注意:该方法中的标识仅用于 ACR 拉取(AcrPull 角色),并不会被附加到环境中的单个 Container App 上;调用方需自行保证该标识已具备 AcrPull 权限(AzureContainerAppExtensions.cs)。
8.4 引用已存在的环境(AsExisting / PublishAsExisting)
当环境被标记为AsExisting时,Aspire 不会生成新的托管环境、Log Analytics 工作区或 Dashboard 组件,而是生成一个引用现有环境的薄模块,并只补充新部署 Container App 所需的 ACR 拉取标识(AzureContainerAppExtensions.cs)。此时以下组合不被允许,会直接抛错:
- 声明了卷挂载(卷需要在托管环境上预配存储);
- 通过
WithDelegatedSubnet配置了 VNet 集成(VNet 是环境自身的属性,无法对已存在环境重新配置); - 通过
WithAzureLogAnalyticsWorkspace指定工作区(已存在环境已拥有自己的日志工作区)。
8.5 卷挂载与探针
- 卷:资源通过标准挂载 API(BindMount / Volume)声明后,环境会自动创建 Storage Account(StandardLRS、StorageV2、启用大文件共享、最低 TLS 1.2)与 Azure Files 文件共享,并以
ContainerAppManagedEnvironmentStorage(AzureFile,读写模式)挂载到环境(AzureContainerAppExtensions.cs); - 探针:
ContainerAppContext.AddProbes会把ProbeAnnotation(Startup/Readiness/Liveness)映射为 ACA 探针;关联到 ingress 端点的探针强制使用http协议、目标端口(BaseContainerAppContext.cs)。
8.6 环境变量与密钥
BaseContainerAppContext.ProcessValue负责把值转换为 Bicep 表达式(BaseContainerAppContext.cs):
- 普通字符串直接作为环境变量值;
- 端点引用解析为容器应用域名地址;
ParameterResource若标记为 Secret,则注册为 Container App 密钥(SecretRef),密钥名由_转-并小写;- Key Vault 引用注册为 Key Vault 密钥引用,并可选附加标识用于访问;
- 不支持的引用类型(如自动 Key Vault 生成)会明确抛错,提示手动创建 Key Vault 资源。
九、发布与部署:publish / deploy / destroy 完整闭环
9.1 aspire publish:生成部署产物(不触碰 Azure)
aspire publish- 生成 Bicep 模板与参数化的部署产物,但不会预配任何 Azure 资源;
- 产物默认写入 AppHost 的
aspire-output目录; - 交互式部署过程中可提示选择订阅、位置与资源组。
9.2 aspire deploy:实际预配与部署
aspire deploy- 解析 Azure 设置与参数;
- 预配 Container Apps 环境及其默认容器注册表;
- 构建并推送镜像;
- 部署应用。
9.3 aspire destroy:清理
aspire destroy注意:该命令会删除整个部署资源组,包括并非由 Aspire 创建的资源!请仅在确认无误后执行。
9.4 安全提示
- 本地运行不会预配 Container Apps 环境;
- 部署后的应用通过托管标识(managed identity)拉取镜像,不依赖明文凭证;
- 敏感配置应放在 secret 参数或 Azure Key Vault 引用中,而不是明文环境变量。
十、测试验证与延伸阅读
该集成的行为在仓库中有较完整的测试覆盖,可作为自定义配置时的参考依据:
- AzureContainerAppEnvironmentExtensionsTests.cs:覆盖环境资源默认生成、
WithAzdResourceNaming/WithCompactResourceNaming/WithUniqueResourceNaming命名策略、AsExisting引用现有环境等场景; - AzureContainerAppsTests.cs:覆盖 Container App 发布与 Bicep 生成。
更多相关背景可继续阅读仓库内文档:docs/specs/aks-support.md(多计算环境编排的设计背景)、docs/azure.md(Azure 相关概览)。若需在生产中落地,请以当前仓库版本的 API 签名与实验性标记为准(部分命名 API 标有Experimental特性,后续版本可能调整)。
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考