ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

.NET Aspire 集成 Azure App Service 实战:环境建模、Web App 发布与基础设施编排

.NET Aspire 集成 Azure App Service 实战:环境建模、Web App 发布与基础设施编排 .NET Aspire 集成 Azure App Service 实战环境建模、Web App 发布与基础设施编排【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire本文围绕开源仓库中 Aspire.Hosting.Azure.AppService 集成文档 展开系统讲解如何在 .NET Aspire 方案AppHost中为计算资源建模、配置并编排 Azure App Service从安装集成、编写 AppHost 代码到 App Service 的部署约束、虚拟网络集成、Application Insights 与 App Service Plan 的自定义。读完本文你将掌握AddAzureAppServiceEnvironment与PublishAsAzureAppServiceWebsite的完整用法并理解底层基础设施的生成逻辑与校验机制能够直接在自己的 Aspire 方案中落地 Azure App Service 发布。集成概览在 Aspire 中编排 Azure App ServiceAspire.Hosting.Azure.AppService是一个 Aspire Hosting 集成用于在 Aspire 方案中对 Azure App Service 进行建模、配置与编排让应用的计算资源如项目、容器可以发布为 Azure App Service Web App。它的核心价值在于以声明式代码AppHost 中的 C#描述我要一个 App Service 环境 若干 Web App而不是手写 Bicep 模板由 Aspire 自动生成配套的 Azure 基础设施App Service Plan、容器注册中心、托管标识、可选 Dashboard 与 Application Insights与 Aspire 的部署流水线pipeline深度集成负责镜像推送、基础设施预配、部署与结果汇总。该集成源码位于 src/Aspire.Hosting.Azure.AppService核心公开 API 可查看 api/Aspire.Hosting.Azure.AppService.cs。入门前置条件与安装集成前置条件一个Azure 订阅并且对目标订阅拥有Owner 权限用于角色分配例如 ACR Pull 角色、Website Contributor 角色等这些角色由 Aspire 在预配过程中自动创建。安装集成在 AppHost 目录下使用 Aspire CLI 添加集成aspire add Aspire.Hosting.Azure.AppService该命令会把集成包引用写入 AppHost 项目之后即可在Program.cs中使用相关扩展方法。快速上手一个完整的使用示例在 AppHost 中先添加一个Azure App Service 环境AzureAppServiceEnvironment再把计算资源发布为 Web Appvar builder DistributedApplication.CreateBuilder(args); var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env); builder.AddProjectProjects.MyWebApp(webapp) .WithExternalHttpEndpoints() .PublishAsAzureAppServiceWebsite((infrastructure, website) { // Customize the App Service health check path and appsettings website.SiteConfig.HealthCheckPath /health; website.SiteConfig.AppSettings.Add(new AppServiceNameValuePair() { Name Environment, Value Production }); });说明AddAzureAppServiceEnvironment(env)创建环境资源详见下文环境资源与默认基础设施WithExternalHttpEndpoints()声明外部 HTTP 端点——这是 App Service 的硬性要求PublishAsAzureAppServiceWebsite的configure回调接收AzureResourceInfrastructure与WebSiteAzure Provisioning SDK 类型可在其中直接修改 Web App 的站点配置如健康检查路径、应用设置等。从源码看PublishAsAzureAppServiceWebsiteAzureAppServiceComputeResourceExtensions.cs支持两个可选回调configure定制WebSite与configureSlot定制部署槽WebSiteSlot并且仅在发布模式IsPublishMode下生效本地运行run 模式时调用它不会产生副作用。Azure App Service 约束部署前必须了解把资源发布到 Azure App Service 时以下约束由平台决定Aspire 会在代码生成阶段强制校验仅支持外部端点External endpoints onlyApp Service 只支持外部端点所有端点必须通过WithExternalHttpEndpoints()配置。仅支持 HTTP/HTTPS其他协议如 gRPC、TCP不被支持。源码 AzureAppServiceWebsiteContext.cs 中若解析到的端点UriScheme不是http或https会抛出NotSupportedException。单一端点Single endpointApp Service 只支持一个目标端口。带不同目标端口的多个外部端点不被支持。默认目标端口为8000可通过WithHttpEndpoint扩展方法覆盖builder.AddProjectProjects.Api(api) .WithHttpEndpoint(targetPort: 8080)在 AzureAppServiceWebsiteContext.cs 中Aspire 会收集所有外部端点的目标端口并去重若出现多于一个不同端口直接抛出App Service does not support resources with multiple external endpoints异常。此外非外部端点也会被拒绝App Service only supports external endpoints。将计算资源发布为 Azure App Service Web AppPublishAsAzureAppServiceWebsite扩展方法把计算资源配置为部署到 Azure 时发布为 App Service Web App。该方法允许你通过Azure Provisioning SDK自由定制 Web App 的配置。更完整的定制示例builder.AddProjectProjects.Api(api) .WithHttpEndpoint(targetPort: 8080) .WithExternalHttpEndpoints() .WithHealthProbe(ProbeType.Liveness, /health) .WithArgs(--environment, Production) .PublishAsAzureAppServiceWebsite((infrastructure, website) { // Customize the App Service Web App appsettings website.SiteConfig.IsWebSocketsEnabled true; website.SiteConfig.MinTlsVersion SupportedTlsVersions.Tls1_2; });这个示例展示了几个在 App Service 场景下常用的链式调用WithHttpEndpoint(targetPort: 8080)覆盖默认目标端口默认 8000WithHealthProbe(ProbeType.Liveness, /health)声明存活探针。从源码看AzureAppServiceWebsiteContext.cs 会把探针注解转换为SiteConfig.HealthCheckPath且由于 App Service 只允许一个健康检查路径Aspire 会优先选择 Liveness 探针否则取第一个WithArgs(--environment, Production)命令行参数。App Service 不支持数组形式的启动参数AzureAppServiceWebsiteContext.cs 会把参数 join 成单个字符串写入主容器的StartUpCommand回调内通过website.SiteConfig直接修改IsWebSocketsEnabled、MinTlsVersion等站点级设置。关于环境变量连字符校验与跳过Azure App Service 在运行时会移除环境变量名中的-连字符这会导致连接字符串等含连字符名称的配置键被改写从而让 Aspire 客户端集成找不到预期的连接字符串。因此Aspire 在发布流水线中默认执行校验任何名称含-的环境变量都会使发布失败并给出可读的错误提示包括受影响设置清单与修复建议。对应的校验逻辑位于 AzureAppServiceEnvironmentResource.cs其给出两种修复方式在 AppHost 中为引用使用不含连字符的连接名称例如WithReference(resource, connectionName: mydb)对确实需要保留连字符名称的资源调用SkipEnvironmentVariableNameChecks()跳过校验builder.AddProjectProjects.Api(api) .WithExternalHttpEndpoints() .PublishAsAzureAppServiceWebsite(configure: (_, _) { }) .SkipEnvironmentVariableNameChecks();从源码看SkipEnvironmentVariableNameChecksAzureAppServiceComputeResourceExtensions.cs要求必须先调用PublishAsAzureAppServiceWebsite否则抛出InvalidOperationException。测试 tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs 中同时覆盖了含连字符连接名导致校验失败与调用SkipEnvironmentVariableNameChecks后校验通过两条路径。环境资源与默认基础设施AddAzureAppServiceEnvironment创建的 App Service 环境资源会生成托管应用所需的底层基础设施包括一个Azure App Service Plan默认 SKUP0v3Premium 层级一个Azure Container RegistryACR用于存放容器镜像一个用于访问容器注册中心的托管标识managed identity可选的Aspire Dashboard默认启用以 App Service Web App 形式部署可选的Application Insights用于监控与遥测。var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env);从源码看AzureAppServiceEnvironmentExtensions.cs 的实现细节包括自动创建名为{name}-acr的默认 ACR创建UserAssignedIdentity{prefix}_mi并为其在 ACR 上分配AcrPull角色供 Web App 拉取镜像创建AppServicePlanP0V3/Premium/Linux并启用IsPerSiteScaling使每个 Web App 可以独立伸缩这也是后续NumberOfWorkers被设为 30 的原因见 AzureAppServiceWebsiteContext.cs通过 Provisioning Output 暴露环境级引用如AZURE_CONTAINER_REGISTRY_ENDPOINT、AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID等供每个 Web App 模块消费。关闭默认的 Aspire Dashboard默认情况下Aspire Dashboard 会包含在 App Service 环境中。使用WithDashboard扩展方法可以关闭它var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env) .WithDashboard(enable: false);Dashboard 被部署为kind app,linux,aspiredashboard的 Web App使用ASPIREDASHBOARD|1.0的 Linux 运行时见 AzureAppServiceEnvironmentUtility.cs。它同时承担两个职责其一复用环境的用户托管标识从 ACR 拉取自身镜像其二作为 OTLP 遥测的接收端——每个 Web App 都会通过WEBSITE_ENABLE_ASPIRE_OTEL_SIDECAR、OTEL_EXPORTER_OTLP_ENDPOINT指向本地 6001 端口的 OTLP sidecar与OTEL_EXPORTER_OTLP_CLIENT_ID等应用设置把遥测发送到 Dashboard见 AzureAppServiceWebsiteContext.cs。配置区域虚拟网络集成Regional VNet Integration要让环境中的 Web App 使用区域虚拟网络集成需要先添加Aspire.Hosting.Azure.Network集成aspire add Aspire.Hosting.Azure.Network然后创建虚拟网络与子网并将其委托给环境#pragma warning disable ASPIREAZURE003 // Azure Virtual Network APIs are experimental. var vnet builder.AddAzureVirtualNetwork(vnet); var subnet vnet.AddSubnet(app-service-subnet, 10.0.0.0/24); var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env) .WithDelegatedSubnet(subnet); #pragma warning restore ASPIREAZURE003TypeScriptPolyglot AppHost版本const vnet await builder.addAzureVirtualNetwork(vnet); const subnet await vnet.addSubnet(app-service-subnet, 10.0.0.0/24); const appServiceEnvironment await builder.addAzureAppServiceEnvironment(env) .withDelegatedSubnet(subnet);要点WithDelegatedSubnet会把子网委托给Microsoft.Web/serverFarms并让环境中生成的每一个 Web App、部署槽deployment slot以及默认的 Aspire Dashboard 都使用该子网进行区域虚拟网络集成子网必须满足 Azure App Service 区域虚拟网络集成的要求地址空间、大小等参见 Aspire.Hosting.Azure.Network 集成文档区域虚拟网络集成只影响出站流量它不会让 Web App 或 Dashboard 的入站访问变成私有也不会启用 Route All。如果需要私有入站、访问限制或 Route All需要另行配置私有端点private endpoints或访问限制access restrictions。从实现上看环境资源实现了IAzureDelegatedSubnetResource接口其委托服务名正是Microsoft.Web/serverFarms见 AzureAppServiceEnvironmentResource.cs生成的每个站点会把子网 ID 写入VirtualNetworkSubnetId。相关测试见 tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs覆盖有无部署槽两种场景以及AddAppServiceWithDelegatedSubnet系列用例。启用 Application Insights使用WithAzureApplicationInsights扩展方法可为 App Service 环境启用 Application Insights。可选地通过 location 参数为 Application Insights 指定不同的位置var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env) .WithAzureApplicationInsights();从源码看AzureAppServiceEnvironmentExtensions.cs 提供了多个重载实际使用时可灵活选用重载形式说明WithAzureApplicationInsights()使用默认位置资源组位置Aspire 自动创建 Log Analytics 工作区PerGB2018SKU Application Insights 组件WithAzureApplicationInsights(string location)指定 Application Insights 的位置字符串WithAzureApplicationInsights(IResourceBuilderParameterResource location)通过参数资源指定位置WithAzureApplicationInsights(IResourceBuilderAzureApplicationInsightsResource insights)复用已存在的 Application Insights 资源启用后每个生成的 Web App及部署槽会自动追加APPINSIGHTS_INSTRUMENTATIONKEY、APPLICATIONINSIGHTS_CONNECTION_STRING与ApplicationInsightsAgent_EXTENSION_VERSION~3等应用设置见 AzureAppServiceWebsiteContext.cs。自定义 App Service PlanSKU 与层级App Service Plan 可以使用ConfigureInfrastructure扩展方法进行自定义。默认 SKU 为P0V3Premium可通过以下方式修改var appServiceEnvironment builder.AddAzureAppServiceEnvironment(env) .ConfigureInfrastructure((infra) { var plan infra.GetProvisionableResources().OfTypeAppServicePlan().Single(); plan.Sku new AppServiceSkuDescription { Name P2V3, Tier Premium }; });要点infra.GetProvisionableResources()返回环境中所有待预配的 Azure 资源从中筛选出唯一的AppServicePlan实例通过plan.Sku可以修改 SKU 名称与层级例如从 P0V3 升到 P2V3同时KindLinux、IsReserved、IsPerSiteScaling等属性也在此处管理见 AzureAppServiceEnvironmentExtensions.cs。注意计划启用IsPerSiteScaling后各 Web App 的NumberOfWorkers被设置为 Premium 系列允许的最大值30以保证 Web App 可以按计划自身定义正常伸缩。部署流水线从代码到 Azure 的关键步骤理解 Aspire 如何编排App Service 发布有助于排查部署问题。从 AzureAppServiceEnvironmentResource.cs 与 AzureAppServiceWebSiteResource.cs 可以看到流水线的核心步骤prepare-azure-app-service-{name}为环境中的每个计算资源物化部署目标DeploymentTargetAnnotation即把ProjectResource或带 Dockerfile 的容器资源转换为AzureAppServiceWebSiteResource并注入环境上下文validate-appservice-config-{name}在发布前校验配置重点是环境变量名校验连字符问题错误会通过活动报告器activity reporter以CompletedWithError状态呈现deploy-{resource}聚合步骤保证推送容器镜像PushContainerImage→ 预配基础设施ProvisionInfrastructure→ 部署的依赖顺序print-{resource}-summary输出部署结果包括最终 URLhttps://{website-name}.azurewebsites.net与 Azure 门户链接print-dashboard-url-{name}若启用了 Dashboard输出 Dashboard 地址。此外环境默认会把 HTTP 端点自动升级为 HTTPS这也是为什么 App Service 平台本身会强制 HTTP→HTTPS 重定向禁用升级主要影响的是为下游依赖生成的连接字符串中的 scheme 与端口。如需保留 HTTP 端点可在环境上使用WithHttpsUpgrade(false)var appService builder.AddAzureAppServiceEnvironment(appservice) .WithHttpsUpgrade(false);升级行为与端口映射的底层逻辑见 AzureAppServiceEnvironmentResource.cs升级后 URL 使用https与端口 443保留 HTTP 时使用http与端口 80。更多进阶能力除本文覆盖的内容外该集成还提供了以下能力详见 AzureAppServiceEnvironmentExtensions.csWithDeploymentSlot为环境中所有 App Service 指定部署槽deployment slot支持字符串或参数资源两种形式。配置槽后Aspire 会同时生成主站点带onlyIfNotExists()保护与槽资源并把端点引用、OTEL_SERVICE_NAME等设置为粘性槽设置sticky slot settings避免槽交换时配置被覆盖WithAcrPullIdentity复用已有的用户分配托管标识作为 ACR Pull 标识需自行保证该标识已具备 ACR 的AcrPull角色适用于向预先预配好的 App Service Plan ACR 部署的场景避免 Aspire 额外生成新的标识与角色分配资源。测试验证集成行为有据可查该集成的行为在 tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs 中有大量测试覆盖可作为理解与排错时的参考AddAppServiceWithDelegatedSubnet/AddAppServiceWithDelegatedSubnetWithoutDeploymentSlot验证子网委托与生成的 BicepPublishAsAzureAppServiceWebsite_CanOverrideEnvironmentDelegatedSubnet验证 Web App 级别可覆盖环境的子网配置PublishToAppService_WithDashedConnectionStringName_FailsValidationInPipeline/_CanBeIgnored验证连字符环境变量名校验及跳过机制KeyvaultReferenceHandling验证环境变量中 Key Vault 密钥引用会被转换为Microsoft.KeyVault(...)形式的 App Service 应用设置EndpointReferencesAreResolvedAcrossProjects验证跨项目端点引用在 App Service 环境中的解析AddDockerfileWithAppServiceInfrastructureAddsDeploymentTargetWithAppServiceToContainerResources验证带 Dockerfile 的容器资源同样支持发布为 Web App。总结Aspire.Hosting.Azure.AppService让开发者用纯代码方式完成 Azure App Service 的建模与发布一条AddAzureAppServiceEnvironment声明环境一条PublishAsAzureAppServiceWebsite把项目或容器发布为 Web App其余的基础设施生成、镜像推送、配置注入、校验与部署汇总都由 Aspire 接管。需要进一步探索源码时可重点阅读AzureAppServiceComputeResourceExtensions.csPublishAsAzureAppServiceWebsite与SkipEnvironmentVariableNameChecks的公开 APIAzureAppServiceEnvironmentExtensions.csAddAzureAppServiceEnvironment及全部配置扩展方法AzureAppServiceEnvironmentResource.cs环境资源模型、校验与流水线步骤AzureAppServiceWebsiteContext.cs单个 Web App 的端点、环境变量、参数、探针与遥测配置生成逻辑。【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进