AKS--Azure Managed Kubernetes

AKS

AKS 是 Azure 托管的 Kubernetes。

Agent 用它运行 RunnerManager、临时 Runner、LLM Gateway 和运维 Dashboard,并让这些容器能够自动部署、隔离、扩缩容和自我恢复
#mermaid-svg-0SsrbCGFNhfHas4O{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-0SsrbCGFNhfHas4O .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0SsrbCGFNhfHas4O .error-icon{fill:#552222;}#mermaid-svg-0SsrbCGFNhfHas4O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0SsrbCGFNhfHas4O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0SsrbCGFNhfHas4O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0SsrbCGFNhfHas4O .marker.cross{stroke:#333333;}#mermaid-svg-0SsrbCGFNhfHas4O svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0SsrbCGFNhfHas4O p{margin:0;}#mermaid-svg-0SsrbCGFNhfHas4O .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0SsrbCGFNhfHas4O .cluster-label text{fill:#333;}#mermaid-svg-0SsrbCGFNhfHas4O .cluster-label span{color:#333;}#mermaid-svg-0SsrbCGFNhfHas4O .cluster-label span p{background-color:transparent;}#mermaid-svg-0SsrbCGFNhfHas4O .label text,#mermaid-svg-0SsrbCGFNhfHas4O span{fill:#333;color:#333;}#mermaid-svg-0SsrbCGFNhfHas4O .node rect,#mermaid-svg-0SsrbCGFNhfHas4O .node circle,#mermaid-svg-0SsrbCGFNhfHas4O .node ellipse,#mermaid-svg-0SsrbCGFNhfHas4O .node polygon,#mermaid-svg-0SsrbCGFNhfHas4O .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0SsrbCGFNhfHas4O .rough-node .label text,#mermaid-svg-0SsrbCGFNhfHas4O .node .label text,#mermaid-svg-0SsrbCGFNhfHas4O .image-shape .label,#mermaid-svg-0SsrbCGFNhfHas4O .icon-shape .label{text-anchor:middle;}#mermaid-svg-0SsrbCGFNhfHas4O .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0SsrbCGFNhfHas4O .rough-node .label,#mermaid-svg-0SsrbCGFNhfHas4O .node .label,#mermaid-svg-0SsrbCGFNhfHas4O .image-shape .label,#mermaid-svg-0SsrbCGFNhfHas4O .icon-shape .label{text-align:center;}#mermaid-svg-0SsrbCGFNhfHas4O .node.clickable{cursor:pointer;}#mermaid-svg-0SsrbCGFNhfHas4O .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0SsrbCGFNhfHas4O .arrowheadPath{fill:#333333;}#mermaid-svg-0SsrbCGFNhfHas4O .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0SsrbCGFNhfHas4O .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0SsrbCGFNhfHas4O .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0SsrbCGFNhfHas4O .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0SsrbCGFNhfHas4O .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0SsrbCGFNhfHas4O .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0SsrbCGFNhfHas4O .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0SsrbCGFNhfHas4O .cluster text{fill:#333;}#mermaid-svg-0SsrbCGFNhfHas4O .cluster span{color:#333;}#mermaid-svg-0SsrbCGFNhfHas4O 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-0SsrbCGFNhfHas4O .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0SsrbCGFNhfHas4O rect.text{fill:none;stroke-width:0;}#mermaid-svg-0SsrbCGFNhfHas4O .icon-shape,#mermaid-svg-0SsrbCGFNhfHas4O .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0SsrbCGFNhfHas4O .icon-shape p,#mermaid-svg-0SsrbCGFNhfHas4O .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0SsrbCGFNhfHas4O .icon-shape .label rect,#mermaid-svg-0SsrbCGFNhfHas4O .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0SsrbCGFNhfHas4O .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0SsrbCGFNhfHas4O .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0SsrbCGFNhfHas4O :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提交任务
ApiServiceNg
Azure Service Bus
RunnerManager
AKS / Kubernetes API
临时 Runner Pod
临时 Runner Pod
LLM Gateway
Copilot / Azure AI 模型

一、AKS 是什么

Kubernetes 可以理解为一个"容器操作系统"。普通操作系统管理进程,Kubernetes 管理运行在多台服务器上的容器;AKS 则是 Azure 帮你托管 Kubernetes 控制面的产品。
#mermaid-svg-WLoDGdjHacY7vlCh{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-WLoDGdjHacY7vlCh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WLoDGdjHacY7vlCh .error-icon{fill:#552222;}#mermaid-svg-WLoDGdjHacY7vlCh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WLoDGdjHacY7vlCh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WLoDGdjHacY7vlCh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WLoDGdjHacY7vlCh .marker.cross{stroke:#333333;}#mermaid-svg-WLoDGdjHacY7vlCh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WLoDGdjHacY7vlCh p{margin:0;}#mermaid-svg-WLoDGdjHacY7vlCh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WLoDGdjHacY7vlCh .cluster-label text{fill:#333;}#mermaid-svg-WLoDGdjHacY7vlCh .cluster-label span{color:#333;}#mermaid-svg-WLoDGdjHacY7vlCh .cluster-label span p{background-color:transparent;}#mermaid-svg-WLoDGdjHacY7vlCh .label text,#mermaid-svg-WLoDGdjHacY7vlCh span{fill:#333;color:#333;}#mermaid-svg-WLoDGdjHacY7vlCh .node rect,#mermaid-svg-WLoDGdjHacY7vlCh .node circle,#mermaid-svg-WLoDGdjHacY7vlCh .node ellipse,#mermaid-svg-WLoDGdjHacY7vlCh .node polygon,#mermaid-svg-WLoDGdjHacY7vlCh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WLoDGdjHacY7vlCh .rough-node .label text,#mermaid-svg-WLoDGdjHacY7vlCh .node .label text,#mermaid-svg-WLoDGdjHacY7vlCh .image-shape .label,#mermaid-svg-WLoDGdjHacY7vlCh .icon-shape .label{text-anchor:middle;}#mermaid-svg-WLoDGdjHacY7vlCh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WLoDGdjHacY7vlCh .rough-node .label,#mermaid-svg-WLoDGdjHacY7vlCh .node .label,#mermaid-svg-WLoDGdjHacY7vlCh .image-shape .label,#mermaid-svg-WLoDGdjHacY7vlCh .icon-shape .label{text-align:center;}#mermaid-svg-WLoDGdjHacY7vlCh .node.clickable{cursor:pointer;}#mermaid-svg-WLoDGdjHacY7vlCh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WLoDGdjHacY7vlCh .arrowheadPath{fill:#333333;}#mermaid-svg-WLoDGdjHacY7vlCh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WLoDGdjHacY7vlCh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WLoDGdjHacY7vlCh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WLoDGdjHacY7vlCh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WLoDGdjHacY7vlCh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WLoDGdjHacY7vlCh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WLoDGdjHacY7vlCh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WLoDGdjHacY7vlCh .cluster text{fill:#333;}#mermaid-svg-WLoDGdjHacY7vlCh .cluster span{color:#333;}#mermaid-svg-WLoDGdjHacY7vlCh 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-WLoDGdjHacY7vlCh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WLoDGdjHacY7vlCh rect.text{fill:none;stroke-width:0;}#mermaid-svg-WLoDGdjHacY7vlCh .icon-shape,#mermaid-svg-WLoDGdjHacY7vlCh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WLoDGdjHacY7vlCh .icon-shape p,#mermaid-svg-WLoDGdjHacY7vlCh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WLoDGdjHacY7vlCh .icon-shape .label rect,#mermaid-svg-WLoDGdjHacY7vlCh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WLoDGdjHacY7vlCh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WLoDGdjHacY7vlCh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WLoDGdjHacY7vlCh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Azure Kubernetes Service
工作节点
Linux Node

Pod Pod Pod
控制面

API Server / Scheduler

由 Azure 托管
Windows Node

Runner Pod
Windows Node

Runner Pod

AKS 不等于某一台服务器,也不等于 Docker。三者关系是:

概念 通俗理解 负责什么
Docker/Image 标准集装箱 打包程序和依赖
Kubernetes 港口调度系统 安排集装箱运行、迁移和扩容
AKS Azure 经营的 Kubernetes 港口 托管控制面,并和 Azure 网络、身份、磁盘结合
Pod 一次具体运行 Kubernetes 最小调度单位
Node 承载 Pod 的机器 真正提供 CPU、内存和操作系统

仓库中的 AKS 目录不是 AKS 集群本身,而是描述部分集群资源的 YAML 和安装脚本。运行 kubectl apply 后,这些"期望状态"才会提交给真实集群。
#mermaid-svg-FqULcFO9XDrz07zy{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-FqULcFO9XDrz07zy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FqULcFO9XDrz07zy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FqULcFO9XDrz07zy .error-icon{fill:#552222;}#mermaid-svg-FqULcFO9XDrz07zy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FqULcFO9XDrz07zy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FqULcFO9XDrz07zy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FqULcFO9XDrz07zy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FqULcFO9XDrz07zy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FqULcFO9XDrz07zy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FqULcFO9XDrz07zy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FqULcFO9XDrz07zy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FqULcFO9XDrz07zy .marker.cross{stroke:#333333;}#mermaid-svg-FqULcFO9XDrz07zy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FqULcFO9XDrz07zy p{margin:0;}#mermaid-svg-FqULcFO9XDrz07zy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FqULcFO9XDrz07zy .cluster-label text{fill:#333;}#mermaid-svg-FqULcFO9XDrz07zy .cluster-label span{color:#333;}#mermaid-svg-FqULcFO9XDrz07zy .cluster-label span p{background-color:transparent;}#mermaid-svg-FqULcFO9XDrz07zy .label text,#mermaid-svg-FqULcFO9XDrz07zy span{fill:#333;color:#333;}#mermaid-svg-FqULcFO9XDrz07zy .node rect,#mermaid-svg-FqULcFO9XDrz07zy .node circle,#mermaid-svg-FqULcFO9XDrz07zy .node ellipse,#mermaid-svg-FqULcFO9XDrz07zy .node polygon,#mermaid-svg-FqULcFO9XDrz07zy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FqULcFO9XDrz07zy .rough-node .label text,#mermaid-svg-FqULcFO9XDrz07zy .node .label text,#mermaid-svg-FqULcFO9XDrz07zy .image-shape .label,#mermaid-svg-FqULcFO9XDrz07zy .icon-shape .label{text-anchor:middle;}#mermaid-svg-FqULcFO9XDrz07zy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FqULcFO9XDrz07zy .rough-node .label,#mermaid-svg-FqULcFO9XDrz07zy .node .label,#mermaid-svg-FqULcFO9XDrz07zy .image-shape .label,#mermaid-svg-FqULcFO9XDrz07zy .icon-shape .label{text-align:center;}#mermaid-svg-FqULcFO9XDrz07zy .node.clickable{cursor:pointer;}#mermaid-svg-FqULcFO9XDrz07zy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FqULcFO9XDrz07zy .arrowheadPath{fill:#333333;}#mermaid-svg-FqULcFO9XDrz07zy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FqULcFO9XDrz07zy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FqULcFO9XDrz07zy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FqULcFO9XDrz07zy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FqULcFO9XDrz07zy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FqULcFO9XDrz07zy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FqULcFO9XDrz07zy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FqULcFO9XDrz07zy .cluster text{fill:#333;}#mermaid-svg-FqULcFO9XDrz07zy .cluster span{color:#333;}#mermaid-svg-FqULcFO9XDrz07zy 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-FqULcFO9XDrz07zy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FqULcFO9XDrz07zy rect.text{fill:none;stroke-width:0;}#mermaid-svg-FqULcFO9XDrz07zy .icon-shape,#mermaid-svg-FqULcFO9XDrz07zy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FqULcFO9XDrz07zy .icon-shape p,#mermaid-svg-FqULcFO9XDrz07zy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FqULcFO9XDrz07zy .icon-shape .label rect,#mermaid-svg-FqULcFO9XDrz07zy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FqULcFO9XDrz07zy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FqULcFO9XDrz07zy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FqULcFO9XDrz07zy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} kubectl apply
异常或 Pod 消失
重新创建
Git 中的 YAML

期望状态
Kubernetes API
控制器持续对账
真实状态

Pod / Service / Disk

这种设计叫 声明式管理:告诉 Kubernetes"我要三个 RunnerManager",而不是手工执行"启动进程 1、2、3"。如果一个 Pod 崩溃,控制器会自动补一个。

二、de 为什么需要 AKS

de 的主要计算任务不是固定、均匀的 Web 请求,而是持续时间长、资源需求大、并发数量变化明显的编码任务。
每个任务可能需要独立代码目录、Git 凭据、模型配置和几十 GiB 内存。
#mermaid-svg-gXBxs1UAflJQpjPQ{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-gXBxs1UAflJQpjPQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gXBxs1UAflJQpjPQ .error-icon{fill:#552222;}#mermaid-svg-gXBxs1UAflJQpjPQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gXBxs1UAflJQpjPQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gXBxs1UAflJQpjPQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gXBxs1UAflJQpjPQ .marker.cross{stroke:#333333;}#mermaid-svg-gXBxs1UAflJQpjPQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gXBxs1UAflJQpjPQ p{margin:0;}#mermaid-svg-gXBxs1UAflJQpjPQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster-label text{fill:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster-label span{color:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster-label span p{background-color:transparent;}#mermaid-svg-gXBxs1UAflJQpjPQ .label text,#mermaid-svg-gXBxs1UAflJQpjPQ span{fill:#333;color:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ .node rect,#mermaid-svg-gXBxs1UAflJQpjPQ .node circle,#mermaid-svg-gXBxs1UAflJQpjPQ .node ellipse,#mermaid-svg-gXBxs1UAflJQpjPQ .node polygon,#mermaid-svg-gXBxs1UAflJQpjPQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gXBxs1UAflJQpjPQ .rough-node .label text,#mermaid-svg-gXBxs1UAflJQpjPQ .node .label text,#mermaid-svg-gXBxs1UAflJQpjPQ .image-shape .label,#mermaid-svg-gXBxs1UAflJQpjPQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-gXBxs1UAflJQpjPQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gXBxs1UAflJQpjPQ .rough-node .label,#mermaid-svg-gXBxs1UAflJQpjPQ .node .label,#mermaid-svg-gXBxs1UAflJQpjPQ .image-shape .label,#mermaid-svg-gXBxs1UAflJQpjPQ .icon-shape .label{text-align:center;}#mermaid-svg-gXBxs1UAflJQpjPQ .node.clickable{cursor:pointer;}#mermaid-svg-gXBxs1UAflJQpjPQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gXBxs1UAflJQpjPQ .arrowheadPath{fill:#333333;}#mermaid-svg-gXBxs1UAflJQpjPQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gXBxs1UAflJQpjPQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gXBxs1UAflJQpjPQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gXBxs1UAflJQpjPQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gXBxs1UAflJQpjPQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gXBxs1UAflJQpjPQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster text{fill:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ .cluster span{color:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ 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-gXBxs1UAflJQpjPQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gXBxs1UAflJQpjPQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-gXBxs1UAflJQpjPQ .icon-shape,#mermaid-svg-gXBxs1UAflJQpjPQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gXBxs1UAflJQpjPQ .icon-shape p,#mermaid-svg-gXBxs1UAflJQpjPQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gXBxs1UAflJQpjPQ .icon-shape .label rect,#mermaid-svg-gXBxs1UAflJQpjPQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gXBxs1UAflJQpjPQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gXBxs1UAflJQpjPQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gXBxs1UAflJQpjPQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 任务 A
独立 Runner Pod

代码仓库 A
任务 B
独立 Runner Pod

代码仓库 B
任务 C
独立 Runner Pod

代码仓库 C
完成后删除
完成后删除
完成后删除

采用单台 VM 当然也能运行程序,但会带来进程相互干扰、依赖冲突、资源争抢、故障集中和清理困难。一个任务把磁盘写满或进程卡死,可能影响其他所有任务。

采用 Azure Functions 也不合适。Functions 更适合短时间、无状态、事件驱动的函数;de Runner 需要长时间执行、较大的 CPU/内存、持久工作目录、Git 和开发工具链,并可能运行 Windows 工作负载。

采用 AKS 后,每个任务可以拥有独立 Pod:

  • 任务之间有进程、文件系统和资源边界。
  • 可以给 Runner 设置 CPU 和内存请求及上限。
  • 任务到来时创建 Pod,结束后删除。
  • Linux 和 Windows 工作负载可以调度到不同节点池。
  • Pod 失败后由 RunnerManager 或 Kubernetes 检测并恢复。
  • 高峰期可以增加节点,低峰期可以回收节点

因此这里选择 AKS,不是因为"Kubernetes 更高级",而是因为工作负载本身具有**动态、隔离、资源密集、生命周期明确**的特点。

三、集群中的主要区域

当前设计使用 Namespace 把不同职责和环境隔开:
#mermaid-svg-ImD2Ako5OH4aqQ9L{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-ImD2Ako5OH4aqQ9L .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ImD2Ako5OH4aqQ9L .error-icon{fill:#552222;}#mermaid-svg-ImD2Ako5OH4aqQ9L .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ImD2Ako5OH4aqQ9L .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .marker.cross{stroke:#333333;}#mermaid-svg-ImD2Ako5OH4aqQ9L svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ImD2Ako5OH4aqQ9L p{margin:0;}#mermaid-svg-ImD2Ako5OH4aqQ9L .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster-label text{fill:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster-label span{color:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster-label span p{background-color:transparent;}#mermaid-svg-ImD2Ako5OH4aqQ9L .label text,#mermaid-svg-ImD2Ako5OH4aqQ9L span{fill:#333;color:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .node rect,#mermaid-svg-ImD2Ako5OH4aqQ9L .node circle,#mermaid-svg-ImD2Ako5OH4aqQ9L .node ellipse,#mermaid-svg-ImD2Ako5OH4aqQ9L .node polygon,#mermaid-svg-ImD2Ako5OH4aqQ9L .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .rough-node .label text,#mermaid-svg-ImD2Ako5OH4aqQ9L .node .label text,#mermaid-svg-ImD2Ako5OH4aqQ9L .image-shape .label,#mermaid-svg-ImD2Ako5OH4aqQ9L .icon-shape .label{text-anchor:middle;}#mermaid-svg-ImD2Ako5OH4aqQ9L .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .rough-node .label,#mermaid-svg-ImD2Ako5OH4aqQ9L .node .label,#mermaid-svg-ImD2Ako5OH4aqQ9L .image-shape .label,#mermaid-svg-ImD2Ako5OH4aqQ9L .icon-shape .label{text-align:center;}#mermaid-svg-ImD2Ako5OH4aqQ9L .node.clickable{cursor:pointer;}#mermaid-svg-ImD2Ako5OH4aqQ9L .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .arrowheadPath{fill:#333333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ImD2Ako5OH4aqQ9L .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ImD2Ako5OH4aqQ9L .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ImD2Ako5OH4aqQ9L .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster text{fill:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L .cluster span{color:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L 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-ImD2Ako5OH4aqQ9L .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ImD2Ako5OH4aqQ9L rect.text{fill:none;stroke-width:0;}#mermaid-svg-ImD2Ako5OH4aqQ9L .icon-shape,#mermaid-svg-ImD2Ako5OH4aqQ9L .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ImD2Ako5OH4aqQ9L .icon-shape p,#mermaid-svg-ImD2Ako5OH4aqQ9L .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ImD2Ako5OH4aqQ9L .icon-shape .label rect,#mermaid-svg-ImD2Ako5OH4aqQ9L .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ImD2Ako5OH4aqQ9L .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ImD2Ako5OH4aqQ9L .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ImD2Ako5OH4aqQ9L :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AKS Cluster
Infrastructure
infra / Kubed
runnerdashboard
Staging
runnermanager-staging
runner-staging
llm-proxy-staging
Production
runnermanager
runner
llm-proxy

生产和 Staging 使用不同 Namespace,而不是把所有资源放入 default。好处是名称、配置、Secret、RBAC 和资源查询都可以按环境分开。例如生产 RunnerManager 创建 Pod 时使用 runner,Staging 使用 runner-staging

为什么不为每个环境建立完全独立的 AKS 集群?独立集群的隔离更强,适合严格合规或高风险系统,但成本、节点利用率、升级和维护工作也会翻倍。Namespace 是一种成本较低的逻辑隔离。它不是完整安全边界,因此仍需要 RBAC、Pod Security 和网络策略共同保护。

Namespace 定义见 namespaces.yaml 和 namespaces-core.yaml。它们统一启用了 Restricted Pod Security:

text 复制代码
enforce = restricted
audit   = baseline
warn    = baseline

含义是:违反严格安全规则的 Pod 会被拒绝,同时对基线规则进行审计和警告。

四、RunnerManager 和临时 Runner

RunnerManager 是 AKS 中的任务调度业务服务。它自身以 Deployment 运行三个副本,并通过 Kubernetes API 动态管理 Runner Pod。
LLM Gateway Runner Pod Kubernetes API RunnerManager Service Bus ApiServiceNg LLM Gateway Runner Pod Kubernetes API RunnerManager Service Bus ApiServiceNg #mermaid-svg-KtmfqzB56wYEh3nK{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-KtmfqzB56wYEh3nK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KtmfqzB56wYEh3nK .error-icon{fill:#552222;}#mermaid-svg-KtmfqzB56wYEh3nK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KtmfqzB56wYEh3nK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KtmfqzB56wYEh3nK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KtmfqzB56wYEh3nK .marker.cross{stroke:#333333;}#mermaid-svg-KtmfqzB56wYEh3nK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KtmfqzB56wYEh3nK p{margin:0;}#mermaid-svg-KtmfqzB56wYEh3nK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KtmfqzB56wYEh3nK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-KtmfqzB56wYEh3nK .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-KtmfqzB56wYEh3nK .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-KtmfqzB56wYEh3nK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-KtmfqzB56wYEh3nK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-KtmfqzB56wYEh3nK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-KtmfqzB56wYEh3nK .sequenceNumber{fill:white;}#mermaid-svg-KtmfqzB56wYEh3nK #sequencenumber{fill:#333;}#mermaid-svg-KtmfqzB56wYEh3nK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-KtmfqzB56wYEh3nK .messageText{fill:#333;stroke:none;}#mermaid-svg-KtmfqzB56wYEh3nK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KtmfqzB56wYEh3nK .labelText,#mermaid-svg-KtmfqzB56wYEh3nK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-KtmfqzB56wYEh3nK .loopText,#mermaid-svg-KtmfqzB56wYEh3nK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-KtmfqzB56wYEh3nK .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-KtmfqzB56wYEh3nK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-KtmfqzB56wYEh3nK .noteText,#mermaid-svg-KtmfqzB56wYEh3nK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-KtmfqzB56wYEh3nK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KtmfqzB56wYEh3nK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KtmfqzB56wYEh3nK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KtmfqzB56wYEh3nK .actorPopupMenu{position:absolute;}#mermaid-svg-KtmfqzB56wYEh3nK .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-KtmfqzB56wYEh3nK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KtmfqzB56wYEh3nK .actor-man circle,#mermaid-svg-KtmfqzB56wYEh3nK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-KtmfqzB56wYEh3nK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 发布编码任务消费任务消息创建带资源与配置的 Pod调度到合适节点请求模型完成编码报告进度、请求审批发布任务状态任务结束后删除 Pod

RunnerManager 配置中,生产 Runner Pod 可以申请最多 16 CPU、36 GiB 内存,并限制单用户最多运行 6 个 Pod,见 config-runnermanager.yaml。

为什么 RunnerManager 自己不直接运行编码任务?因为调度控制和实际计算是两种不同职责:

  • RunnerManager 较轻,应该长期稳定运行。
  • Runner 很重,数量随任务变化,并可能运行不可信的仓库命令。
  • 二者拆开后,一个 Runner 崩溃不会带走调度服务。
  • Runner 镜像和模型配置可以独立升级。

RunnerManager 使用 ClusterIP Service,只供集群内部访问,没有公网 Ingress。这是正确的最小暴露设计:外部系统通过 Service Bus 交换消息,Runner Pod 通过集群 DNS 调用它,没有必要为管理 API开放公网入口。相关资源见 deployment.yaml 和 service.yaml。

五、Deployment、Service 和 Ingress 为什么分开

这三个概念经常混淆:
#mermaid-svg-FjgJIJeryR6p65pg{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-FjgJIJeryR6p65pg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FjgJIJeryR6p65pg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FjgJIJeryR6p65pg .error-icon{fill:#552222;}#mermaid-svg-FjgJIJeryR6p65pg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FjgJIJeryR6p65pg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FjgJIJeryR6p65pg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FjgJIJeryR6p65pg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FjgJIJeryR6p65pg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FjgJIJeryR6p65pg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FjgJIJeryR6p65pg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FjgJIJeryR6p65pg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FjgJIJeryR6p65pg .marker.cross{stroke:#333333;}#mermaid-svg-FjgJIJeryR6p65pg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FjgJIJeryR6p65pg p{margin:0;}#mermaid-svg-FjgJIJeryR6p65pg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FjgJIJeryR6p65pg .cluster-label text{fill:#333;}#mermaid-svg-FjgJIJeryR6p65pg .cluster-label span{color:#333;}#mermaid-svg-FjgJIJeryR6p65pg .cluster-label span p{background-color:transparent;}#mermaid-svg-FjgJIJeryR6p65pg .label text,#mermaid-svg-FjgJIJeryR6p65pg span{fill:#333;color:#333;}#mermaid-svg-FjgJIJeryR6p65pg .node rect,#mermaid-svg-FjgJIJeryR6p65pg .node circle,#mermaid-svg-FjgJIJeryR6p65pg .node ellipse,#mermaid-svg-FjgJIJeryR6p65pg .node polygon,#mermaid-svg-FjgJIJeryR6p65pg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FjgJIJeryR6p65pg .rough-node .label text,#mermaid-svg-FjgJIJeryR6p65pg .node .label text,#mermaid-svg-FjgJIJeryR6p65pg .image-shape .label,#mermaid-svg-FjgJIJeryR6p65pg .icon-shape .label{text-anchor:middle;}#mermaid-svg-FjgJIJeryR6p65pg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FjgJIJeryR6p65pg .rough-node .label,#mermaid-svg-FjgJIJeryR6p65pg .node .label,#mermaid-svg-FjgJIJeryR6p65pg .image-shape .label,#mermaid-svg-FjgJIJeryR6p65pg .icon-shape .label{text-align:center;}#mermaid-svg-FjgJIJeryR6p65pg .node.clickable{cursor:pointer;}#mermaid-svg-FjgJIJeryR6p65pg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FjgJIJeryR6p65pg .arrowheadPath{fill:#333333;}#mermaid-svg-FjgJIJeryR6p65pg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FjgJIJeryR6p65pg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FjgJIJeryR6p65pg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FjgJIJeryR6p65pg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FjgJIJeryR6p65pg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FjgJIJeryR6p65pg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FjgJIJeryR6p65pg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FjgJIJeryR6p65pg .cluster text{fill:#333;}#mermaid-svg-FjgJIJeryR6p65pg .cluster span{color:#333;}#mermaid-svg-FjgJIJeryR6p65pg 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-FjgJIJeryR6p65pg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FjgJIJeryR6p65pg rect.text{fill:none;stroke-width:0;}#mermaid-svg-FjgJIJeryR6p65pg .icon-shape,#mermaid-svg-FjgJIJeryR6p65pg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FjgJIJeryR6p65pg .icon-shape p,#mermaid-svg-FjgJIJeryR6p65pg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FjgJIJeryR6p65pg .icon-shape .label rect,#mermaid-svg-FjgJIJeryR6p65pg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FjgJIJeryR6p65pg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FjgJIJeryR6p65pg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FjgJIJeryR6p65pg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部请求
Ingress

域名和路径路由
Service

稳定虚拟地址
Pod A
Pod B
Pod C

  • Deployment 管 Pod 数量和升级。
  • Service 为不断更换 IP 的 Pod 提供稳定名称和负载均衡。
  • Ingress 把外部 HTTP 流量引入某个 Service。

Pod 是短暂的,重启后 IP 会变化,所以调用方不应该记住 Pod IP。它只访问 runnermanager.runnermanager.svc.cluster.local:3981 之类的 Service DNS。

Dashboard 和 Copilot2API 需要被指定入口访问,因此配置了 Azure Application Gateway Ingress;RunnerManager 不需要公网访问,所以只有 ClusterIP。这体现了"需要才暴露",而不是所有服务都配置公网 IP。

Dashboard 的完整外部链路是:
#mermaid-svg-SpgQ3R7xUbUa61S8{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-SpgQ3R7xUbUa61S8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SpgQ3R7xUbUa61S8 .error-icon{fill:#552222;}#mermaid-svg-SpgQ3R7xUbUa61S8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SpgQ3R7xUbUa61S8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .marker.cross{stroke:#333333;}#mermaid-svg-SpgQ3R7xUbUa61S8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SpgQ3R7xUbUa61S8 p{margin:0;}#mermaid-svg-SpgQ3R7xUbUa61S8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster-label text{fill:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster-label span{color:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster-label span p{background-color:transparent;}#mermaid-svg-SpgQ3R7xUbUa61S8 .label text,#mermaid-svg-SpgQ3R7xUbUa61S8 span{fill:#333;color:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .node rect,#mermaid-svg-SpgQ3R7xUbUa61S8 .node circle,#mermaid-svg-SpgQ3R7xUbUa61S8 .node ellipse,#mermaid-svg-SpgQ3R7xUbUa61S8 .node polygon,#mermaid-svg-SpgQ3R7xUbUa61S8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .rough-node .label text,#mermaid-svg-SpgQ3R7xUbUa61S8 .node .label text,#mermaid-svg-SpgQ3R7xUbUa61S8 .image-shape .label,#mermaid-svg-SpgQ3R7xUbUa61S8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-SpgQ3R7xUbUa61S8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .rough-node .label,#mermaid-svg-SpgQ3R7xUbUa61S8 .node .label,#mermaid-svg-SpgQ3R7xUbUa61S8 .image-shape .label,#mermaid-svg-SpgQ3R7xUbUa61S8 .icon-shape .label{text-align:center;}#mermaid-svg-SpgQ3R7xUbUa61S8 .node.clickable{cursor:pointer;}#mermaid-svg-SpgQ3R7xUbUa61S8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .arrowheadPath{fill:#333333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SpgQ3R7xUbUa61S8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SpgQ3R7xUbUa61S8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SpgQ3R7xUbUa61S8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster text{fill:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 .cluster span{color:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 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-SpgQ3R7xUbUa61S8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SpgQ3R7xUbUa61S8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-SpgQ3R7xUbUa61S8 .icon-shape,#mermaid-svg-SpgQ3R7xUbUa61S8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SpgQ3R7xUbUa61S8 .icon-shape p,#mermaid-svg-SpgQ3R7xUbUa61S8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SpgQ3R7xUbUa61S8 .icon-shape .label rect,#mermaid-svg-SpgQ3R7xUbUa61S8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SpgQ3R7xUbUa61S8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SpgQ3R7xUbUa61S8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SpgQ3R7xUbUa61S8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运维人员浏览器
Azure Front Door
Application Gateway
AKS Ingress
ClusterIP Service :80
Dashboard Pod :3085

Ingress 配置见 ingress.yaml。

六、LLM Gateway 为什么分层

LLM 路径包含 Copilot2API,以及仓库中保存的 LiteLLM 路由配置。二者看似都是代理,职责实际上不同:
#mermaid-svg-4qhO0Y45DgmwW5KL{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-4qhO0Y45DgmwW5KL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4qhO0Y45DgmwW5KL .error-icon{fill:#552222;}#mermaid-svg-4qhO0Y45DgmwW5KL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4qhO0Y45DgmwW5KL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4qhO0Y45DgmwW5KL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4qhO0Y45DgmwW5KL .marker.cross{stroke:#333333;}#mermaid-svg-4qhO0Y45DgmwW5KL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4qhO0Y45DgmwW5KL p{margin:0;}#mermaid-svg-4qhO0Y45DgmwW5KL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster-label text{fill:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster-label span{color:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster-label span p{background-color:transparent;}#mermaid-svg-4qhO0Y45DgmwW5KL .label text,#mermaid-svg-4qhO0Y45DgmwW5KL span{fill:#333;color:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL .node rect,#mermaid-svg-4qhO0Y45DgmwW5KL .node circle,#mermaid-svg-4qhO0Y45DgmwW5KL .node ellipse,#mermaid-svg-4qhO0Y45DgmwW5KL .node polygon,#mermaid-svg-4qhO0Y45DgmwW5KL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4qhO0Y45DgmwW5KL .rough-node .label text,#mermaid-svg-4qhO0Y45DgmwW5KL .node .label text,#mermaid-svg-4qhO0Y45DgmwW5KL .image-shape .label,#mermaid-svg-4qhO0Y45DgmwW5KL .icon-shape .label{text-anchor:middle;}#mermaid-svg-4qhO0Y45DgmwW5KL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4qhO0Y45DgmwW5KL .rough-node .label,#mermaid-svg-4qhO0Y45DgmwW5KL .node .label,#mermaid-svg-4qhO0Y45DgmwW5KL .image-shape .label,#mermaid-svg-4qhO0Y45DgmwW5KL .icon-shape .label{text-align:center;}#mermaid-svg-4qhO0Y45DgmwW5KL .node.clickable{cursor:pointer;}#mermaid-svg-4qhO0Y45DgmwW5KL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4qhO0Y45DgmwW5KL .arrowheadPath{fill:#333333;}#mermaid-svg-4qhO0Y45DgmwW5KL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4qhO0Y45DgmwW5KL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4qhO0Y45DgmwW5KL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4qhO0Y45DgmwW5KL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4qhO0Y45DgmwW5KL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4qhO0Y45DgmwW5KL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster text{fill:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL .cluster span{color:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL 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-4qhO0Y45DgmwW5KL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4qhO0Y45DgmwW5KL rect.text{fill:none;stroke-width:0;}#mermaid-svg-4qhO0Y45DgmwW5KL .icon-shape,#mermaid-svg-4qhO0Y45DgmwW5KL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4qhO0Y45DgmwW5KL .icon-shape p,#mermaid-svg-4qhO0Y45DgmwW5KL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4qhO0Y45DgmwW5KL .icon-shape .label rect,#mermaid-svg-4qhO0Y45DgmwW5KL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4qhO0Y45DgmwW5KL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4qhO0Y45DgmwW5KL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4qhO0Y45DgmwW5KL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Runner
LiteLLM / Gateway

统一模型名、重试、路由
Copilot 账号 1
Copilot 账号 2
Copilot 账号 3
Azure AI fallback

  • Copilot2API 负责把 GitHub Copilot 能力转换成 OpenAI、Anthropic 等兼容接口,并管理账号认证。

  • LiteLLM 配置负责把同一模型映射到多个账号,采用 simple-shuffle 分流,失败后重试三次,并配置 Opus 到 Sonnet 的降级,见 litellm-config.yaml。

为什么不让每个 Runner 自己选择账号和实现重试?

  • 账号池规则会散落到所有 Runner 镜像。
  • 更换账号需要重新构建或重启大量 Runner。
  • 重试、降级和统计逻辑容易不一致。
  • 密钥暴露范围更大。

集中 Gateway 后,Runner 只需要知道一个内部地址和逻辑模型名。路由政策可以独立调整。不过也会增加一跳网络延迟,并形成重要依赖,因此 Gateway 需要监控、重试和容量规划。

需要注意:当前 litellm 只保存 LiteLLM 配置,没有它的 Deployment 或安装脚本;部分 Runner 配置还会直接访问 Copilot2API 的 /gw/api。所以这个目录表达的是路由配置和目标架构,不能单凭这些文件认定所有请求一定先经过独立 LiteLLM Pod。

七、为什么 Copilot2API 只有一个副本

Copilot2API 把账号 Token 和数据库保存在 Azure Disk PVC 中。PVC 使用 ReadWriteOnce,表示同一时刻只能挂载到一个节点。
#mermaid-svg-nfGFM7im8Z6OQLwF{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-nfGFM7im8Z6OQLwF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nfGFM7im8Z6OQLwF .error-icon{fill:#552222;}#mermaid-svg-nfGFM7im8Z6OQLwF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nfGFM7im8Z6OQLwF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nfGFM7im8Z6OQLwF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nfGFM7im8Z6OQLwF .marker.cross{stroke:#333333;}#mermaid-svg-nfGFM7im8Z6OQLwF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nfGFM7im8Z6OQLwF p{margin:0;}#mermaid-svg-nfGFM7im8Z6OQLwF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster-label text{fill:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster-label span{color:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster-label span p{background-color:transparent;}#mermaid-svg-nfGFM7im8Z6OQLwF .label text,#mermaid-svg-nfGFM7im8Z6OQLwF span{fill:#333;color:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF .node rect,#mermaid-svg-nfGFM7im8Z6OQLwF .node circle,#mermaid-svg-nfGFM7im8Z6OQLwF .node ellipse,#mermaid-svg-nfGFM7im8Z6OQLwF .node polygon,#mermaid-svg-nfGFM7im8Z6OQLwF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nfGFM7im8Z6OQLwF .rough-node .label text,#mermaid-svg-nfGFM7im8Z6OQLwF .node .label text,#mermaid-svg-nfGFM7im8Z6OQLwF .image-shape .label,#mermaid-svg-nfGFM7im8Z6OQLwF .icon-shape .label{text-anchor:middle;}#mermaid-svg-nfGFM7im8Z6OQLwF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nfGFM7im8Z6OQLwF .rough-node .label,#mermaid-svg-nfGFM7im8Z6OQLwF .node .label,#mermaid-svg-nfGFM7im8Z6OQLwF .image-shape .label,#mermaid-svg-nfGFM7im8Z6OQLwF .icon-shape .label{text-align:center;}#mermaid-svg-nfGFM7im8Z6OQLwF .node.clickable{cursor:pointer;}#mermaid-svg-nfGFM7im8Z6OQLwF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nfGFM7im8Z6OQLwF .arrowheadPath{fill:#333333;}#mermaid-svg-nfGFM7im8Z6OQLwF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nfGFM7im8Z6OQLwF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nfGFM7im8Z6OQLwF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nfGFM7im8Z6OQLwF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nfGFM7im8Z6OQLwF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nfGFM7im8Z6OQLwF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster text{fill:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF .cluster span{color:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF 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-nfGFM7im8Z6OQLwF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nfGFM7im8Z6OQLwF rect.text{fill:none;stroke-width:0;}#mermaid-svg-nfGFM7im8Z6OQLwF .icon-shape,#mermaid-svg-nfGFM7im8Z6OQLwF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nfGFM7im8Z6OQLwF .icon-shape p,#mermaid-svg-nfGFM7im8Z6OQLwF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nfGFM7im8Z6OQLwF .icon-shape .label rect,#mermaid-svg-nfGFM7im8Z6OQLwF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nfGFM7im8Z6OQLwF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nfGFM7im8Z6OQLwF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nfGFM7im8Z6OQLwF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Copilot2API Pod
PVC 8 GiB

ReadWriteOnce
Azure Premium SSD

Retain
Pod 重建

如果使用默认 RollingUpdate,新 Pod 会先启动,但磁盘仍挂在旧 Pod 所在节点,新 Pod就可能一直等待挂载。当前采用 Recreate
#mermaid-svg-kAQlC7TTIfGLKFmK{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-kAQlC7TTIfGLKFmK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kAQlC7TTIfGLKFmK .error-icon{fill:#552222;}#mermaid-svg-kAQlC7TTIfGLKFmK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kAQlC7TTIfGLKFmK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kAQlC7TTIfGLKFmK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kAQlC7TTIfGLKFmK .marker.cross{stroke:#333333;}#mermaid-svg-kAQlC7TTIfGLKFmK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kAQlC7TTIfGLKFmK p{margin:0;}#mermaid-svg-kAQlC7TTIfGLKFmK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster-label text{fill:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster-label span{color:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster-label span p{background-color:transparent;}#mermaid-svg-kAQlC7TTIfGLKFmK .label text,#mermaid-svg-kAQlC7TTIfGLKFmK span{fill:#333;color:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK .node rect,#mermaid-svg-kAQlC7TTIfGLKFmK .node circle,#mermaid-svg-kAQlC7TTIfGLKFmK .node ellipse,#mermaid-svg-kAQlC7TTIfGLKFmK .node polygon,#mermaid-svg-kAQlC7TTIfGLKFmK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kAQlC7TTIfGLKFmK .rough-node .label text,#mermaid-svg-kAQlC7TTIfGLKFmK .node .label text,#mermaid-svg-kAQlC7TTIfGLKFmK .image-shape .label,#mermaid-svg-kAQlC7TTIfGLKFmK .icon-shape .label{text-anchor:middle;}#mermaid-svg-kAQlC7TTIfGLKFmK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kAQlC7TTIfGLKFmK .rough-node .label,#mermaid-svg-kAQlC7TTIfGLKFmK .node .label,#mermaid-svg-kAQlC7TTIfGLKFmK .image-shape .label,#mermaid-svg-kAQlC7TTIfGLKFmK .icon-shape .label{text-align:center;}#mermaid-svg-kAQlC7TTIfGLKFmK .node.clickable{cursor:pointer;}#mermaid-svg-kAQlC7TTIfGLKFmK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kAQlC7TTIfGLKFmK .arrowheadPath{fill:#333333;}#mermaid-svg-kAQlC7TTIfGLKFmK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kAQlC7TTIfGLKFmK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kAQlC7TTIfGLKFmK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kAQlC7TTIfGLKFmK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kAQlC7TTIfGLKFmK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kAQlC7TTIfGLKFmK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster text{fill:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK .cluster span{color:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK 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-kAQlC7TTIfGLKFmK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kAQlC7TTIfGLKFmK rect.text{fill:none;stroke-width:0;}#mermaid-svg-kAQlC7TTIfGLKFmK .icon-shape,#mermaid-svg-kAQlC7TTIfGLKFmK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kAQlC7TTIfGLKFmK .icon-shape p,#mermaid-svg-kAQlC7TTIfGLKFmK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kAQlC7TTIfGLKFmK .icon-shape .label rect,#mermaid-svg-kAQlC7TTIfGLKFmK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kAQlC7TTIfGLKFmK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kAQlC7TTIfGLKFmK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kAQlC7TTIfGLKFmK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 停止旧 Pod
释放 Azure Disk
启动新 Pod
挂载原有账号数据

这牺牲了升级期间的短暂停机,换取简单可靠的磁盘挂载。另一种方案是把状态迁移到外部数据库或支持多写的存储,然后运行多个无状态副本;可用性更高,但实现和运维复杂度也更高。

StorageClass 使用 Premium SSD、Retain 回收策略和 WaitForFirstConsumer,见 storageclass.yaml:

  • Premium_LRS:降低状态读写延迟。
  • Retain:删除 PVC 后不自动删除底层数据,降低误删账号数据的风险。
  • WaitForFirstConsumer:等 Pod 确定节点后再分配磁盘,避免磁盘区域和节点不匹配。
  • allowVolumeExpansion:未来可以扩容。

八、扩缩容和自我恢复

RunnerManager Deployment 固定从三个副本起步,HPA 可扩展到五个副本:
#mermaid-svg-CjCHANrw2bRhYdZh{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-CjCHANrw2bRhYdZh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CjCHANrw2bRhYdZh .error-icon{fill:#552222;}#mermaid-svg-CjCHANrw2bRhYdZh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CjCHANrw2bRhYdZh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CjCHANrw2bRhYdZh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CjCHANrw2bRhYdZh .marker.cross{stroke:#333333;}#mermaid-svg-CjCHANrw2bRhYdZh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CjCHANrw2bRhYdZh p{margin:0;}#mermaid-svg-CjCHANrw2bRhYdZh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CjCHANrw2bRhYdZh .cluster-label text{fill:#333;}#mermaid-svg-CjCHANrw2bRhYdZh .cluster-label span{color:#333;}#mermaid-svg-CjCHANrw2bRhYdZh .cluster-label span p{background-color:transparent;}#mermaid-svg-CjCHANrw2bRhYdZh .label text,#mermaid-svg-CjCHANrw2bRhYdZh span{fill:#333;color:#333;}#mermaid-svg-CjCHANrw2bRhYdZh .node rect,#mermaid-svg-CjCHANrw2bRhYdZh .node circle,#mermaid-svg-CjCHANrw2bRhYdZh .node ellipse,#mermaid-svg-CjCHANrw2bRhYdZh .node polygon,#mermaid-svg-CjCHANrw2bRhYdZh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CjCHANrw2bRhYdZh .rough-node .label text,#mermaid-svg-CjCHANrw2bRhYdZh .node .label text,#mermaid-svg-CjCHANrw2bRhYdZh .image-shape .label,#mermaid-svg-CjCHANrw2bRhYdZh .icon-shape .label{text-anchor:middle;}#mermaid-svg-CjCHANrw2bRhYdZh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CjCHANrw2bRhYdZh .rough-node .label,#mermaid-svg-CjCHANrw2bRhYdZh .node .label,#mermaid-svg-CjCHANrw2bRhYdZh .image-shape .label,#mermaid-svg-CjCHANrw2bRhYdZh .icon-shape .label{text-align:center;}#mermaid-svg-CjCHANrw2bRhYdZh .node.clickable{cursor:pointer;}#mermaid-svg-CjCHANrw2bRhYdZh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CjCHANrw2bRhYdZh .arrowheadPath{fill:#333333;}#mermaid-svg-CjCHANrw2bRhYdZh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CjCHANrw2bRhYdZh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CjCHANrw2bRhYdZh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CjCHANrw2bRhYdZh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CjCHANrw2bRhYdZh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CjCHANrw2bRhYdZh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CjCHANrw2bRhYdZh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CjCHANrw2bRhYdZh .cluster text{fill:#333;}#mermaid-svg-CjCHANrw2bRhYdZh .cluster span{color:#333;}#mermaid-svg-CjCHANrw2bRhYdZh 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-CjCHANrw2bRhYdZh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CjCHANrw2bRhYdZh rect.text{fill:none;stroke-width:0;}#mermaid-svg-CjCHANrw2bRhYdZh .icon-shape,#mermaid-svg-CjCHANrw2bRhYdZh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CjCHANrw2bRhYdZh .icon-shape p,#mermaid-svg-CjCHANrw2bRhYdZh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CjCHANrw2bRhYdZh .icon-shape .label rect,#mermaid-svg-CjCHANrw2bRhYdZh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CjCHANrw2bRhYdZh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CjCHANrw2bRhYdZh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CjCHANrw2bRhYdZh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CPU > 70%
内存 > 80%
持续下降
CPU / 内存指标
超过阈值?
增加副本
等待 300 秒稳定窗口
缓慢缩容

配置见 hpa.yaml。扩容快、缩容慢,是为了避免短暂波动导致副本数量来回震荡。三个最小副本则保证一个 Pod 重启或节点维护时服务仍有余量。

每个长期服务还配置了探针:

  • startupProbe:应用是否完成启动。
  • readinessProbe:是否可以接收流量。
  • livenessProbe:是否已经卡死,需要重启。

这比单纯判断"进程还在不在"更可靠。进程可能存活,但数据库、事件循环或内部服务已经无法工作。

资源 requests 告诉调度器至少预留多少资源;limits 防止单个容器无限消耗节点。没有 requests,调度器很难正确放置 Pod;没有 limits,一个异常容器可能拖累整个节点。

九、身份、Secret 与最小权限

de 没有给所有 Pod 一个万能管理员身份,而是采用 ServiceAccount、RBAC 和 Azure Workload Identity:
#mermaid-svg-KnYrfgTQ2xjSlqQO{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-KnYrfgTQ2xjSlqQO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KnYrfgTQ2xjSlqQO .error-icon{fill:#552222;}#mermaid-svg-KnYrfgTQ2xjSlqQO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KnYrfgTQ2xjSlqQO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .marker.cross{stroke:#333333;}#mermaid-svg-KnYrfgTQ2xjSlqQO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KnYrfgTQ2xjSlqQO p{margin:0;}#mermaid-svg-KnYrfgTQ2xjSlqQO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster-label text{fill:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster-label span{color:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster-label span p{background-color:transparent;}#mermaid-svg-KnYrfgTQ2xjSlqQO .label text,#mermaid-svg-KnYrfgTQ2xjSlqQO span{fill:#333;color:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .node rect,#mermaid-svg-KnYrfgTQ2xjSlqQO .node circle,#mermaid-svg-KnYrfgTQ2xjSlqQO .node ellipse,#mermaid-svg-KnYrfgTQ2xjSlqQO .node polygon,#mermaid-svg-KnYrfgTQ2xjSlqQO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .rough-node .label text,#mermaid-svg-KnYrfgTQ2xjSlqQO .node .label text,#mermaid-svg-KnYrfgTQ2xjSlqQO .image-shape .label,#mermaid-svg-KnYrfgTQ2xjSlqQO .icon-shape .label{text-anchor:middle;}#mermaid-svg-KnYrfgTQ2xjSlqQO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .rough-node .label,#mermaid-svg-KnYrfgTQ2xjSlqQO .node .label,#mermaid-svg-KnYrfgTQ2xjSlqQO .image-shape .label,#mermaid-svg-KnYrfgTQ2xjSlqQO .icon-shape .label{text-align:center;}#mermaid-svg-KnYrfgTQ2xjSlqQO .node.clickable{cursor:pointer;}#mermaid-svg-KnYrfgTQ2xjSlqQO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .arrowheadPath{fill:#333333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KnYrfgTQ2xjSlqQO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KnYrfgTQ2xjSlqQO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KnYrfgTQ2xjSlqQO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster text{fill:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO .cluster span{color:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO 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-KnYrfgTQ2xjSlqQO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KnYrfgTQ2xjSlqQO rect.text{fill:none;stroke-width:0;}#mermaid-svg-KnYrfgTQ2xjSlqQO .icon-shape,#mermaid-svg-KnYrfgTQ2xjSlqQO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KnYrfgTQ2xjSlqQO .icon-shape p,#mermaid-svg-KnYrfgTQ2xjSlqQO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KnYrfgTQ2xjSlqQO .icon-shape .label rect,#mermaid-svg-KnYrfgTQ2xjSlqQO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KnYrfgTQ2xjSlqQO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KnYrfgTQ2xjSlqQO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KnYrfgTQ2xjSlqQO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pod
Kubernetes ServiceAccount
Federated Identity
Azure Managed Identity
Key Vault / Azure AI / 其他 Azure 服务

Workload Identity 避免把长期 Client Secret 写进镜像或 YAML。Pod 获得短期 Token,身份权限也可以独立控制。

RunnerManager 容器还设置了:

  • 非 root 用户 10001
  • 禁止提权和 privileged。
  • 删除全部 Linux capabilities。
  • 只读根文件系统。
  • RuntimeDefault seccomp。
  • 临时写入只能进入 tmp 的 emptyDir

这比"容器本来就隔离,所以直接 root 运行"更安全。容器不是虚拟机级安全边界;一旦应用存在漏洞,最小权限能减少进一步攻击节点的机会。

Dashboard 的 RBAC 也很有代表性:
#mermaid-svg-FGQKfz5hMlTIkpZt{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-FGQKfz5hMlTIkpZt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FGQKfz5hMlTIkpZt .error-icon{fill:#552222;}#mermaid-svg-FGQKfz5hMlTIkpZt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FGQKfz5hMlTIkpZt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FGQKfz5hMlTIkpZt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FGQKfz5hMlTIkpZt .marker.cross{stroke:#333333;}#mermaid-svg-FGQKfz5hMlTIkpZt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FGQKfz5hMlTIkpZt p{margin:0;}#mermaid-svg-FGQKfz5hMlTIkpZt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster-label text{fill:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster-label span{color:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster-label span p{background-color:transparent;}#mermaid-svg-FGQKfz5hMlTIkpZt .label text,#mermaid-svg-FGQKfz5hMlTIkpZt span{fill:#333;color:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt .node rect,#mermaid-svg-FGQKfz5hMlTIkpZt .node circle,#mermaid-svg-FGQKfz5hMlTIkpZt .node ellipse,#mermaid-svg-FGQKfz5hMlTIkpZt .node polygon,#mermaid-svg-FGQKfz5hMlTIkpZt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FGQKfz5hMlTIkpZt .rough-node .label text,#mermaid-svg-FGQKfz5hMlTIkpZt .node .label text,#mermaid-svg-FGQKfz5hMlTIkpZt .image-shape .label,#mermaid-svg-FGQKfz5hMlTIkpZt .icon-shape .label{text-anchor:middle;}#mermaid-svg-FGQKfz5hMlTIkpZt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FGQKfz5hMlTIkpZt .rough-node .label,#mermaid-svg-FGQKfz5hMlTIkpZt .node .label,#mermaid-svg-FGQKfz5hMlTIkpZt .image-shape .label,#mermaid-svg-FGQKfz5hMlTIkpZt .icon-shape .label{text-align:center;}#mermaid-svg-FGQKfz5hMlTIkpZt .node.clickable{cursor:pointer;}#mermaid-svg-FGQKfz5hMlTIkpZt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FGQKfz5hMlTIkpZt .arrowheadPath{fill:#333333;}#mermaid-svg-FGQKfz5hMlTIkpZt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FGQKfz5hMlTIkpZt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FGQKfz5hMlTIkpZt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FGQKfz5hMlTIkpZt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FGQKfz5hMlTIkpZt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FGQKfz5hMlTIkpZt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster text{fill:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt .cluster span{color:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt 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-FGQKfz5hMlTIkpZt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FGQKfz5hMlTIkpZt rect.text{fill:none;stroke-width:0;}#mermaid-svg-FGQKfz5hMlTIkpZt .icon-shape,#mermaid-svg-FGQKfz5hMlTIkpZt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FGQKfz5hMlTIkpZt .icon-shape p,#mermaid-svg-FGQKfz5hMlTIkpZt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FGQKfz5hMlTIkpZt .icon-shape .label rect,#mermaid-svg-FGQKfz5hMlTIkpZt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FGQKfz5hMlTIkpZt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FGQKfz5hMlTIkpZt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FGQKfz5hMlTIkpZt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Dashboard
全局只读

Pod / 日志 / 事件 / 指标
Staging 指定 Deployment

允许 patch
生产 RunnerManager

只允许 get
指定预拉取 DaemonSet

允许 patch/delete Pod

它没有获得 cluster-admin。写权限细化到 Namespace、资源类型和 resourceNames,见 rbac.yaml。这样 Dashboard 即使发生错误,也不能随意删除生产 Deployment 或读取全部 Secret。

ACR 拉取凭据由 acr-msit Secret 提供。Kubed 根据注解把它同步到各 Namespace:
#mermaid-svg-GTP4vX6tSqhNpnAr{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-GTP4vX6tSqhNpnAr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GTP4vX6tSqhNpnAr .error-icon{fill:#552222;}#mermaid-svg-GTP4vX6tSqhNpnAr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GTP4vX6tSqhNpnAr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GTP4vX6tSqhNpnAr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GTP4vX6tSqhNpnAr .marker.cross{stroke:#333333;}#mermaid-svg-GTP4vX6tSqhNpnAr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GTP4vX6tSqhNpnAr p{margin:0;}#mermaid-svg-GTP4vX6tSqhNpnAr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster-label text{fill:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster-label span{color:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster-label span p{background-color:transparent;}#mermaid-svg-GTP4vX6tSqhNpnAr .label text,#mermaid-svg-GTP4vX6tSqhNpnAr span{fill:#333;color:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr .node rect,#mermaid-svg-GTP4vX6tSqhNpnAr .node circle,#mermaid-svg-GTP4vX6tSqhNpnAr .node ellipse,#mermaid-svg-GTP4vX6tSqhNpnAr .node polygon,#mermaid-svg-GTP4vX6tSqhNpnAr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GTP4vX6tSqhNpnAr .rough-node .label text,#mermaid-svg-GTP4vX6tSqhNpnAr .node .label text,#mermaid-svg-GTP4vX6tSqhNpnAr .image-shape .label,#mermaid-svg-GTP4vX6tSqhNpnAr .icon-shape .label{text-anchor:middle;}#mermaid-svg-GTP4vX6tSqhNpnAr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GTP4vX6tSqhNpnAr .rough-node .label,#mermaid-svg-GTP4vX6tSqhNpnAr .node .label,#mermaid-svg-GTP4vX6tSqhNpnAr .image-shape .label,#mermaid-svg-GTP4vX6tSqhNpnAr .icon-shape .label{text-align:center;}#mermaid-svg-GTP4vX6tSqhNpnAr .node.clickable{cursor:pointer;}#mermaid-svg-GTP4vX6tSqhNpnAr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GTP4vX6tSqhNpnAr .arrowheadPath{fill:#333333;}#mermaid-svg-GTP4vX6tSqhNpnAr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GTP4vX6tSqhNpnAr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GTP4vX6tSqhNpnAr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GTP4vX6tSqhNpnAr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GTP4vX6tSqhNpnAr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GTP4vX6tSqhNpnAr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster text{fill:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr .cluster span{color:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr 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-GTP4vX6tSqhNpnAr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GTP4vX6tSqhNpnAr rect.text{fill:none;stroke-width:0;}#mermaid-svg-GTP4vX6tSqhNpnAr .icon-shape,#mermaid-svg-GTP4vX6tSqhNpnAr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GTP4vX6tSqhNpnAr .icon-shape p,#mermaid-svg-GTP4vX6tSqhNpnAr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GTP4vX6tSqhNpnAr .icon-shape .label rect,#mermaid-svg-GTP4vX6tSqhNpnAr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GTP4vX6tSqhNpnAr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GTP4vX6tSqhNpnAr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GTP4vX6tSqhNpnAr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} infra/acr-msit
Kubed Secret Syncer
runner
runnermanager
llm-proxy
runnerdashboard

选择 Kubed 是因为逐个 Namespace 手工复制 Secret 容易遗漏,而且轮换凭据时可能出现不同步。代价是 Kubed 本身拥有跨 Namespace 操作 Secret 的高权限,因此必须保护 infra Namespace 并严格控制同步注解。

Kubed 的 Helm 包直接保存在仓库中,是因为部署使用的 SAW 环境无法自由访问外部 Registry。这牺牲了一部分依赖更新便利性,但换来可重复的离线安装。

十、Staging 和生产为什么采用不同镜像策略

Copilot2API 的 Staging 使用 :latestimagePullPolicy: Always,生产使用固定的日期与提交标签。
#mermaid-svg-BChozgfaBK0zwtNj{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-BChozgfaBK0zwtNj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BChozgfaBK0zwtNj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BChozgfaBK0zwtNj .error-icon{fill:#552222;}#mermaid-svg-BChozgfaBK0zwtNj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BChozgfaBK0zwtNj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BChozgfaBK0zwtNj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BChozgfaBK0zwtNj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BChozgfaBK0zwtNj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BChozgfaBK0zwtNj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BChozgfaBK0zwtNj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BChozgfaBK0zwtNj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BChozgfaBK0zwtNj .marker.cross{stroke:#333333;}#mermaid-svg-BChozgfaBK0zwtNj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BChozgfaBK0zwtNj p{margin:0;}#mermaid-svg-BChozgfaBK0zwtNj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BChozgfaBK0zwtNj .cluster-label text{fill:#333;}#mermaid-svg-BChozgfaBK0zwtNj .cluster-label span{color:#333;}#mermaid-svg-BChozgfaBK0zwtNj .cluster-label span p{background-color:transparent;}#mermaid-svg-BChozgfaBK0zwtNj .label text,#mermaid-svg-BChozgfaBK0zwtNj span{fill:#333;color:#333;}#mermaid-svg-BChozgfaBK0zwtNj .node rect,#mermaid-svg-BChozgfaBK0zwtNj .node circle,#mermaid-svg-BChozgfaBK0zwtNj .node ellipse,#mermaid-svg-BChozgfaBK0zwtNj .node polygon,#mermaid-svg-BChozgfaBK0zwtNj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BChozgfaBK0zwtNj .rough-node .label text,#mermaid-svg-BChozgfaBK0zwtNj .node .label text,#mermaid-svg-BChozgfaBK0zwtNj .image-shape .label,#mermaid-svg-BChozgfaBK0zwtNj .icon-shape .label{text-anchor:middle;}#mermaid-svg-BChozgfaBK0zwtNj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BChozgfaBK0zwtNj .rough-node .label,#mermaid-svg-BChozgfaBK0zwtNj .node .label,#mermaid-svg-BChozgfaBK0zwtNj .image-shape .label,#mermaid-svg-BChozgfaBK0zwtNj .icon-shape .label{text-align:center;}#mermaid-svg-BChozgfaBK0zwtNj .node.clickable{cursor:pointer;}#mermaid-svg-BChozgfaBK0zwtNj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BChozgfaBK0zwtNj .arrowheadPath{fill:#333333;}#mermaid-svg-BChozgfaBK0zwtNj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BChozgfaBK0zwtNj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BChozgfaBK0zwtNj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BChozgfaBK0zwtNj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BChozgfaBK0zwtNj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BChozgfaBK0zwtNj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BChozgfaBK0zwtNj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BChozgfaBK0zwtNj .cluster text{fill:#333;}#mermaid-svg-BChozgfaBK0zwtNj .cluster span{color:#333;}#mermaid-svg-BChozgfaBK0zwtNj 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-BChozgfaBK0zwtNj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BChozgfaBK0zwtNj rect.text{fill:none;stroke-width:0;}#mermaid-svg-BChozgfaBK0zwtNj .icon-shape,#mermaid-svg-BChozgfaBK0zwtNj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BChozgfaBK0zwtNj .icon-shape p,#mermaid-svg-BChozgfaBK0zwtNj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BChozgfaBK0zwtNj .icon-shape .label rect,#mermaid-svg-BChozgfaBK0zwtNj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BChozgfaBK0zwtNj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BChozgfaBK0zwtNj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BChozgfaBK0zwtNj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 新镜像构建
Staging :latest

快速验证
验证通过
Production 固定 Tag

可追踪、可回滚

Staging 的目标是快速获得最新构建;生产的目标是可复现。如果生产也使用 latest,同一个 YAML 在不同时间可能启动不同代码,事故调查和回滚会很困难。反过来,如果 Staging 每次都人工改固定 Tag,反馈速度会下降。

Dashboard 目前也使用 latest,更方便快速更新,但从生产可复现性角度看,固定 Tag 通常更稳妥。

十一、实际部署怎么做

基础安装脚本 install.ps1 当前只负责:
#mermaid-svg-DiR31u4AscMSzivh{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-DiR31u4AscMSzivh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DiR31u4AscMSzivh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DiR31u4AscMSzivh .error-icon{fill:#552222;}#mermaid-svg-DiR31u4AscMSzivh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DiR31u4AscMSzivh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DiR31u4AscMSzivh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DiR31u4AscMSzivh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DiR31u4AscMSzivh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DiR31u4AscMSzivh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DiR31u4AscMSzivh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DiR31u4AscMSzivh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DiR31u4AscMSzivh .marker.cross{stroke:#333333;}#mermaid-svg-DiR31u4AscMSzivh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DiR31u4AscMSzivh p{margin:0;}#mermaid-svg-DiR31u4AscMSzivh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DiR31u4AscMSzivh .cluster-label text{fill:#333;}#mermaid-svg-DiR31u4AscMSzivh .cluster-label span{color:#333;}#mermaid-svg-DiR31u4AscMSzivh .cluster-label span p{background-color:transparent;}#mermaid-svg-DiR31u4AscMSzivh .label text,#mermaid-svg-DiR31u4AscMSzivh span{fill:#333;color:#333;}#mermaid-svg-DiR31u4AscMSzivh .node rect,#mermaid-svg-DiR31u4AscMSzivh .node circle,#mermaid-svg-DiR31u4AscMSzivh .node ellipse,#mermaid-svg-DiR31u4AscMSzivh .node polygon,#mermaid-svg-DiR31u4AscMSzivh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DiR31u4AscMSzivh .rough-node .label text,#mermaid-svg-DiR31u4AscMSzivh .node .label text,#mermaid-svg-DiR31u4AscMSzivh .image-shape .label,#mermaid-svg-DiR31u4AscMSzivh .icon-shape .label{text-anchor:middle;}#mermaid-svg-DiR31u4AscMSzivh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DiR31u4AscMSzivh .rough-node .label,#mermaid-svg-DiR31u4AscMSzivh .node .label,#mermaid-svg-DiR31u4AscMSzivh .image-shape .label,#mermaid-svg-DiR31u4AscMSzivh .icon-shape .label{text-align:center;}#mermaid-svg-DiR31u4AscMSzivh .node.clickable{cursor:pointer;}#mermaid-svg-DiR31u4AscMSzivh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DiR31u4AscMSzivh .arrowheadPath{fill:#333333;}#mermaid-svg-DiR31u4AscMSzivh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DiR31u4AscMSzivh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DiR31u4AscMSzivh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DiR31u4AscMSzivh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DiR31u4AscMSzivh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DiR31u4AscMSzivh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DiR31u4AscMSzivh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DiR31u4AscMSzivh .cluster text{fill:#333;}#mermaid-svg-DiR31u4AscMSzivh .cluster span{color:#333;}#mermaid-svg-DiR31u4AscMSzivh 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-DiR31u4AscMSzivh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DiR31u4AscMSzivh rect.text{fill:none;stroke-width:0;}#mermaid-svg-DiR31u4AscMSzivh .icon-shape,#mermaid-svg-DiR31u4AscMSzivh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DiR31u4AscMSzivh .icon-shape p,#mermaid-svg-DiR31u4AscMSzivh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DiR31u4AscMSzivh .icon-shape .label rect,#mermaid-svg-DiR31u4AscMSzivh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DiR31u4AscMSzivh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DiR31u4AscMSzivh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DiR31u4AscMSzivh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建基础 Namespace
安装 ACR Secret
安装 Kubed

它并不是完整的一键部署。Copilot2API 需要另外运行 install.ps1,Dashboard 需要分别应用 RBAC、Deployment、Service 和 Ingress;RunnerManager 的主要清单则位于 k8s。

典型顺序是:

  1. 使用 kubectl apply 创建生产与 Staging Namespace。
  2. 创建 ACR Secret,再安装 Kubed 进行同步。
  3. 部署 RunnerManager 的 ConfigMap、Secret、RBAC、Deployment、Service 和 HPA。
  4. 部署 Copilot2API 的 StorageClass、PVC、凭据、Deployment 和 Service。
  5. 配置账号池和 LLM 路由。
  6. 部署 Dashboard 的 RBAC、Deployment、Service 和 Ingress。
  7. 使用 kubectl get pods -A、事件、探针和 Dashboard 验证状态。

这里有两个实际注意点:顶层 README 仍写着旧路径 copilot2api/install.ps1,现在对应目录是 llm-gateway;另外基础 namespaces.yaml 没有声明 llm-proxy-staging,但 Staging Gateway 安装脚本默认使用它。因此部署前需要确认目标集群是否已由其他流程创建该 Namespace,不能把顶层脚本理解成完整环境初始化器。

十二、最终心智模型

#mermaid-svg-LJrQptbQf2t9m1Ia{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-LJrQptbQf2t9m1Ia .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LJrQptbQf2t9m1Ia .error-icon{fill:#552222;}#mermaid-svg-LJrQptbQf2t9m1Ia .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LJrQptbQf2t9m1Ia .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LJrQptbQf2t9m1Ia .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LJrQptbQf2t9m1Ia .marker.cross{stroke:#333333;}#mermaid-svg-LJrQptbQf2t9m1Ia svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LJrQptbQf2t9m1Ia p{margin:0;}#mermaid-svg-LJrQptbQf2t9m1Ia .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster-label text{fill:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster-label span{color:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster-label span p{background-color:transparent;}#mermaid-svg-LJrQptbQf2t9m1Ia .label text,#mermaid-svg-LJrQptbQf2t9m1Ia span{fill:#333;color:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia .node rect,#mermaid-svg-LJrQptbQf2t9m1Ia .node circle,#mermaid-svg-LJrQptbQf2t9m1Ia .node ellipse,#mermaid-svg-LJrQptbQf2t9m1Ia .node polygon,#mermaid-svg-LJrQptbQf2t9m1Ia .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LJrQptbQf2t9m1Ia .rough-node .label text,#mermaid-svg-LJrQptbQf2t9m1Ia .node .label text,#mermaid-svg-LJrQptbQf2t9m1Ia .image-shape .label,#mermaid-svg-LJrQptbQf2t9m1Ia .icon-shape .label{text-anchor:middle;}#mermaid-svg-LJrQptbQf2t9m1Ia .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LJrQptbQf2t9m1Ia .rough-node .label,#mermaid-svg-LJrQptbQf2t9m1Ia .node .label,#mermaid-svg-LJrQptbQf2t9m1Ia .image-shape .label,#mermaid-svg-LJrQptbQf2t9m1Ia .icon-shape .label{text-align:center;}#mermaid-svg-LJrQptbQf2t9m1Ia .node.clickable{cursor:pointer;}#mermaid-svg-LJrQptbQf2t9m1Ia .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LJrQptbQf2t9m1Ia .arrowheadPath{fill:#333333;}#mermaid-svg-LJrQptbQf2t9m1Ia .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LJrQptbQf2t9m1Ia .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LJrQptbQf2t9m1Ia .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LJrQptbQf2t9m1Ia .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LJrQptbQf2t9m1Ia .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LJrQptbQf2t9m1Ia .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster text{fill:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia .cluster span{color:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia 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-LJrQptbQf2t9m1Ia .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LJrQptbQf2t9m1Ia rect.text{fill:none;stroke-width:0;}#mermaid-svg-LJrQptbQf2t9m1Ia .icon-shape,#mermaid-svg-LJrQptbQf2t9m1Ia .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LJrQptbQf2t9m1Ia .icon-shape p,#mermaid-svg-LJrQptbQf2t9m1Ia .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LJrQptbQf2t9m1Ia .icon-shape .label rect,#mermaid-svg-LJrQptbQf2t9m1Ia .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LJrQptbQf2t9m1Ia .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LJrQptbQf2t9m1Ia .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LJrQptbQf2t9m1Ia :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AKS

容器运行与调度平台
RunnerManager

控制任务生命周期
Runner Pods

执行实际编码任务
LLM Gateway

统一模型访问
Dashboard

观察和有限运维
Kubed / PVC / RBAC

基础设施能力

可以把整个设计记成:

  • **RunnerManager 是调度员,Runner Pod 是临时工位,LLM Gateway 是统一模型入口,Dashboard 是控制室,Kubed 和 Azure Disk 是后勤系统
  • AKS 是让这些角色能够安全、动态、可恢复地协同工作的运行平台。**

它不比 VM 天然"更好",而是更适合de 当前这种大量动态 Runner、生产与 Staging 隔离、多种模型路由以及持续运维观察的工作负载。

代价则是 YAML、RBAC、网络、存储、镜像和集群升级都需要更专业的管理。

相关推荐
爱莉希雅&&&9 小时前
K8s NFS+StorageClass+PV/PVC+Deployment 实战笔记
笔记·容器·kubernetes
维核科技12 小时前
大模型私有化部署:Docker与Kubernetes实战避坑
docker·容器·kubernetes
SLD_Allen14 小时前
Kubernetes + Ray + Volcano:云原生AI训练调度体系
人工智能·云原生·kubernetes
A-刘晨阳15 小时前
Kubernetes 非共享存储详解:emptyDir 与 hostPath 从入门到实践
运维·云原生·容器·kubernetes·hostpath·emptydir
2401_8346369915 小时前
K8s 控制器全解:Deployment/DaemonSet/Job/CronJob+Service 服务发现实战宝典
容器·kubernetes·服务发现
风曦Kisaki16 小时前
# Kubernetes(K8s)笔记Day15:K8s网络工作原理【Pod 网络模型,CNI 网络插件,Calico 工作模式详解,BGP协议,路由反射器】
运维·网络·nginx·云原生·容器·kubernetes
明王明王16 小时前
从零搭建一个单节点 K8S 可观测实验室(七):从一次 Pod 创建过程,看懂 Kubernetes 核心原理
云原生·容器·kubernetes
云川之下1 天前
【k8s】NAD(NetworkAttachmentDefinition)与SR‑IOV‑Operator 关系
云原生·容器·kubernetes
潘正翔1 天前
k8s进阶_Configmap配置文件访问
运维·服务器·docker·云原生·容器·kubernetes