尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

在 Windows Azure App Service 上部署 Orleans 集群:购物车示例的完整实战指南

在 Windows Azure App Service 上部署 Orleans 集群:购物车示例的完整实战指南 后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载本指南基于 Orleans 官方仓库中的 Windows Azure App Service 部署教程与配套的 Shopping Cart 示例示例目录系统讲解如何把一个应用进程 Orleans Silo共置cohosted的多实例集群部署到 Windows App Service并利用区域虚拟网络集成、每实例私有 TCP 端口、Azure Table Storage 集群/状态存储、用户托管标识managed identity、Easy Auth 与部署槽slot滚动发布最终形成一套可直接复制到生产环境的完整 DevOps 流水线。读完本文你将掌握App Service 上 Orleans 私有网络拓扑的搭建原理、Bicep 基础设施的每一处关键配置、手动发布与 GitHub Actions OIDC 自动化的完整操作以及健康检查、优雅关闭与生产就绪检查清单。理解拓扑为什么 App Service 的 HTTP 负载均衡不能满足 OrleansOrleans 的 Silo 之间通过长连接 TCP直接互连集群成员需要相互访问对方广告的 Silo 端点。App Service 前端的 HTTP 负载均衡只转发 HTTP 流量无法提供这种粒度的 TCP 直连因此示例采用以下方式解决区域虚拟网络集成Regional virtual network integration每个 worker 获得一个私有地址由平台注入到只读环境变量WEBSITE_PRIVATE_IP。每实例私有端口分配在站点配置中设置vnetPrivatePortsCount: 1见 app-service.bicepApp Service 会为每个 worker 动态分配一个端口写入逗号分隔的WEBSITE_PRIVATE_PORTS。示例取其中第一个端口作为 Silo 端口。Silo 命名使用只读的WEBSITE_INSTANCE_ID作为 Orleans Silo 名称便于在诊断时把集群成员映射回具体 worker 实例。在此基础上应用进程在启动时Program.cs 的ConfigureProductionOrleans完成四件事从WEBSITE_PRIVATE_IP解析私有 IP、从WEBSITE_PRIVATE_PORTS解析首个端口作为对外广告的 Silo 端点通过ConfigureEndpoints(privateIp, siloPort, gatewayPort: 0, listenOnAnyHostAddress: true)监听所有本地接口——因为广告地址可能不是本地可绑定的地址关闭 Orleans 客户端网关gatewayPort: 0因为共置的 Web 应用直接使用 Silo 的本地客户端使用 Azure Table Storage 作为外部集群提供程序和持久化 Grain 存储。// samples/Deployment/AzureAppService/Silo/Program.cs 中的 ConfigureProductionOrleans .ConfigureSiloOptions(options { options.SiloName builder.Configuration[WEBSITE_INSTANCE_ID] ?? Environment.MachineName; }) .ConfigureEndpoints( privateIp, siloPort, gatewayPort: 0, listenOnAnyHostAddress: true) .UseAzureStorageClustering(options { options.TableServiceClient tableServiceClient; options.TableName ${clusterId}Clustering; }) .AddAzureTableGrainStorage( shopping-cart, options { options.TableServiceClient tableServiceClient; options.TableName ${clusterId}Persistence; });拓扑中的两个关键约束约束一全连通full mesh。每个 Silo 都必须能到达所有广告出来的 Silo 端点因此放大到 3 个以上 worker 后务必在生产前验证每个 worker 都拿到了私有 Silo 端口、且能与每个广告端点建立 TCP 连接。虚拟网络集成本质上是出站特性私有端口的入站行为必须实测。约束二网关不是认证边界。关闭网关保证了目录变更只能经由受 Easy Auth 保护的 Web 应用进入而无法通过一条未认证的 Orleans 客户端连接完成。若业务确实需要外部 Orleans 客户端只能为完全可信的应用客户端再分配并广告第二个私有端口不可信客户端必须留在经过认证的 API 之后并在修改 Grain 状态的每个操作上强制授权。[!IMPORTANT] 区域虚拟网络集成主要是出站功能。在扩缩容的生产计划上验证私有端口行为确认每个 worker 都获得私有 Silo 端口并能连接所有广告端点。子网容量应选用支持虚拟网络集成和部署槽的专用层级如 Premium v3。每个集成子网至少按计划最大规模的 2 倍规划新部署建议/26起步为替换 worker 留出空间。示例在 flex/main.bicep 中为生产与暂存各建了一个/24的委托子网Microsoft.Web/serverFarms委托并分别挂上Microsoft.Storage服务终结点。前置条件与本地运行开始前准备一个 Azure 订阅且具备创建资源和角色分配的权限与仓库根目录 global.json 选定的 .NET SDK 匹配的 SDK 版本示例发布目标为net10.0DOTNETCORE|10.0、v10.0、net10.0都是部署字面量不代表 Orleans 产品版本号带 Bicep 的 Azure CLI一份仓库克隆git clone本仓库后进入 samples/Deployment/AzureAppService一个用于 App Service Authentication 的 Microsoft Entra 应用注册。先在本地设置部署变量$location westus3 $resourceGroup orleans-shopping-cart $appName globally-unique-lowercase-name-up-to-16-characters $authenticationTenantId microsoft-entra-tenant-id $authenticationClientId app-registration-client-id $authenticationClientSecret app-registration-client-secretappName有 2–16 个小写字符的长度约束对应 Bicep 参数minLength(2) maxLength(16)见 windows/main.bicep。本地运行示例dotnet run --project .\samples\Deployment\AzureAppService\Silo\Orleans.ShoppingCart.Silo.csproj --environment ASPNETCORE_ENVIRONMENTDevelopment开发环境Development使用 localhost 集群和内存状态存储见 Program.cs。每个非开发环境都必须提供WEBSITE_PRIVATE_IP、WEBSITE_PRIVATE_PORTS、ORLEANS_SERVICE_ID、ORLEANS_CLUSTER_ID、ORLEANS_AZURE_STORAGE_URI、AZURE_CLIENT_ID六个设置缺少任一生产配置都会导致启动失败——GetRequiredSetting会直接抛出InvalidOperationException绝不会静默回退到单机生产集群。本地可以正常浏览匿名商店页面但产品管理不可用本地执行没有 App Service 注入的可信主体头X-MS-CLIENT-PRINCIPAL。配置用户认证Easy Auth ProductAdministrator 应用角色示例用 App Service AuthenticationEasy Auth保护目录变更操作认证模型如下在应用注册中新增一个值为ProductAdministrator的应用角色允许的成员类型包含用户或组创建一个客户端机密client secret通过企业应用把该角色分配给产品管理员添加以/.auth/login/aad/callback结尾的生产与暂存 Web 重定向 URI。由于确切的 hostname 是部署输出可以先部署基础设施、拿到 hostname 后再补重定向 URI在用户登录前完成即可。服务端如何消费可信主体头Easy Auth 允许匿名浏览商店但会把认证后的声明注入到X-MS-CLIENT-PRINCIPAL头。在非容器 Windows 应用上平台认证组件是进程内的原生 IIS 模块Linux 上则是 sidecar 容器两者注入的主体头契约一致。应用的认证处理器AppServiceAuthenticationHandler.cs实现了一套严格的解析逻辑只接受aadEntra身份提供方其余一律认证失败对头做长度限制MaximumHeaderLength 16 * 1024、Base64 解码、JSON 反序列化校验缺头返回NoResult任何一步解析失败都返回Fail不产生任何声明未认证访问受保护路由时挑战逻辑重定向到/.auth/login/aad?post_login_redirect_uri...完成登录回跳。// AppServiceAuthenticationHandler 的核心校验 if (header.Count ! 1 || string.IsNullOrWhiteSpace(header[0]) || header[0]!.Length MaximumHeaderLength) { return Task.FromResult(AuthenticateResult.Fail(The App Service principal header is invalid.)); }该解析器信任 App Service 已校验令牌并剥离伪造的外部身份头因此绝不能把它用在不可信的反向代理之后也不能暴露绕过路由直达应用进程。除处理器外应用还在三层做纵深防御保护/products路由、对未授权用户隐藏导航入口、在ProductService服务层对每次产品变更重新授权策略见 AuthorizationPolicies.cs要求RequireAuthenticatedUser()且具备ProductAdministrator角色。部署基础设施Bicep 模板逐层拆解登录 Azure、创建资源组然后部署 Windows 入口模板az login az group create --name $resourceGroup --location $location az deployment group create --resource-group $resourceGroup --template-file .\samples\Deployment\AzureAppService\infra\windows\main.bicep --parameters appName$appName location$location authenticationTenantId$authenticationTenantId authenticationClientId$authenticationClientId authenticationClientSecret$authenticationClientSecret入口模板 windows/main.bicep 只是薄壳默认serviceId ShoppingCartService、workerCount 3minValue(3)、assignStorageRoles true、allowSharedKeyAccess false然后调用共享模块infra/flex/main.bicep。Windows 与 Linux 共用同一套 flex 模块差异仅在计划类型与平台配置项。整个模板创建以下资源flex/main.bicep资源关键配置虚拟网络172.17.0.0/16192.168.0.0/16地址空间default172.17.0.0/24与staging192.168.0.0/24两个/24委托子网存储账户Standard_LRS、StorageV2allowSharedKeyAccess默认关闭、defaultToOAuthAuthentication: true、minimumTlsVersion: TLS1_2、publicNetworkAccess: Enabled但networkAcls.defaultAction: Deny仅放行两个集成子网的虚拟网络规则托管标识用户分配标识${appName}-identity并分配Storage Table Data Contributor角色App Service 计划P1v3capacity: workerCount3生产站点 暂存槽各自挂接独立委托子网、独立 Easy Auth 配置可观测性Log Analytics 工作区级 Application Insights站点配置里藏着 Orleans 运行的关键app-service.bicep 的commonSiteConfig同时应用于生产与暂存var commonSiteConfig { alwaysOn: true ftpsState: Disabled healthCheckPath: /health/ready http20Enabled: true minTlsVersion: 1.2 numberOfWorkers: workerCount vnetPrivatePortsCount: 1 webSocketsEnabled: true }vnetPrivatePortsCount: 1是每实例私有端口的开关直接决定WEBSITE_PRIVATE_PORTS是否注入alwaysOn: true保证 worker 常驻避免空闲回收导致 Silo 频繁离群healthCheckPath: /health/ready把 Orleans 就绪状态接入平台健康检查。共同应用设置commonAppSettings包括AZURE_CLIENT_ID托管标识客户端 ID、APPLICATIONINSIGHTS_CONNECTION_STRING、ASPNETCORE_FORWARDEDHEADERS_ENABLED、ORLEANS_AZURE_STORAGE_URI、ORLEANS_SERVICE_IDShoppingCartService以及三条暖机相关设置WEBSITE_HEALTHCHECK_MAXPINGFAILURES2、WEBSITE_SWAP_WARMUP_PING_PATH/health/ready、WEBSITE_WARMUP_PATH/health/ready。Windows 平台额外设置WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG1。生产与暂存集群隔离的关键设计生产站点与暂存槽的唯一设置差异是ORLEANS_CLUSTER_ID生产为Default暂存为Staging。slotConfigNames把三个设置标记为slot-sticky交换时不随之变更properties: { appSettingNames: [ AZURE_CLIENT_ID authenticationSecretSettingName // MICROSOFT_PROVIDER_AUTHENTICATION_SECRET ORLEANS_CLUSTER_ID ] }这意味着两个槽共享稳定的ShoppingCartService服务 ID但各自使用独立的集群表DefaultClustering/StagingClustering与状态表DefaultPersistence/StagingPersistence从物理上隔离了生产与暂存的成员关系与 Grain 状态。认证机密与引导部署认证客户端机密是secure()Bicep 参数并以 slot-sticky 应用设置MICROSOFT_PROVIDER_AUTHENTICATION_SECRET注入 Easy Auth 配置。首次部署是特权引导它要创建数据面角色分配storage-role.bicep 使用 Storage Table Data Contributor 角色定义 ID0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3为用户分配标识赋权因此执行者需要roleAssignments/write。日常部署传assignStorageRolesfalse就不再需要角色分配权限。注意托管标识的角色传播可能需要几分钟首次应用启动可能因标识尚未获得表数据访问权而失败这是预期现象稍后重试即可。发布并部署到暂存槽手动发布流程与仓库 README 的完整版一致$publish Join-Path $env:TEMP orleans-shopping-cart-publish $package Join-Path $env:TEMP orleans-shopping-cart.zip dotnet publish .\samples\Deployment\AzureAppService\Silo\Orleans.ShoppingCart.Silo.csproj --configuration Release --framework net10.0 --output $publish Compress-Archive -Path $publish\* -DestinationPath $package -Force az webapp deploy --name $appName --resource-group $resourceGroup --slot ${appName}stg --type zip --src-path $package --clean true --restart true两个细节值得注意ZIP 内容是发布目录的内容本身而不是发布目录。App Service 解压到 Windows 的D:\home\site\wwwrootLinux 为/home/site/wwwroot。示例不把持久数据写在这里——Orleans Grain 状态始终留在 Azure Table Storage。部署完成后把生产与暂存两个回调 URL 补进应用注册然后等待暂存部署输出的 hostname 就绪https://staging-default-hostname/health/ready交换到生产部署槽与 Orleans 升级策略az webapp deployment slot swap --name $appName --resource-group $resourceGroup --slot ${appName}stg --target-slot production交换期间App Service 会把生产设置应用到暂存但ORLEANS_CLUSTER_ID等 slot-sticky 设置除外对暂存每个 worker 执行暖机然后才切换流量。新 Silo 在切换前就已加入生产集群——这正是蓝绿并存的根源新旧 Silo 会短暂共存因此 Grain 接口、序列化载荷、状态与外部行为必须互相兼容对于不兼容的发布应部署独立的应用与集群 ID绝不允许不兼容的集群拥有同一份可变状态交换后暂存槽运行的是旧版本可用于快速回滚。配置 GitHub Actions 与 OIDC 持续部署将示例工作流 infra/deploy.yml 复制到.github/workflows/deploy-app-service.yml。为受保护的 GitHubproduction环境创建联邦部署标识配置合理的审查人、限制部署分支不要创建--sdk-auth凭据也不要把 Azure 凭据 JSON 文档存入仓库。配置以下 GitHub 环境变量变量用途AUTHENTICATION_CLIENT_IDApp Service Authentication 客户端 IDAUTHENTICATION_TENANT_ID用户认证所在的租户AZURE_APP_NAME全局唯一的 App Service 名称AZURE_APP_SERVICE_OSwindowsAZURE_CLIENT_ID联邦部署标识的客户端 IDAZURE_RESOURCE_GROUP_LOCATIONAzure 区域AZURE_RESOURCE_GROUP_NAME已存在的目标资源组AZURE_SUBSCRIPTION_ID订阅 IDAZURE_TENANT_IDAzure 部署所在租户AUTHENTICATION_CLIENT_SECRET以受保护的环境机密形式添加——它属于 Easy Auth 应用注册Azure 部署本身使用短时 OIDC 凭据与这个机密完全分离。工作流的关键特征对应 deploy.ymlactions 全部锁定到不可变提交 SHA如actions/checkout11d5960a...权限收敛到最小contents: read与id-token: write没有pull-requests: write等多余权限部署 Bicep 时显式传assignStorageRolesfalse allowSharedKeyAccessfalse因此日常 Azure 身份不需要角色分配权限——只需在目标资源组授予 Contributor或更佳授予仅限模板所涉资源的自定义角色流水线顺序publish → 部署基础设施 →az webapp deploy到暂存 →curl --retry 30轮询https://staging-host/health/ready→ 交换 → 再次轮询生产就绪端点。permissions: contents: read id-token: write健康检查与优雅关闭/health/ready是平台级健康检查、启动暖机与槽交换暖机的统一入口实现在 AppServiceLifecycle.cs它实现IHostedLifecycleService在StartedAsync宿主与 Silo 均已启动把IsReady置为true在StoppingAsync关闭开始立即置回false。对应的路由Program.csapp.MapGet(/health/ready, (AppServiceLifecycle lifecycle) lifecycle.IsReady ? Results.Ok() : Results.StatusCode(StatusCodes.Status503ServiceUnavailable));/health/ready只有宿主和 Silo 完全启动后才返回 200关闭一开始即返回 503——这正是平台健康检查与槽暖机需要的语义/health/live廉价的本地进程存活探针刻意不依赖共享存储。关闭方面宿主为 Orleans 离开成员关系预留了最多 30 秒HostOptions.ShutdownTimeout TimeSpan.FromSeconds(30)见 Program.cs。但 App Service 可能更早终止 worker因此应用正确性必须容忍 Silo 丢失与未知调用结果Orleans 消息的 at-least-once 语义下调用可能已执行但结果未返回。安全与可观测性基线基础设施层强制HTTPS-onlyhttpsOnly: true、TLS 1.2 及以上minTlsVersion: 1.2、禁用 FTPSftpsState: Disabled、禁用存储共享密钥授权allowSharedKeyAccess: falsedefaultToOAuthAuthentication: true、存储网络访问仅限集成子网networkAcls.defaultAction: Deny。表数据访问完全走托管标识 Entra 授权。需要清醒认识的两点HTTPS 只保护公共 Web 端点。Orleans Silo 之间的私有 TCP 连接在本示例中未加密当威胁模型要求虚拟网络内传输加密时应叠加网络控制并配置 Orleans TLS。客户端亲和性clientAffinityEnabled: true是为共置的 Blazor Server UI 保留的。Orleans 传输走私有 Silo 端点与 HTTP 亲和性相互独立。可观测性方面Application Insights 接收请求、依赖、异常、应用与 Orleans 日志。建议持续监控就绪 worker 数与 Silo 数、成员关系变化、延迟、拒绝数、存储授权/限流、worker 资源、重启与槽操作。另外Telemetry/ApplicationMapNodeNameInitializer.cs 等辅助代码可进一步把遥测与实例身份关联起来。生产检查清单关注点Windows App Service 交付结果拓扑与网络每个 worker 广告私有实例地址与分配的 Silo 端口且每个 worker 能连接所有活跃成员端点依赖与数据Azure Table 集群与 Grain 状态使用独立的生产数据并具备测试过的备份恢复使用提醒reminder与流stream时显式配置对应 provider身份与机密运行时存储访问走托管标识Easy Auth、日常部署、特权引导三类凭据相互独立并在过期前轮换健康与生命周期健康检查、启动暖机、槽暖机、就绪摘除、有界关闭完整反映应用生命周期扩缩容与韧性计划保留至少 3 个 worker 与经过测试的备用容量在负载下演练扩容、缩容、worker 替换、依赖劣化与突发丢失升级与回滚兼容版本用暂存槽交换并做混合版本验证不兼容版本用独立应用、集群 ID、状态计划与流量切换可观测性与事故Application Insights、Log Analytics、Orleans 遥测、worker 身份、成员关系、provider 信号与槽操作相互关联基础设施交付Bicep 与受保护的 GitHub OIDC 工作流可复现基础设施并通过暂存发布不可变应用制品最后提醒Windows 与 Linux 之间不要直接切换现有 App Service 计划应部署独立应用、验证后迁移流量平台差异见 在 Linux Azure App Service 上部署 Orleans。延伸阅读仓库内文档Azure App Service 部署目标总览Windows/Linux 两种平台共用的拓扑与验收方法生产就绪检查清单、拓扑、网络与集群、优雅关闭与升级、选择部署目标示例完整实现samples/Deployment/AzureAppService含 README.md、Windows/Linux/flex 三套 Bicep 入口与 deploy.ymlOrleans 购物车示例在 Azure App Service 上的部署架构示意赞分享后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载相关推荐Orleans 集群部署到 Azure App Service基于私有实例端点的 Windows/Linux 完整实战指南Orleans 集群部署到 Azure App Service基于私有实例端点的 Windows/Linux 完整实战指南 Azure App Service后端微服务Ryujinx Switch模拟器上手手册从源码编译到跑通第一款游戏Ryujinx Switch模拟器上手手册从源码编译到跑通第一款游戏 游戏文件放进去了窗口却一闪就没或者卡在一块白屏上出不来。Ryujinx 是一款用 C硬件仿真图形学ToolJet 在 Azure Kubernetes ServiceAKS上部署完整指南ToolJet 在 Azure Kubernetes ServiceAKS上部署完整指南 ToolJet 是开源的内部工具与业务应用构建平台本文基于 To低代码后端前端AI 应用MCP 服务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表