ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

在 Azure Container Apps 上托管 Orleans 集群:拓扑设计、端点映射与生产级部署指南

在 Azure Container Apps 上托管 Orleans 集群:拓扑设计、端点映射与生产级部署指南 在 Azure Container Apps 上托管 Orleans 集群拓扑设计、端点映射与生产级部署指南【免费下载链接】orleansCloud Native application framework for .NET项目地址: https://gitcode.com/gh_mirrors/or/orleansAzure Container Apps 是 .NET 云原生应用托管平台但它以应用/修订版本为粒度做服务发现与负载均衡这与 Orleans 以每个成员自通告唯一 silo/gateway 端点为核心的集群语义存在根本差异。本文以 deploy-to-azure-container-apps.md 为主线系统讲解在 Container Apps 上维持 Orleans 端点语义的一容器应用一 silo 副本拓扑、内外网与双 TCP 端口映射、基于 Microsoft Entra ID 的集群/持久化配置、健康探针与优雅停机、滚动替换升级策略及验收测试清单并结合仓库内 AzureContainerApps 示例 与 Bicep/源码给出可复制的实现细节。读完本文你将能够设计、加固、部署并验证一个生产可用的 Orleans 集群。为什么 Container Apps 需要特殊拓扑Orleans 集群中每个 silo 会向成员表通告自己的silo 端口silo 间通信与gateway 端口客户端接入对等节点与客户端依据成员表中的唯一地址直连。而 Azure Container Apps 的服务发现、TCP/HTTP 入口都是面向容器应用或修订版本的请求会被平台代理负载均衡到该应用的任意副本上。Container Apps不发布受支持的单副本网络地址——CONTAINER_APP_REPLICA_NAME只能标识一个副本CONTAINER_APP_HOSTNAME只能标识修订版本主机两者都不是可路由的每副本地址。因此若把一个 Container App 扩展为多个 silo 副本并让它们通告同一个应用端点对等节点可能被路由到与成员表条目不一致的另一个副本上集群语义即被破坏。这正是官方文档给出的三种拓扑对比拓扑端点行为建议每个 Container App 一个 silo 副本环境私有静态 IP 上的唯一 silo/gateway 端口对路由到一个应用、一个 silo在必须使用 Container Apps 时采用min/max 副本均设为 1部署多个 silo 应用一个 Container App 内多个 silo 副本应用与修订主机名经平台代理路由到任一合格副本Container Apps 不提供选取单副本的受支持地址使用受维护的一副本一应用拓扑或改选 AKS 等直接寻址平台silo 部署在 Kubernetes 或其他直接寻址平台编排器为每个 Pod/进程发布可路由地址需要自动副本扩缩与常规滚动替换时优先选择一副本一应用拓扑的代价是运维更重基础设施即代码IaC必须创建有界的 silo 应用集合并为每个应用分配环境内唯一端口升级时还要执行审慎的替换流程换来的是不依赖未文档化的 Pod 网络细节。需要特别提醒的是不要宣称一副本一应用拓扑具备可用区冗余Container Apps 的可用区冗余指导是针对同一应用的多个副本的至少需要两个副本这与本端点模型冲突多个一副本应用之间也不提供反亲和或跨可用区放置保证。若确实需要独立的故障域放置应选择同时提供每进程直连地址与放置控制的平台。公共 HTTP API 应放在独立的 Container App承载 Orleans 客户端或仅在有意为之的拓扑下与 silo 共宿主。公共 HTTP 入口只路由应用请求它不是 Orleans 传输通道。配置网络与 Orleans 端点内网环境与私有静态 IP在现有虚拟网络中创建 Container Apps 环境并将可访问级别设为Internal内部。环境随后会在 Azure 内部负载均衡器上获得一个私有静态 IP且无公共端点。仓库示例 environment.bicep 展示了这种配置vnetConfiguration.internal: true、zoneRedundant: false并把环境诊断日志路由到 Log Analytics 工作区。双 TCP 入口端口为每个 silo 应用配置两个 TCP 入口端口silo 端口承载 silo 间流量gateway 端口承载 Orleans 客户端流量。将应用入口设为external: true使这些端口在环境边界可用——因为环境本身是内部的入站 IP 仍保持私有。每个 silo 应用必须分配唯一的外露 silo/gateway 端口对环境内所有外部暴露的 TCP 端口必须唯一且端口36985被保留。各应用可以使用相同的容器目标端口如11111与30000。示例 silo.bicep 的 ingress 结构给出了精确写法主入口targetPort: 11111、exposedPort: advertisedSiloPort、transport: tcp通过additionalPortMappings增加targetPort: 30000的 gateway 映射同时minReplicas: 1、maxReplicas: 1见 containerapp.bicep。监听端点与通告端点分离把环境的properties.staticIp和应用的唯一外露端口传给每个 silo并将监听端点绑定到容器目标端口。监听端点listening endpoint是进程在容器内的绑定位置通告端点advertised endpoint是 Orleans 写入成员表、供对等节点与客户端使用的地址。绑定到0.0.0.0并不能自动发现一个可通告的地址。若入口映射的外露端口与目标端口不同需直接配置EndpointOptionsSiloListeningEndpoint与GatewayListeningEndpoint填入目标端口AdvertisedIPAddress、SiloPort与GatewayPort填入可路由的入口地址与外露端口。文档片段 DeploymentSnippets.cs 给出了标准实现var advertisedAddress IPAddress.Parse( builder.Configuration[ORLEANS_ADVERTISED_IP] ?? throw new InvalidOperationException(ORLEANS_ADVERTISED_IP isnt configured.)); var advertisedSiloPort int.Parse( builder.Configuration[ORLEANS_ADVERTISED_SILO_PORT] ?? throw new InvalidOperationException(ORLEANS_ADVERTISED_SILO_PORT isnt configured.)); var advertisedGatewayPort int.Parse( builder.Configuration[ORLEANS_ADVERTISED_GATEWAY_PORT] ?? throw new InvalidOperationException(ORLEANS_ADVERTISED_GATEWAY_PORT isnt configured.)); builder.Host.UseOrleans(siloBuilder { siloBuilder.ConfigureEndpointOptions(options { options.AdvertisedIPAddress advertisedAddress; options.SiloPort advertisedSiloPort; options.GatewayPort advertisedGatewayPort; options.SiloListeningEndpoint new IPEndPoint(IPAddress.Any, 11_111); options.GatewayListeningEndpoint new IPEndPoint(IPAddress.Any, 30_000); }); });仓库示例中的 OrleansEndpointConfigurationExtensions.cs 实现了同样的模式从Orleans:AdvertisedIPAddress、Orleans:AdvertisedSiloPort、Orleans:AdvertisedGatewayPort读取通告信息监听端点固定绑定IPAddress.Any上的11111/30000并在开发环境下回退到普通ConfigureEndpoints。客户端应置于同一环境或能触达环境私有 IP 的已连接私有网络中当网络不是可信边界时限制对可信工作负载的访问并使用 Orleans 传输层安全TLS。配置集群与持久化状态使用外部集群提供程序让 silo 与客户端发现同一份成员记录——Azure Table Storage 是常见选择。注意集群提供程序只存成员关系不持久化 grain 状态必须为每个需要跨激活或集群丢失存活的 state 名称单独注册 grain 存储提供程序。以下配置使用 Microsoft Entra ID 而非存储账户密钥片段见 DeploymentSnippets.csvar tableEndpoint new Uri( builder.Configuration[AZURE_TABLE_STORAGE_ENDPOINT] ?? throw new InvalidOperationException(AZURE_TABLE_STORAGE_ENDPOINT isnt configured.)); var tableServiceClient new TableServiceClient( tableEndpoint, new DefaultAzureCredential()); builder.Host.UseOrleans(siloBuilder { siloBuilder .ConfigureClusterOptions(options { options.ServiceId orders; options.ClusterId builder.Configuration[ORLEANS_CLUSTER_ID] ?? throw new InvalidOperationException(ORLEANS_CLUSTER_ID isnt configured.); }) .UseAzureStorageClustering( options options.TableServiceClient tableServiceClient) .AddAzureTableGrainStorage( name: default, options options.TableServiceClient tableServiceClient); });此配置需要安装Microsoft.Orleans.Clustering.AzureStorage、Microsoft.Orleans.Persistence.AzureStorage与Azure.Identity并在 Orleans 客户端上配置相同的ServiceId、ClusterId、集群表和凭据。ServiceId对应用保持稳定每个环境或隔离的蓝绿集群使用独立的ClusterId。示例中的 AzureTableServiceClientFactory.cs 进一步展示了生产与开发分支生产必须提供 HTTPS 的AzureTable:ServiceUri与用户分配托管身份的AZURE_CLIENT_ID通过DefaultAzureCredentialOptions.ManagedIdentityClientId定向开发环境仅接受 Azurite 快捷方式AzureTable:ConnectionStringUseDevelopmentStoragetrue生产不会回退到连接字符串。角色分配细节给 silo 与客户端身份授予仅其使用范围的Storage Table Data Contributor。Orleans Azure Table 提供程序会调用TableClient.CreateIfNotExistsAsync因此即使客户端后续只读 gateway 记录仅授予Storage Table Data Reader也不够。若 grain 状态使用 blob 或其他服务应在尽量窄的范围内授予对应数据面角色当所有消费者都支持 Microsoft Entra ID 时应禁用共享密钥访问。规划生产基础设施使用稳定的 Azure Resource Manager API 版本定义环境与每个 Container App。一个生产模板应包含虚拟网络集成、内部访问的环境并将其私有properties.staticIp传给每个 silo至少两个、通常三个一副本 silo 应用以提供进程与应用资源冗余每个 silo 应用minReplicas: 1、maxReplicas: 1不构成文档化的跨可用区放置保证每个应用唯一的外露 silo/gateway 端口对映射到容器监听端口仅在内网环境中启用应用级外部 TCP 入口显式的 startup、readiness、liveness 探针terminationGracePeriodSeconds大于实测的 .NET 主机与 Orleans 停机时间Container Apps 默认进程宽限期为 30 秒超时即发SIGKILL每个运行时应用的用户分配或系统分配托管身份从 Azure Container Registry 进行托管身份拉取镜像仅授予AcrPull或 ABAC 仓库的等价 repository-reader 角色Azure Table Storage 或其他受支持集群提供程序、按需的持久 grain 存储、安全模型要求的私有服务访问Log Analytics 或 Azure Monitor 诊断路由以及应用指标与追踪不可变镜像摘要或唯一镜像标签绝不部署可变的latest。示例 containerapp.bicep 的探针配置可直接参考Startup 探针failureThreshold: 30、periodSeconds: 5Readiness 探针failureThreshold: 6、periodSeconds: 5Liveness 探针failureThreshold: 3、periodSeconds: 10均走httpGetContainer Apps 每种类型每个容器仅支持一个 HTTP(S) 或 TCP 探针不支持exec或 gRPC 探针。切勿将 Orleans 集群缩到零保持足够数量的 silo 应用运行以在失去一个实例后仍满足经测试的可用性与容量下限。扩容新增一个一副本 silo 应用并等待其成为活动成员缩容一次一个应用先将其移出应用流量并允许优雅停机。真实机密优先使用 Container Apps 的 Key Vault 密钥引用配合具备Key Vault Secrets User的托管身份不要把存储密钥、注册表密码、证书或部署凭据写进源码、镜像、Bicep 参数或普通环境变量。保障持续部署安全用GitHub OpenID ConnectOIDC与工作负载身份联合替代长期有效的服务主体机密permissions: contents: read id-token: write steps: - uses: azure/loginf5d393ae46f8fde4be8b75f32e3fc50e654ad0ca # v3.0.1 with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}将联合凭据限定到执行部署的仓库与受保护分支或 GitHub 环境并把第三方 action 固定到经审查的提交 SHA。仓库示例 deploy.yml 即采用此模式。按职责拆分身份与权限常规部署身份只能更新目标资源组内的 Container Apps 及相关资源镜像发布身份仅在目标仓库拥有AcrPush或仓库级 writer 角色运行时 Container Apps 使用另一身份仅拥有拉取镜像与应用数据面权限单独治理的 bootstrap 身份负责创建角色分配。不要给常规工作流订阅级Contributor或任意角色分配权。示例的 bootstrap.bicep 正是这样收敛范围仅在工作流主体所在的示例资源组授予Contributor、在示例注册表授予AcrPush常规工作流无法创建角色分配。安全提示在将不可信输入用作 grain key 前必须校验。攻击者若可挑选任意 key就能迫使产生无界数量的 grain 激活。应限定接受的 key 空间、授权访问、限流请求并避免把原始 grain key 记录为指标维度。示例通过hello grain 使用整数 key、公共路由只接受 0~255、provider 端点返回数字 key、非活动 hello grain 两分钟回收来收敛公共 grain 身份该有界输入模式应保留单靠回收时间并不能让无界 key 空间变安全。配置健康与停机在 IaC 中显式定义 HTTP startup、readiness、liveness 探针三者语义必须区分Startup配置有效、监听器已绑定、silo 已加入目标集群后成功Readiness仅当应用能安全接收新应用流量时成功停机开始时应使其失败Liveness只检查本地进程进度不得依赖Azure Storage、其他 silo 或远程服务——共享故障可能导致整个集群重启。Readiness 控制 Container Apps 的入口流量。对一副本 silo 应用readiness 失败会阻止通过其通告 silo/gateway 入口端口建立新连接但已有 TCP 连接可以保持打开readiness 本身不更新 Orleans 成员关系、也不完成 drain。因此必须把 readiness 状态切换与停止新应用工作、离开成员关系、关闭现有连接、正常 .NET 主机终止协调一致。设置terminationGracePeriodSeconds高于实测停机时间并留出余量同时让 .NET 主机停机超时短于平台截止时间。示例 Silo/Program.cs 暴露了/health/startup、/health/ready、/health/live三个探针端点生产应用应让 readiness 进一步反映自身的流量排空与依赖要求。相关参考health-and-observability.md。规划修订版本与升级Container Apps 默认使用单修订模式在等待 startup 与 readiness 期间可能短暂同时运行新旧副本。对一副本 silo 应用而言若两个修订版本共享一个通告应用端点这种重叠是不安全的。应刻意替换silo 应用版本兼容时部署一个带新外露端口对、相同集群身份的新应用等待新应用就绪并成为 Orleans 成员停止旧 silo 上的应用工作允许优雅停机确认其离开成员关系仅在集群容量与延迟稳定后移除旧应用。这是跨不同 Container App 资源的滚动替换而非流量加权修订版本发布。新旧 silo 共享ClusterId的前提是grain 接口、序列化器、持久化状态、提供程序 schema 与副作用全部兼容。不兼容的蓝绿部署应使用独立的ClusterId与端点集并在匹配的客户端/API 部署之间切换应用 HTTP 流量——Container Apps 的修订版本权重与标签只影响入口流量不会拆分直连的 Orleans TCP 流量。更多细节见 upgrades.md。配置可观测性将应用日志、Orleans 与 .NET 指标、分布式追踪集中导出并为日志与追踪附加以下维度CONTAINER_APP_NAME、CONTAINER_APP_REVISION、CONTAINER_APP_REPLICA_NAMEOrleans silo 名称、通告端点、ServiceId、ClusterId镜像摘要或部署版本。需要监控的指标包括就绪/活动 silo 数、成员变化、gateway 连接数、grain 调用延迟与失败、激活数、CPU、内存、套接字使用、重启次数、提供程序延迟或限流。Container Apps 的控制台与系统日志带有 app/revision/replica 元数据为公共应用入口启用 HTTP 日志。不要输出机密、租户数据或无限增长的 grain key。验证部署为确切的 Container Apps 环境与网络配置记录确定性证据。首先枚举活动修订版本与副本az containerapp revision list \ --resource-group $RESOURCE_GROUP \ --name $CONTAINER_APP \ --query [].{name:name,active:properties.active,replicas:properties.replicas,health:properties.healthState,running:properties.runningState} \ --output table az containerapp replica list \ --resource-group $RESOURCE_GROUP \ --name $CONTAINER_APP \ --revision $REVISION \ --output json副本 API 不返回受支持的应用网络 IP 地址可用az containerapp exec检查每个副本的环境与监听套接字但不要把观察到的接口地址推断为支持保证。使用 Microsoft Entra 认证查询 Azure Table 成员关系az storage entity query \ --account-name $STORAGE_ACCOUNT \ --auth-mode login \ --table-name OrleansSiloInstances \ --filter PartitionKey eq $CLUSTER_ID \ --output table验收测试清单在生产上线前以及平台或网络变更后完成以下测试确认每个目标 silo 有一条活动成员记录且通告的 silo/gateway 端点唯一从每个 silo 应用向每个其他通告 silo 端点建立 TCP 连接从每个客户端网络向每个通告 gateway 端点建立 TCP 连接通过有界的测试 grain key 集合发调用验证调用到达集群各处的激活负载下新增一个替换 silo、移除一个旧 silo确认优雅成员变化、状态稳定、延迟可接受逐个重启每个 silo验证持久 grain 状态存活演练兼容的滚动与隔离蓝绿流程包括回滚验证 silo 与 gateway 端口无法被公开访问运行时与部署身份仅有预期角色。示例 README 还建议在生产前检查dashboard 显示Silo-A、Silo-B、Dashboard均活动GET /hello/0与GET /hello/255成功GET /hello/-1与GET /hello/256返回 HTTP 400GET /providers返回数字形式的活跃 hello-grain key见 README.md。仓库示例解剖仓库内 AzureContainerApps 示例源自 Azure-Samples/Orleans-Cluster-on-Azure-Container-AppsMIT 许可保留在该目录中演示了以下内容一个内部环境内包含两个专用 silo Container App、一个 dashboard silo、一个 Minimal API 客户端、一个 worker 客户端与一个外部伸缩服务每个 Orleans 服务器应用仅一个副本。两个 silo 与 dashboard 通告环境私有静态 IP使用唯一外露端口对11111/30000、11112/30001、11113/30002见 README.md稳定的 Container Apps 资源 API、带私有 DNS 的虚拟网络集成、显式 startup/readiness/liveness 探针、60 秒终止宽限期、非零副本下限用户分配运行时身份、托管身份 ACR 拉取、禁用注册表管理员凭据、禁用存储共享密钥访问通过DefaultAzureCredential的 Azure Table Storage 集群运行时身份在预建成员表上拥有Storage Table Data Contributor示例未配置持久 grain 存储单独运行的 bootstrap 模板负责角色分配常规部署工作流使用 GitHub OIDC、SHA 固定 action、Git-SHA 镜像标签与摘要固定的 Container App 修订版本客户端通过 Orleans 成员关系发现各 gateway而非把 HTTP 入口当作 Orleans 传输外部伸缩 gRPC 服务仅作学习组件未挂到任何 silo 伸缩规则上——因为把一个应用缩到多个 silo 副本会重新引入不受支持的端点假设。下方是示例环境的应用映射Application Insights Application map展示了 Orleans silo 与 Azure Table Storage 客户端之间的调用关系与延迟示例的边界它仍是架构演示而非生产部署清单。注册表与存储数据端点保持公共虽要求 Microsoft Entra 认证所有运行时应用共享一个身份简单 readiness 端点未实现应用级排空工作流原地更新现有应用可能临时重叠通告同一端点的修订版本——生产升级请使用本文的替换应用流程。一副本应用不能证明跨可用区或独立故障域放置外部伸缩器也不提供容量建议。适合用它理解组件关系、基于成员关系的 gateway 发现、托管身份、工作负载生成与显式端点映射但在用于生产前必须完成本文的联网、故障、升级、安全、状态恢复与 readiness 验收测试。生产清单速查关注点Azure Container Apps 目标状态拓扑与网络每个一副本 silo 应用拥有唯一私有 silo/gateway 端口对每个成员端点恰好映射到一个应用依赖与数据生产集群、grain 存储、reminder、stream 均有显式提供程序、命名空间、持久性、配额、备份与恢复流程身份与机密运行时、镜像发布、常规部署与特权 bootstrap 身份各有独立的 least-privilege 角色机密采用托管交付与轮换健康与生命周期startup/readiness/liveness 探针代表不同应用状态终止宽限期超过实测主机停机时间扩缩与韧性扩缩变更以增删一副本 silo 应用的方式执行保持经测试的容量下限并能从单个应用/主机丢失中恢复升级与回滚兼容版本使用带新端口对的替换应用不兼容版本使用隔离集群 ID、端点集、状态方案与应用流量切换可观测性与事件Orleans 遥测、Container App 的 app/revision/replica 身份、成员关系、提供程序信号与部署元数据集中关联基础设施交付版本化 Bicep 与受保护的 GitHub OIDC 工作流复现有界应用拓扑并部署不可变镜像摘要部署目标选型可对比 choose-deployment-target.mdAKS、App Service、Kubernetes、Service Fabric 与多主机容器随后完成共享的 production-readiness.md 清单。【免费下载链接】orleansCloud Native application framework for .NET项目地址: https://gitcode.com/gh_mirrors/or/orleans创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表