devops
**devops 是 Agent 的部署控制中心:它不包含主要业务代码
- 用 Bicep 描述 Azure 基础设施
- 用 EV2 描述 ApiServiceNg 应用版本如何安全上线。**
#mermaid-svg-lqR4mwTvaGfJRmfO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lqR4mwTvaGfJRmfO .error-icon{fill:#552222;}#mermaid-svg-lqR4mwTvaGfJRmfO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lqR4mwTvaGfJRmfO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lqR4mwTvaGfJRmfO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lqR4mwTvaGfJRmfO .marker.cross{stroke:#333333;}#mermaid-svg-lqR4mwTvaGfJRmfO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lqR4mwTvaGfJRmfO p{margin:0;}#mermaid-svg-lqR4mwTvaGfJRmfO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster-label text{fill:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster-label span{color:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster-label span p{background-color:transparent;}#mermaid-svg-lqR4mwTvaGfJRmfO .label text,#mermaid-svg-lqR4mwTvaGfJRmfO span{fill:#333;color:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO .node rect,#mermaid-svg-lqR4mwTvaGfJRmfO .node circle,#mermaid-svg-lqR4mwTvaGfJRmfO .node ellipse,#mermaid-svg-lqR4mwTvaGfJRmfO .node polygon,#mermaid-svg-lqR4mwTvaGfJRmfO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lqR4mwTvaGfJRmfO .rough-node .label text,#mermaid-svg-lqR4mwTvaGfJRmfO .node .label text,#mermaid-svg-lqR4mwTvaGfJRmfO .image-shape .label,#mermaid-svg-lqR4mwTvaGfJRmfO .icon-shape .label{text-anchor:middle;}#mermaid-svg-lqR4mwTvaGfJRmfO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lqR4mwTvaGfJRmfO .rough-node .label,#mermaid-svg-lqR4mwTvaGfJRmfO .node .label,#mermaid-svg-lqR4mwTvaGfJRmfO .image-shape .label,#mermaid-svg-lqR4mwTvaGfJRmfO .icon-shape .label{text-align:center;}#mermaid-svg-lqR4mwTvaGfJRmfO .node.clickable{cursor:pointer;}#mermaid-svg-lqR4mwTvaGfJRmfO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lqR4mwTvaGfJRmfO .arrowheadPath{fill:#333333;}#mermaid-svg-lqR4mwTvaGfJRmfO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lqR4mwTvaGfJRmfO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lqR4mwTvaGfJRmfO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lqR4mwTvaGfJRmfO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lqR4mwTvaGfJRmfO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lqR4mwTvaGfJRmfO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster text{fill:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO .cluster span{color:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lqR4mwTvaGfJRmfO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lqR4mwTvaGfJRmfO rect.text{fill:none;stroke-width:0;}#mermaid-svg-lqR4mwTvaGfJRmfO .icon-shape,#mermaid-svg-lqR4mwTvaGfJRmfO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lqR4mwTvaGfJRmfO .icon-shape p,#mermaid-svg-lqR4mwTvaGfJRmfO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lqR4mwTvaGfJRmfO .icon-shape .label rect,#mermaid-svg-lqR4mwTvaGfJRmfO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lqR4mwTvaGfJRmfO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lqR4mwTvaGfJRmfO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lqR4mwTvaGfJRmfO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ApiServiceNg 代码
测试、签名、打包
Bicep 基础设施
Azure 环境
EV2 发布编排
App Service
Azure Monitor 验证
这里的 DevOps 不是单指"运维人员",而是把开发、测试、基础设施、发布、安全和监控连接成一条可审查、可重复、可回滚的工程流程。
一、目录的整体结构
#mermaid-svg-JGBpMCCdE412B6Br{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JGBpMCCdE412B6Br .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JGBpMCCdE412B6Br .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JGBpMCCdE412B6Br .error-icon{fill:#552222;}#mermaid-svg-JGBpMCCdE412B6Br .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JGBpMCCdE412B6Br .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JGBpMCCdE412B6Br .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JGBpMCCdE412B6Br .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JGBpMCCdE412B6Br .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JGBpMCCdE412B6Br .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JGBpMCCdE412B6Br .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JGBpMCCdE412B6Br .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JGBpMCCdE412B6Br .marker.cross{stroke:#333333;}#mermaid-svg-JGBpMCCdE412B6Br svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JGBpMCCdE412B6Br p{margin:0;}#mermaid-svg-JGBpMCCdE412B6Br .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JGBpMCCdE412B6Br .cluster-label text{fill:#333;}#mermaid-svg-JGBpMCCdE412B6Br .cluster-label span{color:#333;}#mermaid-svg-JGBpMCCdE412B6Br .cluster-label span p{background-color:transparent;}#mermaid-svg-JGBpMCCdE412B6Br .label text,#mermaid-svg-JGBpMCCdE412B6Br span{fill:#333;color:#333;}#mermaid-svg-JGBpMCCdE412B6Br .node rect,#mermaid-svg-JGBpMCCdE412B6Br .node circle,#mermaid-svg-JGBpMCCdE412B6Br .node ellipse,#mermaid-svg-JGBpMCCdE412B6Br .node polygon,#mermaid-svg-JGBpMCCdE412B6Br .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGBpMCCdE412B6Br .rough-node .label text,#mermaid-svg-JGBpMCCdE412B6Br .node .label text,#mermaid-svg-JGBpMCCdE412B6Br .image-shape .label,#mermaid-svg-JGBpMCCdE412B6Br .icon-shape .label{text-anchor:middle;}#mermaid-svg-JGBpMCCdE412B6Br .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JGBpMCCdE412B6Br .rough-node .label,#mermaid-svg-JGBpMCCdE412B6Br .node .label,#mermaid-svg-JGBpMCCdE412B6Br .image-shape .label,#mermaid-svg-JGBpMCCdE412B6Br .icon-shape .label{text-align:center;}#mermaid-svg-JGBpMCCdE412B6Br .node.clickable{cursor:pointer;}#mermaid-svg-JGBpMCCdE412B6Br .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JGBpMCCdE412B6Br .arrowheadPath{fill:#333333;}#mermaid-svg-JGBpMCCdE412B6Br .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JGBpMCCdE412B6Br .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JGBpMCCdE412B6Br .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGBpMCCdE412B6Br .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JGBpMCCdE412B6Br .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGBpMCCdE412B6Br .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JGBpMCCdE412B6Br .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JGBpMCCdE412B6Br .cluster text{fill:#333;}#mermaid-svg-JGBpMCCdE412B6Br .cluster span{color:#333;}#mermaid-svg-JGBpMCCdE412B6Br div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JGBpMCCdE412B6Br .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JGBpMCCdE412B6Br rect.text{fill:none;stroke-width:0;}#mermaid-svg-JGBpMCCdE412B6Br .icon-shape,#mermaid-svg-JGBpMCCdE412B6Br .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGBpMCCdE412B6Br .icon-shape p,#mermaid-svg-JGBpMCCdE412B6Br .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JGBpMCCdE412B6Br .icon-shape .label rect,#mermaid-svg-JGBpMCCdE412B6Br .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGBpMCCdE412B6Br .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JGBpMCCdE412B6Br .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JGBpMCCdE412B6Br :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} devops
Azure/IaC
基础设施定义
ev2/ApiServiceNg
应用发布定义
ev2/service
服务身份与订阅注册
Bicep 模板
Staging / Production 参数
ZIP 发布模板
Rollout 步骤和健康检查
Service Tree / EV2 注册
它当前主要服务于 ApiServiceNg。目录为 DevBrain、Portal、RestApi 等应用预留了扩展结构,但不能据此认为这些服务已经全部由这里管理。
二、为什么分成 Bicep 和 EV2
最关键的区别是:
#mermaid-svg-gPT4LQTAnjbPRzaW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gPT4LQTAnjbPRzaW .error-icon{fill:#552222;}#mermaid-svg-gPT4LQTAnjbPRzaW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gPT4LQTAnjbPRzaW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gPT4LQTAnjbPRzaW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gPT4LQTAnjbPRzaW .marker.cross{stroke:#333333;}#mermaid-svg-gPT4LQTAnjbPRzaW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gPT4LQTAnjbPRzaW p{margin:0;}#mermaid-svg-gPT4LQTAnjbPRzaW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster-label text{fill:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster-label span{color:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster-label span p{background-color:transparent;}#mermaid-svg-gPT4LQTAnjbPRzaW .label text,#mermaid-svg-gPT4LQTAnjbPRzaW span{fill:#333;color:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW .node rect,#mermaid-svg-gPT4LQTAnjbPRzaW .node circle,#mermaid-svg-gPT4LQTAnjbPRzaW .node ellipse,#mermaid-svg-gPT4LQTAnjbPRzaW .node polygon,#mermaid-svg-gPT4LQTAnjbPRzaW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gPT4LQTAnjbPRzaW .rough-node .label text,#mermaid-svg-gPT4LQTAnjbPRzaW .node .label text,#mermaid-svg-gPT4LQTAnjbPRzaW .image-shape .label,#mermaid-svg-gPT4LQTAnjbPRzaW .icon-shape .label{text-anchor:middle;}#mermaid-svg-gPT4LQTAnjbPRzaW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gPT4LQTAnjbPRzaW .rough-node .label,#mermaid-svg-gPT4LQTAnjbPRzaW .node .label,#mermaid-svg-gPT4LQTAnjbPRzaW .image-shape .label,#mermaid-svg-gPT4LQTAnjbPRzaW .icon-shape .label{text-align:center;}#mermaid-svg-gPT4LQTAnjbPRzaW .node.clickable{cursor:pointer;}#mermaid-svg-gPT4LQTAnjbPRzaW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gPT4LQTAnjbPRzaW .arrowheadPath{fill:#333333;}#mermaid-svg-gPT4LQTAnjbPRzaW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gPT4LQTAnjbPRzaW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gPT4LQTAnjbPRzaW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gPT4LQTAnjbPRzaW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gPT4LQTAnjbPRzaW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gPT4LQTAnjbPRzaW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster text{fill:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW .cluster span{color:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gPT4LQTAnjbPRzaW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gPT4LQTAnjbPRzaW rect.text{fill:none;stroke-width:0;}#mermaid-svg-gPT4LQTAnjbPRzaW .icon-shape,#mermaid-svg-gPT4LQTAnjbPRzaW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gPT4LQTAnjbPRzaW .icon-shape p,#mermaid-svg-gPT4LQTAnjbPRzaW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gPT4LQTAnjbPRzaW .icon-shape .label rect,#mermaid-svg-gPT4LQTAnjbPRzaW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gPT4LQTAnjbPRzaW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gPT4LQTAnjbPRzaW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gPT4LQTAnjbPRzaW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Bicep
环境应该长什么样
网络、身份、App Service、监控
EV2
某个版本怎样上线
ZIP 部署、顺序、审批、健康验证
Bicep 负责长期基础设施:
- VNet Integration Subnet 和 NAT Gateway。
- App Service Plan 与 Web App。
- User Assigned Managed Identity。
- Application Insights 和 Log Analytics。
- App Settings、Easy Auth 和访问限制。
- Azure Monitor 健康告警。
- 可选的 Key Vault、Service Bus、Storage RBAC。
EV2 负责短周期应用发布:
- 选择 CI 生成的
ApiServiceNg.zip。 - 把包发布到已有 Web App。
- 区分 Staging 和 Production。
- 应用环境配置覆盖。
- 执行部署后健康验证。
- 管理生产审批和 SDP 发布策略。
为什么不用一个 Bicep 文件同时部署基础设施和每次代码版本?因为两者变化频率和风险不同。代码一天可能发布多次,网络和身份可能几个月才调整一次。若每次代码发布都重新运行完整基础设施部署,会扩大权限、故障面和审查成本。
| 方案 | 优点 | 问题 |
|---|---|---|
| Bicep 同时部署代码和基础设施 | 一个入口 | 高频代码发布会反复触碰低频基础设施 |
| EV2 同时创建全部 Azure 资源 | 发布流程统一 | EV2 Service Root 复杂,基础设施 What-If 不直观 |
| Bicep 管环境,EV2 管版本 | 生命周期和权限边界清晰 | 需要维护两套声明 |
| 手工 Portal 操作 | 初期最快 | 不可审查、不可重复、容易环境漂移 |
这里采用第三种方案,本质上是分离环境生命周期和应用版本生命周期。
三、Bicep 如何描述 Azure 环境
根入口是 main.bicep。它不是把所有资源直接堆在一个文件里,而是负责组合各个拥有明确职责的单元:
#mermaid-svg-wegwKOIdaowKzLHR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wegwKOIdaowKzLHR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wegwKOIdaowKzLHR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wegwKOIdaowKzLHR .error-icon{fill:#552222;}#mermaid-svg-wegwKOIdaowKzLHR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wegwKOIdaowKzLHR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wegwKOIdaowKzLHR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wegwKOIdaowKzLHR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wegwKOIdaowKzLHR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wegwKOIdaowKzLHR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wegwKOIdaowKzLHR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wegwKOIdaowKzLHR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wegwKOIdaowKzLHR .marker.cross{stroke:#333333;}#mermaid-svg-wegwKOIdaowKzLHR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wegwKOIdaowKzLHR p{margin:0;}#mermaid-svg-wegwKOIdaowKzLHR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wegwKOIdaowKzLHR .cluster-label text{fill:#333;}#mermaid-svg-wegwKOIdaowKzLHR .cluster-label span{color:#333;}#mermaid-svg-wegwKOIdaowKzLHR .cluster-label span p{background-color:transparent;}#mermaid-svg-wegwKOIdaowKzLHR .label text,#mermaid-svg-wegwKOIdaowKzLHR span{fill:#333;color:#333;}#mermaid-svg-wegwKOIdaowKzLHR .node rect,#mermaid-svg-wegwKOIdaowKzLHR .node circle,#mermaid-svg-wegwKOIdaowKzLHR .node ellipse,#mermaid-svg-wegwKOIdaowKzLHR .node polygon,#mermaid-svg-wegwKOIdaowKzLHR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wegwKOIdaowKzLHR .rough-node .label text,#mermaid-svg-wegwKOIdaowKzLHR .node .label text,#mermaid-svg-wegwKOIdaowKzLHR .image-shape .label,#mermaid-svg-wegwKOIdaowKzLHR .icon-shape .label{text-anchor:middle;}#mermaid-svg-wegwKOIdaowKzLHR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wegwKOIdaowKzLHR .rough-node .label,#mermaid-svg-wegwKOIdaowKzLHR .node .label,#mermaid-svg-wegwKOIdaowKzLHR .image-shape .label,#mermaid-svg-wegwKOIdaowKzLHR .icon-shape .label{text-align:center;}#mermaid-svg-wegwKOIdaowKzLHR .node.clickable{cursor:pointer;}#mermaid-svg-wegwKOIdaowKzLHR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wegwKOIdaowKzLHR .arrowheadPath{fill:#333333;}#mermaid-svg-wegwKOIdaowKzLHR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wegwKOIdaowKzLHR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wegwKOIdaowKzLHR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wegwKOIdaowKzLHR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wegwKOIdaowKzLHR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wegwKOIdaowKzLHR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wegwKOIdaowKzLHR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wegwKOIdaowKzLHR .cluster text{fill:#333;}#mermaid-svg-wegwKOIdaowKzLHR .cluster span{color:#333;}#mermaid-svg-wegwKOIdaowKzLHR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wegwKOIdaowKzLHR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wegwKOIdaowKzLHR rect.text{fill:none;stroke-width:0;}#mermaid-svg-wegwKOIdaowKzLHR .icon-shape,#mermaid-svg-wegwKOIdaowKzLHR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wegwKOIdaowKzLHR .icon-shape p,#mermaid-svg-wegwKOIdaowKzLHR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wegwKOIdaowKzLHR .icon-shape .label rect,#mermaid-svg-wegwKOIdaowKzLHR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wegwKOIdaowKzLHR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wegwKOIdaowKzLHR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wegwKOIdaowKzLHR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main.bicep
apiServiceNetwork
platformMonitoring
apiServiceDeployment
apiServiceAccess
apiServiceAlerts
这个依赖关系很重要。例如 Web App 必须在 VNet Integration Subnet 和共享监控资源准备好之后部署;健康告警必须等 Web App 存在;RBAC 需要 ApiService Managed Identity 的 principalId。
Bicep 的目标不是"依次运行五个脚本",而是声明依赖图。Azure Resource Manager 根据图决定可以并行执行什么、必须等待什么。
四、为什么按资源所有权拆目录
当前约定是:
apps/:应用自己的资源。network/:网络与子网。identity/:身份和权限。monitoring/:共享监控。edge/:Front Door、DNS 等边缘资源。shared/:Key Vault、Service Bus 等跨应用资源。types/:组件间共享的编译期类型。modules/:至少有两个真实调用方后才形成的复用模块。
#mermaid-svg-8I0GKfbkdDreylvH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8I0GKfbkdDreylvH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8I0GKfbkdDreylvH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8I0GKfbkdDreylvH .error-icon{fill:#552222;}#mermaid-svg-8I0GKfbkdDreylvH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8I0GKfbkdDreylvH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8I0GKfbkdDreylvH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8I0GKfbkdDreylvH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8I0GKfbkdDreylvH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8I0GKfbkdDreylvH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8I0GKfbkdDreylvH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8I0GKfbkdDreylvH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8I0GKfbkdDreylvH .marker.cross{stroke:#333333;}#mermaid-svg-8I0GKfbkdDreylvH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8I0GKfbkdDreylvH p{margin:0;}#mermaid-svg-8I0GKfbkdDreylvH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8I0GKfbkdDreylvH .cluster-label text{fill:#333;}#mermaid-svg-8I0GKfbkdDreylvH .cluster-label span{color:#333;}#mermaid-svg-8I0GKfbkdDreylvH .cluster-label span p{background-color:transparent;}#mermaid-svg-8I0GKfbkdDreylvH .label text,#mermaid-svg-8I0GKfbkdDreylvH span{fill:#333;color:#333;}#mermaid-svg-8I0GKfbkdDreylvH .node rect,#mermaid-svg-8I0GKfbkdDreylvH .node circle,#mermaid-svg-8I0GKfbkdDreylvH .node ellipse,#mermaid-svg-8I0GKfbkdDreylvH .node polygon,#mermaid-svg-8I0GKfbkdDreylvH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8I0GKfbkdDreylvH .rough-node .label text,#mermaid-svg-8I0GKfbkdDreylvH .node .label text,#mermaid-svg-8I0GKfbkdDreylvH .image-shape .label,#mermaid-svg-8I0GKfbkdDreylvH .icon-shape .label{text-anchor:middle;}#mermaid-svg-8I0GKfbkdDreylvH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8I0GKfbkdDreylvH .rough-node .label,#mermaid-svg-8I0GKfbkdDreylvH .node .label,#mermaid-svg-8I0GKfbkdDreylvH .image-shape .label,#mermaid-svg-8I0GKfbkdDreylvH .icon-shape .label{text-align:center;}#mermaid-svg-8I0GKfbkdDreylvH .node.clickable{cursor:pointer;}#mermaid-svg-8I0GKfbkdDreylvH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8I0GKfbkdDreylvH .arrowheadPath{fill:#333333;}#mermaid-svg-8I0GKfbkdDreylvH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8I0GKfbkdDreylvH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8I0GKfbkdDreylvH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8I0GKfbkdDreylvH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8I0GKfbkdDreylvH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8I0GKfbkdDreylvH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8I0GKfbkdDreylvH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8I0GKfbkdDreylvH .cluster text{fill:#333;}#mermaid-svg-8I0GKfbkdDreylvH .cluster span{color:#333;}#mermaid-svg-8I0GKfbkdDreylvH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8I0GKfbkdDreylvH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8I0GKfbkdDreylvH rect.text{fill:none;stroke-width:0;}#mermaid-svg-8I0GKfbkdDreylvH .icon-shape,#mermaid-svg-8I0GKfbkdDreylvH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8I0GKfbkdDreylvH .icon-shape p,#mermaid-svg-8I0GKfbkdDreylvH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8I0GKfbkdDreylvH .icon-shape .label rect,#mermaid-svg-8I0GKfbkdDreylvH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8I0GKfbkdDreylvH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8I0GKfbkdDreylvH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8I0GKfbkdDreylvH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ApiService 专属
环境共享
网络边界
身份权限
一个 Azure 资源
谁控制其生命周期?
apps/apiservice
monitoring / shared
network
identity
为什么不按 Azure 资源类型简单拆成 webapps/、subnets/、alerts/?因为工程变更通常按业务所有权发生,而不是按 Azure 类型发生。ApiService 健康告警虽然是 Monitoring 资源,但它只服务 ApiService,因此放在 apps/apiservice/alerts.bicep;共享 Log Analytics 则由 monitoring/platform-monitoring 管理。
每个资源只能有一个 IaC Owner。其他组件如果需要使用它,应声明为 existing 并读取 ID,不能在两个模板中同时声明"由我管理",否则两个部署会互相覆盖。
五、ApiService 基础设施具体做什么
#mermaid-svg-Zy9QGDYb2ADJXN8b{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Zy9QGDYb2ADJXN8b .error-icon{fill:#552222;}#mermaid-svg-Zy9QGDYb2ADJXN8b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Zy9QGDYb2ADJXN8b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .marker.cross{stroke:#333333;}#mermaid-svg-Zy9QGDYb2ADJXN8b svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Zy9QGDYb2ADJXN8b p{margin:0;}#mermaid-svg-Zy9QGDYb2ADJXN8b .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster-label text{fill:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster-label span{color:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster-label span p{background-color:transparent;}#mermaid-svg-Zy9QGDYb2ADJXN8b .label text,#mermaid-svg-Zy9QGDYb2ADJXN8b span{fill:#333;color:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .node rect,#mermaid-svg-Zy9QGDYb2ADJXN8b .node circle,#mermaid-svg-Zy9QGDYb2ADJXN8b .node ellipse,#mermaid-svg-Zy9QGDYb2ADJXN8b .node polygon,#mermaid-svg-Zy9QGDYb2ADJXN8b .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .rough-node .label text,#mermaid-svg-Zy9QGDYb2ADJXN8b .node .label text,#mermaid-svg-Zy9QGDYb2ADJXN8b .image-shape .label,#mermaid-svg-Zy9QGDYb2ADJXN8b .icon-shape .label{text-anchor:middle;}#mermaid-svg-Zy9QGDYb2ADJXN8b .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .rough-node .label,#mermaid-svg-Zy9QGDYb2ADJXN8b .node .label,#mermaid-svg-Zy9QGDYb2ADJXN8b .image-shape .label,#mermaid-svg-Zy9QGDYb2ADJXN8b .icon-shape .label{text-align:center;}#mermaid-svg-Zy9QGDYb2ADJXN8b .node.clickable{cursor:pointer;}#mermaid-svg-Zy9QGDYb2ADJXN8b .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .arrowheadPath{fill:#333333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zy9QGDYb2ADJXN8b .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Zy9QGDYb2ADJXN8b .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zy9QGDYb2ADJXN8b .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster text{fill:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b .cluster span{color:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Zy9QGDYb2ADJXN8b .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Zy9QGDYb2ADJXN8b rect.text{fill:none;stroke-width:0;}#mermaid-svg-Zy9QGDYb2ADJXN8b .icon-shape,#mermaid-svg-Zy9QGDYb2ADJXN8b .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zy9QGDYb2ADJXN8b .icon-shape p,#mermaid-svg-Zy9QGDYb2ADJXN8b .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Zy9QGDYb2ADJXN8b .icon-shape .label rect,#mermaid-svg-Zy9QGDYb2ADJXN8b .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zy9QGDYb2ADJXN8b .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Zy9QGDYb2ADJXN8b .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Zy9QGDYb2ADJXN8b :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户请求
Front Door / CorpNet 访问限制
App Service Easy Auth
ApiServiceNg Web App
VNet Integration Subnet
NAT Gateway
Application Insights
Log Analytics
HealthCheckStatus Alert
Web App 使用 Python 3.13,启动命令为 python -u main.py,启用 HTTPS、Always On、HTTP/2 和 /health 健康检查;禁用 FTP、WebSocket,并要求 TLS 1.2。
入口网络默认拒绝,只允许:
- 配置了 ID 时的 Azure Front Door。
CorpNetPublic。CorpNetSAW。
出站流量通过专用集成子网和 NAT Gateway,使出口地址和网络路径可控。子网关闭默认公网出站,并委托给 Microsoft.Web/serverFarms。
身份方面使用 UAMI,而不是把 Client Secret 固定写入 App Settings。应用通过 Managed Identity 获取 Key Vault、Service Bus、Storage 等资源的短期令牌。
六、环境参数为什么单独存放
相同的 Bicep 结构分别配合:
environments/staging.bicepparamenvironments/production.bicepparam
#mermaid-svg-PjgqUechHhmyDSf8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PjgqUechHhmyDSf8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PjgqUechHhmyDSf8 .error-icon{fill:#552222;}#mermaid-svg-PjgqUechHhmyDSf8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PjgqUechHhmyDSf8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PjgqUechHhmyDSf8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PjgqUechHhmyDSf8 .marker.cross{stroke:#333333;}#mermaid-svg-PjgqUechHhmyDSf8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PjgqUechHhmyDSf8 p{margin:0;}#mermaid-svg-PjgqUechHhmyDSf8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PjgqUechHhmyDSf8 .cluster-label text{fill:#333;}#mermaid-svg-PjgqUechHhmyDSf8 .cluster-label span{color:#333;}#mermaid-svg-PjgqUechHhmyDSf8 .cluster-label span p{background-color:transparent;}#mermaid-svg-PjgqUechHhmyDSf8 .label text,#mermaid-svg-PjgqUechHhmyDSf8 span{fill:#333;color:#333;}#mermaid-svg-PjgqUechHhmyDSf8 .node rect,#mermaid-svg-PjgqUechHhmyDSf8 .node circle,#mermaid-svg-PjgqUechHhmyDSf8 .node ellipse,#mermaid-svg-PjgqUechHhmyDSf8 .node polygon,#mermaid-svg-PjgqUechHhmyDSf8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PjgqUechHhmyDSf8 .rough-node .label text,#mermaid-svg-PjgqUechHhmyDSf8 .node .label text,#mermaid-svg-PjgqUechHhmyDSf8 .image-shape .label,#mermaid-svg-PjgqUechHhmyDSf8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-PjgqUechHhmyDSf8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PjgqUechHhmyDSf8 .rough-node .label,#mermaid-svg-PjgqUechHhmyDSf8 .node .label,#mermaid-svg-PjgqUechHhmyDSf8 .image-shape .label,#mermaid-svg-PjgqUechHhmyDSf8 .icon-shape .label{text-align:center;}#mermaid-svg-PjgqUechHhmyDSf8 .node.clickable{cursor:pointer;}#mermaid-svg-PjgqUechHhmyDSf8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PjgqUechHhmyDSf8 .arrowheadPath{fill:#333333;}#mermaid-svg-PjgqUechHhmyDSf8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PjgqUechHhmyDSf8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PjgqUechHhmyDSf8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PjgqUechHhmyDSf8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PjgqUechHhmyDSf8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PjgqUechHhmyDSf8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PjgqUechHhmyDSf8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PjgqUechHhmyDSf8 .cluster text{fill:#333;}#mermaid-svg-PjgqUechHhmyDSf8 .cluster span{color:#333;}#mermaid-svg-PjgqUechHhmyDSf8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PjgqUechHhmyDSf8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PjgqUechHhmyDSf8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-PjgqUechHhmyDSf8 .icon-shape,#mermaid-svg-PjgqUechHhmyDSf8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PjgqUechHhmyDSf8 .icon-shape p,#mermaid-svg-PjgqUechHhmyDSf8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PjgqUechHhmyDSf8 .icon-shape .label rect,#mermaid-svg-PjgqUechHhmyDSf8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PjgqUechHhmyDSf8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PjgqUechHhmyDSf8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PjgqUechHhmyDSf8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 同一 main.bicep
Staging 参数
Production 参数
Corp Subscription
PME Subscription
环境参数控制订阅、资源组、SKU、VNet、应用名、身份、监控和外部服务地址。这样架构结构只有一份,不会出现 main-staging.bicep 和 main-prod.bicep 长期分叉。
为什么不把所有参数放进 Pipeline 变量?Pipeline 变量适合服务连接和执行路由;复杂嵌套架构放在 .bicepparam 中更容易类型检查和 Code Review。敏感值则不应进入参数文件,而应由安全 Pipeline 参数或 Key Vault 注入。
七、Bicep CI 为什么只做 What-If
基础设施 CI 的流程是:
#mermaid-svg-C0IWtS1NspLU5qTI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-C0IWtS1NspLU5qTI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-C0IWtS1NspLU5qTI .error-icon{fill:#552222;}#mermaid-svg-C0IWtS1NspLU5qTI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-C0IWtS1NspLU5qTI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-C0IWtS1NspLU5qTI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-C0IWtS1NspLU5qTI .marker.cross{stroke:#333333;}#mermaid-svg-C0IWtS1NspLU5qTI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-C0IWtS1NspLU5qTI p{margin:0;}#mermaid-svg-C0IWtS1NspLU5qTI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-C0IWtS1NspLU5qTI .cluster-label text{fill:#333;}#mermaid-svg-C0IWtS1NspLU5qTI .cluster-label span{color:#333;}#mermaid-svg-C0IWtS1NspLU5qTI .cluster-label span p{background-color:transparent;}#mermaid-svg-C0IWtS1NspLU5qTI .label text,#mermaid-svg-C0IWtS1NspLU5qTI span{fill:#333;color:#333;}#mermaid-svg-C0IWtS1NspLU5qTI .node rect,#mermaid-svg-C0IWtS1NspLU5qTI .node circle,#mermaid-svg-C0IWtS1NspLU5qTI .node ellipse,#mermaid-svg-C0IWtS1NspLU5qTI .node polygon,#mermaid-svg-C0IWtS1NspLU5qTI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-C0IWtS1NspLU5qTI .rough-node .label text,#mermaid-svg-C0IWtS1NspLU5qTI .node .label text,#mermaid-svg-C0IWtS1NspLU5qTI .image-shape .label,#mermaid-svg-C0IWtS1NspLU5qTI .icon-shape .label{text-anchor:middle;}#mermaid-svg-C0IWtS1NspLU5qTI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-C0IWtS1NspLU5qTI .rough-node .label,#mermaid-svg-C0IWtS1NspLU5qTI .node .label,#mermaid-svg-C0IWtS1NspLU5qTI .image-shape .label,#mermaid-svg-C0IWtS1NspLU5qTI .icon-shape .label{text-align:center;}#mermaid-svg-C0IWtS1NspLU5qTI .node.clickable{cursor:pointer;}#mermaid-svg-C0IWtS1NspLU5qTI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-C0IWtS1NspLU5qTI .arrowheadPath{fill:#333333;}#mermaid-svg-C0IWtS1NspLU5qTI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-C0IWtS1NspLU5qTI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-C0IWtS1NspLU5qTI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C0IWtS1NspLU5qTI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-C0IWtS1NspLU5qTI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C0IWtS1NspLU5qTI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-C0IWtS1NspLU5qTI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-C0IWtS1NspLU5qTI .cluster text{fill:#333;}#mermaid-svg-C0IWtS1NspLU5qTI .cluster span{color:#333;}#mermaid-svg-C0IWtS1NspLU5qTI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-C0IWtS1NspLU5qTI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-C0IWtS1NspLU5qTI rect.text{fill:none;stroke-width:0;}#mermaid-svg-C0IWtS1NspLU5qTI .icon-shape,#mermaid-svg-C0IWtS1NspLU5qTI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C0IWtS1NspLU5qTI .icon-shape p,#mermaid-svg-C0IWtS1NspLU5qTI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-C0IWtS1NspLU5qTI .icon-shape .label rect,#mermaid-svg-C0IWtS1NspLU5qTI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C0IWtS1NspLU5qTI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-C0IWtS1NspLU5qTI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-C0IWtS1NspLU5qTI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不自动部署
提交 IaC PR
编译所有 Bicep
编译所有 bicepparam
Staging What-If
Production What-If
审查资源差异
CI 完成
CI 固定使用 Bicep 0.45.15,避免不同 Agent 使用不同编译器产生差异。它同时对 Staging 和 Production 运行 what-if,并使用 FullResourcePayloads 展示属性级变化,但不会执行部署。
为什么 PR Pipeline 不自动部署 Staging?基础设施变更可能删除子网、修改身份或改变公网访问。代码测试通过并不代表资源变更安全。What-If 相当于基础设施的 git diff,先让评审者看到 Azure 将执行什么。
真正部署使用独立的手工 Pipeline:
#mermaid-svg-LoxN7f2XqzKQnQvv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LoxN7f2XqzKQnQvv .error-icon{fill:#552222;}#mermaid-svg-LoxN7f2XqzKQnQvv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LoxN7f2XqzKQnQvv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LoxN7f2XqzKQnQvv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LoxN7f2XqzKQnQvv .marker.cross{stroke:#333333;}#mermaid-svg-LoxN7f2XqzKQnQvv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LoxN7f2XqzKQnQvv p{margin:0;}#mermaid-svg-LoxN7f2XqzKQnQvv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster-label text{fill:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster-label span{color:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster-label span p{background-color:transparent;}#mermaid-svg-LoxN7f2XqzKQnQvv .label text,#mermaid-svg-LoxN7f2XqzKQnQvv span{fill:#333;color:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv .node rect,#mermaid-svg-LoxN7f2XqzKQnQvv .node circle,#mermaid-svg-LoxN7f2XqzKQnQvv .node ellipse,#mermaid-svg-LoxN7f2XqzKQnQvv .node polygon,#mermaid-svg-LoxN7f2XqzKQnQvv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LoxN7f2XqzKQnQvv .rough-node .label text,#mermaid-svg-LoxN7f2XqzKQnQvv .node .label text,#mermaid-svg-LoxN7f2XqzKQnQvv .image-shape .label,#mermaid-svg-LoxN7f2XqzKQnQvv .icon-shape .label{text-anchor:middle;}#mermaid-svg-LoxN7f2XqzKQnQvv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LoxN7f2XqzKQnQvv .rough-node .label,#mermaid-svg-LoxN7f2XqzKQnQvv .node .label,#mermaid-svg-LoxN7f2XqzKQnQvv .image-shape .label,#mermaid-svg-LoxN7f2XqzKQnQvv .icon-shape .label{text-align:center;}#mermaid-svg-LoxN7f2XqzKQnQvv .node.clickable{cursor:pointer;}#mermaid-svg-LoxN7f2XqzKQnQvv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LoxN7f2XqzKQnQvv .arrowheadPath{fill:#333333;}#mermaid-svg-LoxN7f2XqzKQnQvv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LoxN7f2XqzKQnQvv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LoxN7f2XqzKQnQvv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LoxN7f2XqzKQnQvv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LoxN7f2XqzKQnQvv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LoxN7f2XqzKQnQvv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster text{fill:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv .cluster span{color:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LoxN7f2XqzKQnQvv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LoxN7f2XqzKQnQvv rect.text{fill:none;stroke-width:0;}#mermaid-svg-LoxN7f2XqzKQnQvv .icon-shape,#mermaid-svg-LoxN7f2XqzKQnQvv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LoxN7f2XqzKQnQvv .icon-shape p,#mermaid-svg-LoxN7f2XqzKQnQvv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LoxN7f2XqzKQnQvv .icon-shape .label rect,#mermaid-svg-LoxN7f2XqzKQnQvv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LoxN7f2XqzKQnQvv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LoxN7f2XqzKQnQvv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LoxN7f2XqzKQnQvv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 默认 true
false
手工启动
dryRun?
只运行 What-If
人工审批
Incremental Deployment
默认 dryRun=true 是 Fail-Closed 设计:操作者必须明确选择真实部署,并在看过 What-If 后再次审批。
八、EV2 CI 怎样生成发布物
ApiServiceNg CI 首先使用 Python 3.13 安装依赖并运行完整测试。只有满足以下条件时才发布 EV2 Artifact:
main分支自动 CI。- 或手工运行并设置
publishEv2=true。
#mermaid-svg-2rCN2rhCwk6tLT3e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2rCN2rhCwk6tLT3e .error-icon{fill:#552222;}#mermaid-svg-2rCN2rhCwk6tLT3e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2rCN2rhCwk6tLT3e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2rCN2rhCwk6tLT3e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2rCN2rhCwk6tLT3e .marker.cross{stroke:#333333;}#mermaid-svg-2rCN2rhCwk6tLT3e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2rCN2rhCwk6tLT3e p{margin:0;}#mermaid-svg-2rCN2rhCwk6tLT3e .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster-label text{fill:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster-label span{color:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster-label span p{background-color:transparent;}#mermaid-svg-2rCN2rhCwk6tLT3e .label text,#mermaid-svg-2rCN2rhCwk6tLT3e span{fill:#333;color:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e .node rect,#mermaid-svg-2rCN2rhCwk6tLT3e .node circle,#mermaid-svg-2rCN2rhCwk6tLT3e .node ellipse,#mermaid-svg-2rCN2rhCwk6tLT3e .node polygon,#mermaid-svg-2rCN2rhCwk6tLT3e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2rCN2rhCwk6tLT3e .rough-node .label text,#mermaid-svg-2rCN2rhCwk6tLT3e .node .label text,#mermaid-svg-2rCN2rhCwk6tLT3e .image-shape .label,#mermaid-svg-2rCN2rhCwk6tLT3e .icon-shape .label{text-anchor:middle;}#mermaid-svg-2rCN2rhCwk6tLT3e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2rCN2rhCwk6tLT3e .rough-node .label,#mermaid-svg-2rCN2rhCwk6tLT3e .node .label,#mermaid-svg-2rCN2rhCwk6tLT3e .image-shape .label,#mermaid-svg-2rCN2rhCwk6tLT3e .icon-shape .label{text-align:center;}#mermaid-svg-2rCN2rhCwk6tLT3e .node.clickable{cursor:pointer;}#mermaid-svg-2rCN2rhCwk6tLT3e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2rCN2rhCwk6tLT3e .arrowheadPath{fill:#333333;}#mermaid-svg-2rCN2rhCwk6tLT3e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2rCN2rhCwk6tLT3e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2rCN2rhCwk6tLT3e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2rCN2rhCwk6tLT3e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2rCN2rhCwk6tLT3e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2rCN2rhCwk6tLT3e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster text{fill:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e .cluster span{color:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2rCN2rhCwk6tLT3e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2rCN2rhCwk6tLT3e rect.text{fill:none;stroke-width:0;}#mermaid-svg-2rCN2rhCwk6tLT3e .icon-shape,#mermaid-svg-2rCN2rhCwk6tLT3e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2rCN2rhCwk6tLT3e .icon-shape p,#mermaid-svg-2rCN2rhCwk6tLT3e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2rCN2rhCwk6tLT3e .icon-shape .label rect,#mermaid-svg-2rCN2rhCwk6tLT3e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2rCN2rhCwk6tLT3e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2rCN2rhCwk6tLT3e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2rCN2rhCwk6tLT3e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ApiServiceNg 源码
pytest
ESRP 代码签名
写入 deploy-metadata.json
生成 ApiServiceNg.zip
组合 EV2 Service Root
drop-ev2
PR 构建默认不会生成可部署 Artifact,避免未经合并的代码自然进入发布渠道。手工构建仍可显式生成,方便受控测试。
deploy-metadata.json 记录 Branch、Commit SHA、Build ID、Build Number、时间和触发原因,使线上 ZIP 可以追溯到具体源码。
九、EV2 Service Root 是什么
EV2 发布包不是只有 ZIP,而是一整套声明:
#mermaid-svg-hTxlpq6CtSbjbHNe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hTxlpq6CtSbjbHNe .error-icon{fill:#552222;}#mermaid-svg-hTxlpq6CtSbjbHNe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hTxlpq6CtSbjbHNe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hTxlpq6CtSbjbHNe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hTxlpq6CtSbjbHNe .marker.cross{stroke:#333333;}#mermaid-svg-hTxlpq6CtSbjbHNe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hTxlpq6CtSbjbHNe p{margin:0;}#mermaid-svg-hTxlpq6CtSbjbHNe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster-label text{fill:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster-label span{color:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster-label span p{background-color:transparent;}#mermaid-svg-hTxlpq6CtSbjbHNe .label text,#mermaid-svg-hTxlpq6CtSbjbHNe span{fill:#333;color:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe .node rect,#mermaid-svg-hTxlpq6CtSbjbHNe .node circle,#mermaid-svg-hTxlpq6CtSbjbHNe .node ellipse,#mermaid-svg-hTxlpq6CtSbjbHNe .node polygon,#mermaid-svg-hTxlpq6CtSbjbHNe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hTxlpq6CtSbjbHNe .rough-node .label text,#mermaid-svg-hTxlpq6CtSbjbHNe .node .label text,#mermaid-svg-hTxlpq6CtSbjbHNe .image-shape .label,#mermaid-svg-hTxlpq6CtSbjbHNe .icon-shape .label{text-anchor:middle;}#mermaid-svg-hTxlpq6CtSbjbHNe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hTxlpq6CtSbjbHNe .rough-node .label,#mermaid-svg-hTxlpq6CtSbjbHNe .node .label,#mermaid-svg-hTxlpq6CtSbjbHNe .image-shape .label,#mermaid-svg-hTxlpq6CtSbjbHNe .icon-shape .label{text-align:center;}#mermaid-svg-hTxlpq6CtSbjbHNe .node.clickable{cursor:pointer;}#mermaid-svg-hTxlpq6CtSbjbHNe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hTxlpq6CtSbjbHNe .arrowheadPath{fill:#333333;}#mermaid-svg-hTxlpq6CtSbjbHNe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hTxlpq6CtSbjbHNe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hTxlpq6CtSbjbHNe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hTxlpq6CtSbjbHNe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hTxlpq6CtSbjbHNe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hTxlpq6CtSbjbHNe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster text{fill:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe .cluster span{color:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hTxlpq6CtSbjbHNe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hTxlpq6CtSbjbHNe rect.text{fill:none;stroke-width:0;}#mermaid-svg-hTxlpq6CtSbjbHNe .icon-shape,#mermaid-svg-hTxlpq6CtSbjbHNe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hTxlpq6CtSbjbHNe .icon-shape p,#mermaid-svg-hTxlpq6CtSbjbHNe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hTxlpq6CtSbjbHNe .icon-shape .label rect,#mermaid-svg-hTxlpq6CtSbjbHNe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hTxlpq6CtSbjbHNe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hTxlpq6CtSbjbHNe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hTxlpq6CtSbjbHNe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} EV2 Service Root
rolloutSpec.json
serviceModel.json
scopeBindings.json
configurationSpec.json
rolloutParameters.json
azuredeploy.json
bin/ApiServiceNg.zip
version.txt
- serviceModel.json:服务部署到哪个订阅和资源组。
- rolloutSpec.json:部署和验证步骤的顺序。
- scopeBindings.json:把占位符替换为目标环境值。
- configurationSpec.json:允许 CD 提供哪些环境配置。
- azuredeploy.json:执行 Web App ZipDeploy。
- rolloutParameters.json:定义部署后健康检查。
- version.txt:标识发布版本。
配置文件使用占位符而不是直接写死 Staging/Production 值。CD Pipeline 再通过 configurationOverrides 注入目标订阅、Web App、区域和告警名称。因此同一份 drop-ev2 可以经过验证后从 Staging 提升到 Production,不需要重新编译代码。
十、一次 EV2 发布怎样执行
AlertsManagement Existing Web App Azure Resource Manager EV2 CD Pipeline AlertsManagement Existing Web App Azure Resource Manager EV2 CD Pipeline #mermaid-svg-LAjjCBRlDQIS1Qq0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .error-icon{fill:#552222;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .marker.cross{stroke:#333333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LAjjCBRlDQIS1Qq0 p{margin:0;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LAjjCBRlDQIS1Qq0 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-LAjjCBRlDQIS1Qq0 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .sequenceNumber{fill:white;}#mermaid-svg-LAjjCBRlDQIS1Qq0 #sequencenumber{fill:#333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .messageText{fill:#333;stroke:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .labelText,#mermaid-svg-LAjjCBRlDQIS1Qq0 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .loopText,#mermaid-svg-LAjjCBRlDQIS1Qq0 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-LAjjCBRlDQIS1Qq0 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .noteText,#mermaid-svg-LAjjCBRlDQIS1Qq0 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actorPopupMenu{position:absolute;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LAjjCBRlDQIS1Qq0 .actor-man circle,#mermaid-svg-LAjjCBRlDQIS1Qq0 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-LAjjCBRlDQIS1Qq0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} drop-ev2 + 环境覆盖参数部署 sites/extensions/ZipDeploy下载并安装 ApiServiceNg.zip查询指定健康指标告警value = \[\]发布成功
这里 EV2 不负责创建 Web App。它假设 Bicep 已经部署好 App Service、身份、网络、诊断设置和健康告警,然后只更新应用包。
这意味着正确顺序是:
#mermaid-svg-zAGX0Udi1SY9pgkN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zAGX0Udi1SY9pgkN .error-icon{fill:#552222;}#mermaid-svg-zAGX0Udi1SY9pgkN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zAGX0Udi1SY9pgkN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zAGX0Udi1SY9pgkN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zAGX0Udi1SY9pgkN .marker.cross{stroke:#333333;}#mermaid-svg-zAGX0Udi1SY9pgkN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zAGX0Udi1SY9pgkN p{margin:0;}#mermaid-svg-zAGX0Udi1SY9pgkN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster-label text{fill:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster-label span{color:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster-label span p{background-color:transparent;}#mermaid-svg-zAGX0Udi1SY9pgkN .label text,#mermaid-svg-zAGX0Udi1SY9pgkN span{fill:#333;color:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN .node rect,#mermaid-svg-zAGX0Udi1SY9pgkN .node circle,#mermaid-svg-zAGX0Udi1SY9pgkN .node ellipse,#mermaid-svg-zAGX0Udi1SY9pgkN .node polygon,#mermaid-svg-zAGX0Udi1SY9pgkN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zAGX0Udi1SY9pgkN .rough-node .label text,#mermaid-svg-zAGX0Udi1SY9pgkN .node .label text,#mermaid-svg-zAGX0Udi1SY9pgkN .image-shape .label,#mermaid-svg-zAGX0Udi1SY9pgkN .icon-shape .label{text-anchor:middle;}#mermaid-svg-zAGX0Udi1SY9pgkN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zAGX0Udi1SY9pgkN .rough-node .label,#mermaid-svg-zAGX0Udi1SY9pgkN .node .label,#mermaid-svg-zAGX0Udi1SY9pgkN .image-shape .label,#mermaid-svg-zAGX0Udi1SY9pgkN .icon-shape .label{text-align:center;}#mermaid-svg-zAGX0Udi1SY9pgkN .node.clickable{cursor:pointer;}#mermaid-svg-zAGX0Udi1SY9pgkN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zAGX0Udi1SY9pgkN .arrowheadPath{fill:#333333;}#mermaid-svg-zAGX0Udi1SY9pgkN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zAGX0Udi1SY9pgkN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zAGX0Udi1SY9pgkN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zAGX0Udi1SY9pgkN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zAGX0Udi1SY9pgkN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zAGX0Udi1SY9pgkN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster text{fill:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN .cluster span{color:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zAGX0Udi1SY9pgkN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zAGX0Udi1SY9pgkN rect.text{fill:none;stroke-width:0;}#mermaid-svg-zAGX0Udi1SY9pgkN .icon-shape,#mermaid-svg-zAGX0Udi1SY9pgkN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zAGX0Udi1SY9pgkN .icon-shape p,#mermaid-svg-zAGX0Udi1SY9pgkN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zAGX0Udi1SY9pgkN .icon-shape .label rect,#mermaid-svg-zAGX0Udi1SY9pgkN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zAGX0Udi1SY9pgkN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zAGX0Udi1SY9pgkN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zAGX0Udi1SY9pgkN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Bicep 部署基础设施
健康告警存在
CI 生成 drop-ev2
EV2 validateOnly
Staging Rollout
Production Approval + Rollout
十一、为什么健康检查查询告警,而不直接访问 /health
EV2 的部署后检查会调用 Azure AlertsManagement API,要求目标 Metric Alert 没有 Fired,而不是直接请求 Web App /health。
#mermaid-svg-i8UGskJbrdTjJl7c{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-i8UGskJbrdTjJl7c .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-i8UGskJbrdTjJl7c .error-icon{fill:#552222;}#mermaid-svg-i8UGskJbrdTjJl7c .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i8UGskJbrdTjJl7c .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i8UGskJbrdTjJl7c .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i8UGskJbrdTjJl7c .marker.cross{stroke:#333333;}#mermaid-svg-i8UGskJbrdTjJl7c svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i8UGskJbrdTjJl7c p{margin:0;}#mermaid-svg-i8UGskJbrdTjJl7c .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-i8UGskJbrdTjJl7c .cluster-label text{fill:#333;}#mermaid-svg-i8UGskJbrdTjJl7c .cluster-label span{color:#333;}#mermaid-svg-i8UGskJbrdTjJl7c .cluster-label span p{background-color:transparent;}#mermaid-svg-i8UGskJbrdTjJl7c .label text,#mermaid-svg-i8UGskJbrdTjJl7c span{fill:#333;color:#333;}#mermaid-svg-i8UGskJbrdTjJl7c .node rect,#mermaid-svg-i8UGskJbrdTjJl7c .node circle,#mermaid-svg-i8UGskJbrdTjJl7c .node ellipse,#mermaid-svg-i8UGskJbrdTjJl7c .node polygon,#mermaid-svg-i8UGskJbrdTjJl7c .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i8UGskJbrdTjJl7c .rough-node .label text,#mermaid-svg-i8UGskJbrdTjJl7c .node .label text,#mermaid-svg-i8UGskJbrdTjJl7c .image-shape .label,#mermaid-svg-i8UGskJbrdTjJl7c .icon-shape .label{text-anchor:middle;}#mermaid-svg-i8UGskJbrdTjJl7c .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-i8UGskJbrdTjJl7c .rough-node .label,#mermaid-svg-i8UGskJbrdTjJl7c .node .label,#mermaid-svg-i8UGskJbrdTjJl7c .image-shape .label,#mermaid-svg-i8UGskJbrdTjJl7c .icon-shape .label{text-align:center;}#mermaid-svg-i8UGskJbrdTjJl7c .node.clickable{cursor:pointer;}#mermaid-svg-i8UGskJbrdTjJl7c .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-i8UGskJbrdTjJl7c .arrowheadPath{fill:#333333;}#mermaid-svg-i8UGskJbrdTjJl7c .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i8UGskJbrdTjJl7c .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i8UGskJbrdTjJl7c .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i8UGskJbrdTjJl7c .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-i8UGskJbrdTjJl7c .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i8UGskJbrdTjJl7c .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-i8UGskJbrdTjJl7c .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i8UGskJbrdTjJl7c .cluster text{fill:#333;}#mermaid-svg-i8UGskJbrdTjJl7c .cluster span{color:#333;}#mermaid-svg-i8UGskJbrdTjJl7c div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i8UGskJbrdTjJl7c .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-i8UGskJbrdTjJl7c rect.text{fill:none;stroke-width:0;}#mermaid-svg-i8UGskJbrdTjJl7c .icon-shape,#mermaid-svg-i8UGskJbrdTjJl7c .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i8UGskJbrdTjJl7c .icon-shape p,#mermaid-svg-i8UGskJbrdTjJl7c .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-i8UGskJbrdTjJl7c .icon-shape .label rect,#mermaid-svg-i8UGskJbrdTjJl7c .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i8UGskJbrdTjJl7c .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-i8UGskJbrdTjJl7c .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-i8UGskJbrdTjJl7c :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} health
HealthCheckStatus Metric
Azure Monitor Alert
EV2
AlertsManagement Query
没有 Fired Alert?
这样设计有几个优势:
- EV2 不需要穿过 CorpNet、Front Door 或 App Service IP 限制。
- 使用 Rollout Identity 调用 Azure Management Plane,身份边界统一。
- 验证的是一段时间内的健康状态,而不是单次 HTTP 碰巧成功。
- 告警同时服务正常运营和发布门禁。
代价是告警存在采样和传播延迟,而且必须先由 Bicep 部署正确。它不能完全替代端到端功能测试,只能回答"平台健康指标是否异常"。
十二、Staging 和 Production 为什么分开
Staging 与 Production 使用独立 CD Pipeline,而不是一个 Pipeline 通过下拉框随意切环境。
| 设计 | 优点 | 风险 |
|---|---|---|
| 一个 Pipeline 动态选择环境 | 文件少、复用高 | 变量选错就可能操作生产 |
| 独立 Staging/Production Pipeline | 目标订阅和连接固定 | 有少量 YAML 重复 |
| 自动部署 Production | 发布快 | 错误直接进入生产 |
| Production Approval | 多一道人工门禁 | 发布稍慢 |
当前设计让 Production Pipeline 固定 PME 订阅、生产资源组和生产参数,并使用 Approval Service。两个 EV2 Pipeline 都默认 validateOnly=true,所以第一次运行通常只验证注册和 Service Root,不会发布。
紧急情况可以选择 emergency 或 globaloutage SDP 类型;globaloutage 还要求 IcM Incident ID,避免日常发布滥用紧急通道。
十三、Service Tree 和订阅注册是什么
serviceSpecification.json 将该发布系统绑定到 Service Tree ID:
text
5454a423-698a-466e-ba6e-abcf19960ed9
#mermaid-svg-PtZFGxOZLtfK729V{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PtZFGxOZLtfK729V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PtZFGxOZLtfK729V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PtZFGxOZLtfK729V .error-icon{fill:#552222;}#mermaid-svg-PtZFGxOZLtfK729V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PtZFGxOZLtfK729V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PtZFGxOZLtfK729V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PtZFGxOZLtfK729V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PtZFGxOZLtfK729V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PtZFGxOZLtfK729V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PtZFGxOZLtfK729V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PtZFGxOZLtfK729V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PtZFGxOZLtfK729V .marker.cross{stroke:#333333;}#mermaid-svg-PtZFGxOZLtfK729V svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PtZFGxOZLtfK729V p{margin:0;}#mermaid-svg-PtZFGxOZLtfK729V .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PtZFGxOZLtfK729V .cluster-label text{fill:#333;}#mermaid-svg-PtZFGxOZLtfK729V .cluster-label span{color:#333;}#mermaid-svg-PtZFGxOZLtfK729V .cluster-label span p{background-color:transparent;}#mermaid-svg-PtZFGxOZLtfK729V .label text,#mermaid-svg-PtZFGxOZLtfK729V span{fill:#333;color:#333;}#mermaid-svg-PtZFGxOZLtfK729V .node rect,#mermaid-svg-PtZFGxOZLtfK729V .node circle,#mermaid-svg-PtZFGxOZLtfK729V .node ellipse,#mermaid-svg-PtZFGxOZLtfK729V .node polygon,#mermaid-svg-PtZFGxOZLtfK729V .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PtZFGxOZLtfK729V .rough-node .label text,#mermaid-svg-PtZFGxOZLtfK729V .node .label text,#mermaid-svg-PtZFGxOZLtfK729V .image-shape .label,#mermaid-svg-PtZFGxOZLtfK729V .icon-shape .label{text-anchor:middle;}#mermaid-svg-PtZFGxOZLtfK729V .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PtZFGxOZLtfK729V .rough-node .label,#mermaid-svg-PtZFGxOZLtfK729V .node .label,#mermaid-svg-PtZFGxOZLtfK729V .image-shape .label,#mermaid-svg-PtZFGxOZLtfK729V .icon-shape .label{text-align:center;}#mermaid-svg-PtZFGxOZLtfK729V .node.clickable{cursor:pointer;}#mermaid-svg-PtZFGxOZLtfK729V .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PtZFGxOZLtfK729V .arrowheadPath{fill:#333333;}#mermaid-svg-PtZFGxOZLtfK729V .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PtZFGxOZLtfK729V .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PtZFGxOZLtfK729V .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PtZFGxOZLtfK729V .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PtZFGxOZLtfK729V .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PtZFGxOZLtfK729V .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PtZFGxOZLtfK729V .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PtZFGxOZLtfK729V .cluster text{fill:#333;}#mermaid-svg-PtZFGxOZLtfK729V .cluster span{color:#333;}#mermaid-svg-PtZFGxOZLtfK729V div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PtZFGxOZLtfK729V .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PtZFGxOZLtfK729V rect.text{fill:none;stroke-width:0;}#mermaid-svg-PtZFGxOZLtfK729V .icon-shape,#mermaid-svg-PtZFGxOZLtfK729V .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PtZFGxOZLtfK729V .icon-shape p,#mermaid-svg-PtZFGxOZLtfK729V .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PtZFGxOZLtfK729V .icon-shape .label rect,#mermaid-svg-PtZFGxOZLtfK729V .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PtZFGxOZLtfK729V .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PtZFGxOZLtfK729V .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PtZFGxOZLtfK729V :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Service Tree 服务身份
EV2 Service Group
Corp Test Subscription Key
PME Prod Subscription Key
Staging Subscription
Production Subscription
订阅必须先注册到 EV2 服务身份和对应 Rollout Infra。否则 Service Root 即使格式正确,也没有权利把逻辑 subscriptionKey 解析成真实订阅。
仓库中的注册命令属于基础准备,不应在每次发布时重复运行,也不应由普通 CI 自动执行。
十四、为什么使用 Bicep,而不是 Terraform
Terraform 当然可以实现类似效果,但当前项目的目标资源高度 Azure 原生:
- App Service、ARM What-If、Managed Identity。
- Azure Monitor、Log Analytics。
- Azure RBAC、VNet Integration。
- EV2 最终也调用 ARM。
Bicep 直接编译成 ARM JSON,不需要额外 State Backend。Azure 是真实状态源,部署采用声明式收敛。
| Bicep | Terraform |
|---|---|
| Azure 原生类型和 API 支持快 | 多云生态更强 |
| 无独立 State 文件 | 依赖 Terraform State |
| ARM What-If 与 EV2 衔接自然 | Plan 体验成熟 |
| 更适合纯 Azure 项目 | 更适合跨云或多 Provider |
如果 DigitalEmployee 需要统一管理 Azure、AWS、GitHub、Datadog 等多种 Provider,Terraform 的价值会增加;当前纯 Azure 部署使用 Bicep更直接。
十五、Checkov 在这里扮演什么角色
根目录 .checkov.yaml 配置了安全扫描排除路径:
docs/debug- archived
- 本地或模板 Runner Pod Spec
#mermaid-svg-2DBT31jArVPG7jKb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2DBT31jArVPG7jKb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2DBT31jArVPG7jKb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2DBT31jArVPG7jKb .error-icon{fill:#552222;}#mermaid-svg-2DBT31jArVPG7jKb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2DBT31jArVPG7jKb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2DBT31jArVPG7jKb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2DBT31jArVPG7jKb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2DBT31jArVPG7jKb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2DBT31jArVPG7jKb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2DBT31jArVPG7jKb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2DBT31jArVPG7jKb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2DBT31jArVPG7jKb .marker.cross{stroke:#333333;}#mermaid-svg-2DBT31jArVPG7jKb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2DBT31jArVPG7jKb p{margin:0;}#mermaid-svg-2DBT31jArVPG7jKb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2DBT31jArVPG7jKb .cluster-label text{fill:#333;}#mermaid-svg-2DBT31jArVPG7jKb .cluster-label span{color:#333;}#mermaid-svg-2DBT31jArVPG7jKb .cluster-label span p{background-color:transparent;}#mermaid-svg-2DBT31jArVPG7jKb .label text,#mermaid-svg-2DBT31jArVPG7jKb span{fill:#333;color:#333;}#mermaid-svg-2DBT31jArVPG7jKb .node rect,#mermaid-svg-2DBT31jArVPG7jKb .node circle,#mermaid-svg-2DBT31jArVPG7jKb .node ellipse,#mermaid-svg-2DBT31jArVPG7jKb .node polygon,#mermaid-svg-2DBT31jArVPG7jKb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2DBT31jArVPG7jKb .rough-node .label text,#mermaid-svg-2DBT31jArVPG7jKb .node .label text,#mermaid-svg-2DBT31jArVPG7jKb .image-shape .label,#mermaid-svg-2DBT31jArVPG7jKb .icon-shape .label{text-anchor:middle;}#mermaid-svg-2DBT31jArVPG7jKb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2DBT31jArVPG7jKb .rough-node .label,#mermaid-svg-2DBT31jArVPG7jKb .node .label,#mermaid-svg-2DBT31jArVPG7jKb .image-shape .label,#mermaid-svg-2DBT31jArVPG7jKb .icon-shape .label{text-align:center;}#mermaid-svg-2DBT31jArVPG7jKb .node.clickable{cursor:pointer;}#mermaid-svg-2DBT31jArVPG7jKb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2DBT31jArVPG7jKb .arrowheadPath{fill:#333333;}#mermaid-svg-2DBT31jArVPG7jKb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2DBT31jArVPG7jKb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2DBT31jArVPG7jKb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DBT31jArVPG7jKb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2DBT31jArVPG7jKb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DBT31jArVPG7jKb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2DBT31jArVPG7jKb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2DBT31jArVPG7jKb .cluster text{fill:#333;}#mermaid-svg-2DBT31jArVPG7jKb .cluster span{color:#333;}#mermaid-svg-2DBT31jArVPG7jKb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2DBT31jArVPG7jKb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2DBT31jArVPG7jKb rect.text{fill:none;stroke-width:0;}#mermaid-svg-2DBT31jArVPG7jKb .icon-shape,#mermaid-svg-2DBT31jArVPG7jKb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DBT31jArVPG7jKb .icon-shape p,#mermaid-svg-2DBT31jArVPG7jKb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2DBT31jArVPG7jKb .icon-shape .label rect,#mermaid-svg-2DBT31jArVPG7jKb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DBT31jArVPG7jKb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2DBT31jArVPG7jKb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2DBT31jArVPG7jKb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 跳过
IaC 与配置
Checkov 静态安全检查
错误配置发现
明确排除的非部署样例
排除归档文件是合理的,因为旧 ARM 快照并不代表当前部署;扫描它会产生不可执行的历史告警。排除 Runner 本地模板则说明它们不是最终部署清单。不过排除项应保持最少,并写清原因,否则真正的部署风险可能被静默跳过。
仅凭当前读取到的文件,能确认 Checkov 配置存在,但不能断言这个分支的所有 Pipeline 都已经执行 Checkov;Bicep CI 中明确可见的是 Bicep Build、1ES SDL 和 Azure What-If。
十六、实际修改应该怎么做
修改基础设施时:
#mermaid-svg-ytFse2qAQzmi4xaY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ytFse2qAQzmi4xaY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ytFse2qAQzmi4xaY .error-icon{fill:#552222;}#mermaid-svg-ytFse2qAQzmi4xaY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ytFse2qAQzmi4xaY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ytFse2qAQzmi4xaY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ytFse2qAQzmi4xaY .marker.cross{stroke:#333333;}#mermaid-svg-ytFse2qAQzmi4xaY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ytFse2qAQzmi4xaY p{margin:0;}#mermaid-svg-ytFse2qAQzmi4xaY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ytFse2qAQzmi4xaY .cluster-label text{fill:#333;}#mermaid-svg-ytFse2qAQzmi4xaY .cluster-label span{color:#333;}#mermaid-svg-ytFse2qAQzmi4xaY .cluster-label span p{background-color:transparent;}#mermaid-svg-ytFse2qAQzmi4xaY .label text,#mermaid-svg-ytFse2qAQzmi4xaY span{fill:#333;color:#333;}#mermaid-svg-ytFse2qAQzmi4xaY .node rect,#mermaid-svg-ytFse2qAQzmi4xaY .node circle,#mermaid-svg-ytFse2qAQzmi4xaY .node ellipse,#mermaid-svg-ytFse2qAQzmi4xaY .node polygon,#mermaid-svg-ytFse2qAQzmi4xaY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ytFse2qAQzmi4xaY .rough-node .label text,#mermaid-svg-ytFse2qAQzmi4xaY .node .label text,#mermaid-svg-ytFse2qAQzmi4xaY .image-shape .label,#mermaid-svg-ytFse2qAQzmi4xaY .icon-shape .label{text-anchor:middle;}#mermaid-svg-ytFse2qAQzmi4xaY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ytFse2qAQzmi4xaY .rough-node .label,#mermaid-svg-ytFse2qAQzmi4xaY .node .label,#mermaid-svg-ytFse2qAQzmi4xaY .image-shape .label,#mermaid-svg-ytFse2qAQzmi4xaY .icon-shape .label{text-align:center;}#mermaid-svg-ytFse2qAQzmi4xaY .node.clickable{cursor:pointer;}#mermaid-svg-ytFse2qAQzmi4xaY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ytFse2qAQzmi4xaY .arrowheadPath{fill:#333333;}#mermaid-svg-ytFse2qAQzmi4xaY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ytFse2qAQzmi4xaY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ytFse2qAQzmi4xaY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ytFse2qAQzmi4xaY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ytFse2qAQzmi4xaY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ytFse2qAQzmi4xaY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ytFse2qAQzmi4xaY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ytFse2qAQzmi4xaY .cluster text{fill:#333;}#mermaid-svg-ytFse2qAQzmi4xaY .cluster span{color:#333;}#mermaid-svg-ytFse2qAQzmi4xaY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ytFse2qAQzmi4xaY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ytFse2qAQzmi4xaY rect.text{fill:none;stroke-width:0;}#mermaid-svg-ytFse2qAQzmi4xaY .icon-shape,#mermaid-svg-ytFse2qAQzmi4xaY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ytFse2qAQzmi4xaY .icon-shape p,#mermaid-svg-ytFse2qAQzmi4xaY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ytFse2qAQzmi4xaY .icon-shape .label rect,#mermaid-svg-ytFse2qAQzmi4xaY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ytFse2qAQzmi4xaY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ytFse2qAQzmi4xaY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ytFse2qAQzmi4xaY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
修改最小 owning component
输入契约变化?
同步 types/root/所有环境参数
Bicep Build
Staging + Production What-If
审查属性级变化
手工 Deployment Pipeline
修改应用发布时:
#mermaid-svg-xTAZtVpjA3GcPVAY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xTAZtVpjA3GcPVAY .error-icon{fill:#552222;}#mermaid-svg-xTAZtVpjA3GcPVAY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xTAZtVpjA3GcPVAY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xTAZtVpjA3GcPVAY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xTAZtVpjA3GcPVAY .marker.cross{stroke:#333333;}#mermaid-svg-xTAZtVpjA3GcPVAY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xTAZtVpjA3GcPVAY p{margin:0;}#mermaid-svg-xTAZtVpjA3GcPVAY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster-label text{fill:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster-label span{color:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster-label span p{background-color:transparent;}#mermaid-svg-xTAZtVpjA3GcPVAY .label text,#mermaid-svg-xTAZtVpjA3GcPVAY span{fill:#333;color:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY .node rect,#mermaid-svg-xTAZtVpjA3GcPVAY .node circle,#mermaid-svg-xTAZtVpjA3GcPVAY .node ellipse,#mermaid-svg-xTAZtVpjA3GcPVAY .node polygon,#mermaid-svg-xTAZtVpjA3GcPVAY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xTAZtVpjA3GcPVAY .rough-node .label text,#mermaid-svg-xTAZtVpjA3GcPVAY .node .label text,#mermaid-svg-xTAZtVpjA3GcPVAY .image-shape .label,#mermaid-svg-xTAZtVpjA3GcPVAY .icon-shape .label{text-anchor:middle;}#mermaid-svg-xTAZtVpjA3GcPVAY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xTAZtVpjA3GcPVAY .rough-node .label,#mermaid-svg-xTAZtVpjA3GcPVAY .node .label,#mermaid-svg-xTAZtVpjA3GcPVAY .image-shape .label,#mermaid-svg-xTAZtVpjA3GcPVAY .icon-shape .label{text-align:center;}#mermaid-svg-xTAZtVpjA3GcPVAY .node.clickable{cursor:pointer;}#mermaid-svg-xTAZtVpjA3GcPVAY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xTAZtVpjA3GcPVAY .arrowheadPath{fill:#333333;}#mermaid-svg-xTAZtVpjA3GcPVAY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xTAZtVpjA3GcPVAY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xTAZtVpjA3GcPVAY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xTAZtVpjA3GcPVAY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xTAZtVpjA3GcPVAY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xTAZtVpjA3GcPVAY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster text{fill:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY .cluster span{color:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xTAZtVpjA3GcPVAY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xTAZtVpjA3GcPVAY rect.text{fill:none;stroke-width:0;}#mermaid-svg-xTAZtVpjA3GcPVAY .icon-shape,#mermaid-svg-xTAZtVpjA3GcPVAY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xTAZtVpjA3GcPVAY .icon-shape p,#mermaid-svg-xTAZtVpjA3GcPVAY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xTAZtVpjA3GcPVAY .icon-shape .label rect,#mermaid-svg-xTAZtVpjA3GcPVAY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xTAZtVpjA3GcPVAY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xTAZtVpjA3GcPVAY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xTAZtVpjA3GcPVAY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 修改 ApiServiceNg
CI 测试
生成并签名 drop-ev2
Staging validateOnly
Staging rollout
观察健康告警
Production approval
Production rollout
不要直接修改编译生成的 EV2 ARM 内容而不理解它与 Service Root 的关系;不要拿普通 PR Artifact 直接发布生产;也不要跳过 What-If 去手工修改 Portal,因为下次 Bicep 部署可能把手工修改收敛回声明状态。
模型
#mermaid-svg-7p39vHIg1gzXWXzI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7p39vHIg1gzXWXzI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7p39vHIg1gzXWXzI .error-icon{fill:#552222;}#mermaid-svg-7p39vHIg1gzXWXzI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7p39vHIg1gzXWXzI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7p39vHIg1gzXWXzI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7p39vHIg1gzXWXzI .marker.cross{stroke:#333333;}#mermaid-svg-7p39vHIg1gzXWXzI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7p39vHIg1gzXWXzI p{margin:0;}#mermaid-svg-7p39vHIg1gzXWXzI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7p39vHIg1gzXWXzI .cluster-label text{fill:#333;}#mermaid-svg-7p39vHIg1gzXWXzI .cluster-label span{color:#333;}#mermaid-svg-7p39vHIg1gzXWXzI .cluster-label span p{background-color:transparent;}#mermaid-svg-7p39vHIg1gzXWXzI .label text,#mermaid-svg-7p39vHIg1gzXWXzI span{fill:#333;color:#333;}#mermaid-svg-7p39vHIg1gzXWXzI .node rect,#mermaid-svg-7p39vHIg1gzXWXzI .node circle,#mermaid-svg-7p39vHIg1gzXWXzI .node ellipse,#mermaid-svg-7p39vHIg1gzXWXzI .node polygon,#mermaid-svg-7p39vHIg1gzXWXzI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7p39vHIg1gzXWXzI .rough-node .label text,#mermaid-svg-7p39vHIg1gzXWXzI .node .label text,#mermaid-svg-7p39vHIg1gzXWXzI .image-shape .label,#mermaid-svg-7p39vHIg1gzXWXzI .icon-shape .label{text-anchor:middle;}#mermaid-svg-7p39vHIg1gzXWXzI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7p39vHIg1gzXWXzI .rough-node .label,#mermaid-svg-7p39vHIg1gzXWXzI .node .label,#mermaid-svg-7p39vHIg1gzXWXzI .image-shape .label,#mermaid-svg-7p39vHIg1gzXWXzI .icon-shape .label{text-align:center;}#mermaid-svg-7p39vHIg1gzXWXzI .node.clickable{cursor:pointer;}#mermaid-svg-7p39vHIg1gzXWXzI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7p39vHIg1gzXWXzI .arrowheadPath{fill:#333333;}#mermaid-svg-7p39vHIg1gzXWXzI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7p39vHIg1gzXWXzI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7p39vHIg1gzXWXzI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7p39vHIg1gzXWXzI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7p39vHIg1gzXWXzI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7p39vHIg1gzXWXzI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7p39vHIg1gzXWXzI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7p39vHIg1gzXWXzI .cluster text{fill:#333;}#mermaid-svg-7p39vHIg1gzXWXzI .cluster span{color:#333;}#mermaid-svg-7p39vHIg1gzXWXzI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7p39vHIg1gzXWXzI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7p39vHIg1gzXWXzI rect.text{fill:none;stroke-width:0;}#mermaid-svg-7p39vHIg1gzXWXzI .icon-shape,#mermaid-svg-7p39vHIg1gzXWXzI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7p39vHIg1gzXWXzI .icon-shape p,#mermaid-svg-7p39vHIg1gzXWXzI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7p39vHIg1gzXWXzI .icon-shape .label rect,#mermaid-svg-7p39vHIg1gzXWXzI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7p39vHIg1gzXWXzI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7p39vHIg1gzXWXzI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7p39vHIg1gzXWXzI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} devops
Bicep
建舞台
CI
检查并包装演员
EV2
安排演员登台
Azure Monitor
确认演出正常
稳定基础设施
可追溯发布包
受控环境发布
发布后质量门禁
可以把它记成:
Bicep 建好房子,CI 检查并打包应用,EV2 把新版本搬进去,Azure Monitor 判断搬完后房子是否仍然健康。
这套设计牺牲了一些文件数量和流程复杂度,换来的是:基础设施与代码版本分离、Staging 与 Production 隔离、默认只预览不部署、生产必须审批、发布包可追溯、健康验证可自动执行。对于跨订阅、受监管、需要 Service Tree 和 EV2 的企业级 Azure 服务,这种复杂度是有目的的。