11 - 发布上线完整流程
一、发布流程全景
开发者日常工作 发布流水线 生产环境
─────────────── ──────────── ──────────
feature 分支开发
│
▼
本地测试通过
│
▼
提交 PR → main ┌──────────────────────────────────────┐
│ │ CI Pipeline │
▼ │ │
Code Review │ ① Lint (ruff/mypy/eslint) │
│ │ ② Unit Test (pytest/jest) │
▼ │ ③ Integration Test │
PR 合并到 main ─────────►│ ④ Docker Build (多阶段构建) │
│ ⑤ Security Scan (Trivy) │
│ ⑥ Push Image → ACR │
│ ⑦ 自动更新 Manifests Repo (staging) │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ CD Pipeline │
│ │
│ ⑧ ArgoCD 检测到 Git 变更 │
│ ⑨ 自动同步 → Staging │
│ ⑩ Staging 验证 │
│ ⑪ 提 PR 更新 Production overlay │
│ ⑫ Tech Lead 审批 + Merge │
│ ⑬ ArgoCD Sync → Production │
│ ⑭ 灰度发布 │────► 生产环境
│ ⑮ 监控观察 → 全量发布 │
└──────────────────────────────────────┘二、Dockerfile 在研发流程中的位置
Dockerfile 是什么阶段写的?
Dockerfile 在开发阶段编写,跟随业务代码一起维护在同一个代码仓库中。
开发阶段写 Dockerfile
─────────────────────
项目仓库结构(每个服务一个 Dockerfile)
├── robotics-api/
│ ├── src/ ← 业务代码
│ ├── tests/ ← 测试代码
│ ├── requirements.txt ← Python 依赖
│ ├── Dockerfile ← 👈 开发者编写,跟代码一起提交
│ └── .github/workflows/ci.yml
│
├── robotics-training/
│ ├── src/
│ ├── configs/
│ ├── Dockerfile ← 👈 训练镜像的 Dockerfile
│ └── .github/workflows/ci.yml
│
└── robotics-llm-server/
├── src/
├── Dockerfile ← 👈 LLM 推理镜像的 Dockerfile
└── .github/workflows/ci.yml不同镜像的 Dockerfile 编写职责
| 镜像类型 | 谁写 | 什么时候写 | 变更频率 | 存放位置 |
|---|---|---|---|---|
| 基础镜像 (cuda-base, pytorch-base) | DevOps/SRE | 项目初期搭建 | 低(季度级) | 独立仓库 robotics-base/ |
| 训练镜像 (vision-train) | 算法工程师 | 开发训练代码时 | 中(周级) | robotics-training/Dockerfile |
| API 服务镜像 (api-gateway) | 后端工程师 | 开发 API 时 | 中(周级) | robotics-api/Dockerfile |
| LLM 推理镜像 (llm-server) | 算法 + 后端 | 模型上线时 | 中 | robotics-llm-server/Dockerfile |
| 前端镜像 (admin-web) | 前端工程师 | 开发 Web 时 | 中 | robotics-admin-web/Dockerfile |
| 工具镜像 (data-pipeline) | 数据工程师 | 开发数据管道时 | 中 | robotics-data-pipeline/Dockerfile |
Dockerfile 的生命周期
阶段 1: 开发编写
──────────────
开发者在本地编写 Dockerfile
│
├── 基于基础镜像 (FROM robotics-base/pytorch-base:2.2.0)
├── 安装项目依赖 (COPY requirements.txt + pip install)
├── 复制业务代码 (COPY src/ /app/src/)
├── 配置启动命令 (CMD / ENTRYPOINT)
└── 本地测试: docker build -t myapp:dev . && docker run myapp:dev
阶段 2: 代码审查
──────────────
Dockerfile 随代码一起提交 PR
│
├── Reviewer 检查: 基础镜像版本、层缓存优化、安全性
├── 确认多阶段构建(减小镜像体积)
└── 确认没有硬编码 Secret
阶段 3: CI 自动构建
───────────────
PR 合并到 main → GitHub Actions 自动执行
│
├── docker build(用 Dockerfile 构建镜像)
├── Trivy 安全扫描
├── docker push → ACR(推送到镜像仓库)
└── 生成镜像 tag: 20260315-abc1234
阶段 4: CD 部署
──────────────
CI 更新 K8s manifests repo 中的 image tag
│
└── ArgoCD 检测到变更 → 将新镜像部署到集群典型 Dockerfile 示例
API 服务(Python,多阶段构建):
dockerfile
# ===== 构建阶段 =====
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# ===== 运行阶段 =====
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY src/ ./src/
RUN useradd -r -s /bin/false appuser
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz')" || exit 1
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]训练镜像(GPU,基于内部基础镜像):
dockerfile
FROM registry-vpc.cn-hangzhou.aliyuncs.com/robotics-base/pytorch-base:2.2.0-cuda12.1
WORKDIR /workspace
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
COPY configs/ ./configs/
CMD ["python", "-m", "torch.distributed.run", "src/train.py"]前端服务(Node.js,多阶段构建):
dockerfile
# ===== 构建阶段 =====
FROM node:20-alpine AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ===== 运行阶段 =====
FROM nginx:alpine
COPY --from=builder /build/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80关键原则
- Dockerfile 跟业务代码在同一仓库 — 代码改了镜像自动重建
- 基础镜像单独管理 — 变更频率低,需要严格版本控制
- 开发者负责自己服务的 Dockerfile — 谁开发谁维护
- CI 负责构建和推送 — 开发者不手动 push 镜像到 ACR
- 多阶段构建 — 减小镜像体积,提高安全性(不包含构建工具)
三、发布前 Checklist
每次发布前,必须逐项检查:
代码质量
- [ ] 所有 CI 检查通过(Lint、Test、Scan)
- [ ] PR 经过至少 1 人 Code Review
- [ ] 无 CRITICAL/HIGH 级别安全漏洞(Trivy 扫描)
- [ ] 测试覆盖率不低于既有水平
配置确认
- [ ] ConfigMap/Secret 变更已同步到目标环境
- [ ] 环境变量无遗漏(对比 staging 与 production)
- [ ] 资源 requests/limits 已设置且合理
- [ ] Health probes(liveness/readiness/startup)已配置
依赖检查
- [ ] 数据库 Migration 已执行(如有)
- [ ] 上下游服务 API 兼容性已确认
- [ ] 外部依赖(ACR 镜像、NAS 挂载、OSS Bucket)可访问
发布窗口
- [ ] 选择低流量时段发布(如有)
- [ ] 通知相关团队发布计划
- [ ] 确认回滚方案可执行
四、发布策略详解
策略对比
| 策略 | 原理 | 适用场景 | 回滚速度 | 资源开销 | 复杂度 |
|---|---|---|---|---|---|
| Rolling Update | 逐步替换旧 Pod | 常规更新、无状态服务 | 中 | 低 | 低 |
| Canary(灰度) | 少量流量验证新版本 | 重要服务、用户敏感 | 快 | 中 | 中 |
| Blue-Green | 新旧双副本一键切换 | 关键服务、零停机 | 最快 | 高(双倍资源) | 中 |
| A/B Testing | 按条件路由不同版本 | 功能验证、商业决策 | 快 | 高 | 高 |
策略 1:Rolling Update(K8s 原生)
最基本的发布方式,直接由 Deployment 控制。
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: production
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新时最多多出 1 个 Pod
maxUnavailable: 0 # 更新时不允许有 Pod 不可用(保证可用性)
template:
spec:
containers:
- name: api
image: registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/api-gateway:20260315-abc1234
readinessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
terminationGracePeriodSeconds: 30更新过程:
初始状态: [v1] [v1] [v1] [v1] ← 4 个旧 Pod
↓ maxSurge=1, 多创建 1 个
Step 1: [v1] [v1] [v1] [v1] [v2] ← v2 创建中
↓ v2 Ready, 移除 1 个 v1
Step 2: [v1] [v1] [v1] [v2] ← 继续
↓ 重复
Step 3: [v1] [v1] [v2] [v2]
Step 4: [v1] [v2] [v2] [v2]
Step 5: [v2] [v2] [v2] [v2] ← 全量完成关键参数说明:
| 参数 | 含义 | 推荐值 | 说明 |
|---|---|---|---|
maxSurge | 超过 replicas 的额外 Pod 数 | 25% 或 1 | 越大更新越快,资源消耗越多 |
maxUnavailable | 允许不可用的 Pod 数 | 0 | 设为 0 保证零停机 |
terminationGracePeriodSeconds | Pod 优雅关闭等待时间 | 30s | 让进行中的请求处理完毕 |
手动操作:
bash
# 触发更新(修改镜像 tag)
kubectl set image deployment/api-gateway api=registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/api-gateway:20260316-def5678 -n production
# 观察更新进度
kubectl rollout status deployment/api-gateway -n production
# 查看更新历史
kubectl rollout history deployment/api-gateway -n production
# 回滚到上一个版本
kubectl rollout undo deployment/api-gateway -n production
# 回滚到指定版本
kubectl rollout undo deployment/api-gateway --to-revision=3 -n production
# 暂停/恢复更新
kubectl rollout pause deployment/api-gateway -n production
kubectl rollout resume deployment/api-gateway -n production策略 2:Canary 灰度发布(Argo Rollouts)
灰度发布是生产环境最推荐的方式。需要安装 Argo Rollouts。
安装 Argo Rollouts
bash
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
# 安装 kubectl 插件
# macOS
brew install argoproj/tap/kubectl-argo-rollouts
# 验证
kubectl argo rollouts versionCanary Rollout 定义
yaml
# rollout-api-gateway.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-gateway
namespace: production
spec:
replicas: 5
revisionHistoryLimit: 3
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: api
image: registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/api-gateway:v3.1.0
ports:
- containerPort: 8000
readinessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
strategy:
canary:
maxSurge: "25%"
maxUnavailable: 0
steps:
# Step 1: 10% 流量给新版本
- setWeight: 10
# Step 2: 暂停,人工观察 5 分钟
- pause: {duration: 5m}
# Step 3: 扩大到 30%
- setWeight: 30
# Step 4: 暂停,观察 + 可选人工确认
- pause: {duration: 10m}
# Step 5: 扩大到 60%
- setWeight: 60
# Step 6: 暂停,继续观察
- pause: {duration: 10m}
# Step 7: 全量发布
- setWeight: 100灰度发布过程:
流量分配
──────
Step 1: ██░░░░░░░░ 10% → v2 (90% v1) 观察 5 分钟
Step 2: ███░░░░░░░ 30% → v2 (70% v1) 观察 10 分钟
Step 3: ██████░░░░ 60% → v2 (40% v1) 观察 10 分钟
Step 4: ██████████ 100% → v2 全量完成操作命令:
bash
# 触发灰度发布(更新镜像)
kubectl argo rollouts set image api-gateway api=registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/api-gateway:v3.2.0 -n production
# 实时观察灰度进度(带 Watch)
kubectl argo rollouts get rollout api-gateway -n production -w
# 手动推进到下一步(如果 pause 没设 duration)
kubectl argo rollouts promote api-gateway -n production
# 跳过所有步骤直接全量
kubectl argo rollouts promote api-gateway --full -n production
# 灰度过程中发现问题 → 立即中止回滚
kubectl argo rollouts abort api-gateway -n production
# 中止后重试
kubectl argo rollouts retry rollout api-gateway -n production灰度 + 自动分析(推荐)
结合 Prometheus 指标自动判断是否继续灰度:
yaml
# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
namespace: production
spec:
metrics:
- name: success-rate
interval: 60s
# 成功率必须 > 99%
successCondition: result[0] >= 0.99
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{service="{{args.service-name}}", status=~"2.."}[5m]))
/
sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))
args:
- name: service-name
---
# rollout 中引用 analysis
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-gateway
namespace: production
spec:
strategy:
canary:
analysis:
templates:
- templateName: success-rate
startingStep: 1 # 从第 2 步开始分析
args:
- name: service-name
value: api-gateway
steps:
- setWeight: 10
- pause: {duration: 5m}
- setWeight: 30
- pause: {duration: 10m}
- setWeight: 60
- pause: {duration: 10m}
- setWeight: 100自动分析判定逻辑:
灰度期间持续采集 Prometheus 指标
│
├── 成功率 ≥ 99% → 继续推进
├── 成功率 < 99% 但失败次数 < 3 → 继续观察
└── 连续失败 ≥ 3 次 → 自动回滚策略 3:Blue-Green 蓝绿部署(Argo Rollouts)
yaml
# rollout-bluegreen.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: llm-server
namespace: production
spec:
replicas: 3
revisionHistoryLimit: 2
selector:
matchLabels:
app: llm-server
template:
metadata:
labels:
app: llm-server
spec:
containers:
- name: llm
image: registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/llm-server:v2.0.0
ports:
- containerPort: 8080
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
strategy:
blueGreen:
activeService: llm-server-active # 当前生产流量
previewService: llm-server-preview # 预览流量(内部测试)
autoPromotionEnabled: false # 不自动切换,需人工确认
prePromotionAnalysis: # 切换前自动检查
templates:
- templateName: llm-health-check
scaleDownDelaySeconds: 300 # 切换后旧版本保留 5 分钟再缩容
---
apiVersion: v1
kind: Service
metadata:
name: llm-server-active
namespace: production
spec:
selector:
app: llm-server
ports:
- port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: llm-server-preview
namespace: production
spec:
selector:
app: llm-server
ports:
- port: 8080Blue-Green 流程:
状态 1(初始):
Active Service ──► [v1] [v1] [v1] ← 处理全部生产流量
Preview Service ──► (空)
状态 2(部署新版本):
Active Service ──► [v1] [v1] [v1] ← 仍然处理生产流量
Preview Service ──► [v2] [v2] [v2] ← 内部测试访问
状态 3(验证通过,执行切换):
Active Service ──► [v2] [v2] [v2] ← 一键切换到新版本
Preview Service ──► [v1] [v1] [v1] ← 旧版本保留 5 分钟
状态 4(确认无问题,清理):
Active Service ──► [v2] [v2] [v2] ← 正式运行
Preview Service ──► (缩容清理)操作:
bash
# 内部验证 preview 版本
kubectl port-forward svc/llm-server-preview 8080:8080 -n production
curl http://localhost:8080/v1/health
# 确认切换
kubectl argo rollouts promote llm-server -n production
# 发现问题回滚(立即切回旧版本)
kubectl argo rollouts undo llm-server -n production策略选型建议(AI 公司场景)
| 服务类型 | 推荐策略 | 原因 |
|---|---|---|
| API Gateway | Canary(灰度) | 直接面向用户,需要渐进验证 |
| LLM 推理服务 | Blue-Green | GPU 资源昂贵,需要快速切换和回滚 |
| 管理后台 Web | Rolling Update | 内部系统,风险低 |
| 数据处理 Pipeline | Rolling Update | 后台任务,无实时流量 |
| 训练镜像 | 不走 CD,手动/Arena 提交 | 训练是一次性 Job,非长驻服务 |
五、完整发布 SOP(标准操作流程)
4.1 常规服务发布
Day 0 (发布前一天)
────────────────
① 开发完成,PR 合并到 main
② CI 全部通过,镜像已推送到 ACR
③ 发布通知:"明天 XX:XX 计划发布 api-gateway v3.2.0"
④ 确认回滚方案(上一个稳定镜像 tag)
Day 1 (发布日)
────────────────
准备阶段 (T-30min)
├── 确认 Staging 验证通过
├── 确认 Grafana 当前基线指标(错误率、延迟、QPS)
├── 打开 Grafana 发布仪表盘
└── 在群里通知:"发布开始"
执行阶段 (T=0)
├── 提交 PR:更新 production overlay 的 image tag
├── Tech Lead 审批 Merge
├── ArgoCD 开始同步
└── 观察 Rollout 状态
灰度阶段
├── 10% 流量:观察 5 分钟
│ └── 检查:5xx 错误率、P99 延迟、Pod 状态
├── 30% 流量:观察 10 分钟
│ └── 检查同上 + 业务指标
├── 60% 流量:观察 10 分钟
└── 100% 全量:继续观察 30 分钟
验收阶段 (T+1h)
├── 确认所有监控指标正常
├── 确认无用户反馈异常
├── 在群里通知:"发布完成,一切正常"
└── 更新发布记录4.2 LLM 推理服务发布
LLM 服务因为 GPU 资源和模型加载的特殊性,流程有所不同:
LLM 推理服务发布 (Blue-Green)
─────────────────────────────
准备阶段
├── 新模型已上传到 CPFS/OSS
├── 新镜像已构建并扫描
└── GPU 节点有足够空闲资源(同时运行新旧两组)
部署预览版
├── 更新 Rollout 镜像 tag
├── 等待新 Pod 启动(GPU 服务通常需要 3-10 分钟加载模型)
│ └── kubectl argo rollouts get rollout llm-server -n production -w
├── 通过 preview Service 内部测试
│ ├── 功能测试:关键 prompt 测试
│ ├── 性能测试:吞吐量和延迟对比
│ └── 质量测试:输出质量抽检
└── 测试通过
执行切换
├── kubectl argo rollouts promote llm-server -n production
├── 流量瞬间切换到新版本(毫秒级)
├── 监控 30 分钟
│ ├── GPU 利用率
│ ├── 推理延迟 P50/P99
│ ├── 吞吐量(tokens/s)
│ └── OOM / CUDA 错误
└── 旧版本 5 分钟后自动缩容
异常处理
└── 发现问题 → kubectl argo rollouts undo llm-server -n production
└── 立即切回旧版本(秒级回滚)4.3 训练任务发布
训练任务不是长驻服务,使用 Job 方式发布:
训练任务发布流程
────────────────
① 训练代码推送到 main → CI 自动构建训练镜像
② 镜像 tag:registry.cn-hangzhou.aliyuncs.com/robotics-training/vision-train:20260315-abc1234
③ 算法工程师修改训练配置
└── 修改 PyTorchJob YAML 中的:
- image tag(指向新镜像)
- 训练参数(epochs, batch_size, lr)
- 资源配置(GPU 数量、节点数)
④ 提交到 manifests repo → 或者用 Arena 命令行提交
# Arena 方式
arena submit pytorchjob \
--name=resnet50-train-v3 \
--gpus=8 \
--workers=4 \
--image=registry-vpc.cn-hangzhou.aliyuncs.com/robotics-training/vision-train:20260315-abc1234 \
--data=training-cpfs:/data \
"python train.py --config /data/configs/resnet50.yaml"
⑤ 监控训练任务
arena get resnet50-train-v3
arena logs resnet50-train-v3
⑥ 训练完成 → 模型文件保存到 CPFS/OSS六、Ingress 灰度(无 Argo Rollouts 的方案)
如果暂时没有引入 Argo Rollouts,可以用 Nginx Ingress 注解实现基于 Header 或权重的灰度:
基于权重的灰度
yaml
# 生产 Ingress(主流量)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-main
namespace: production
spec:
ingressClassName: nginx
rules:
- host: api.robotics.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-gateway-stable
port:
number: 8000
---
# 灰度 Ingress(部分流量到新版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-canary
namespace: production
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量到新版本
spec:
ingressClassName: nginx
rules:
- host: api.robotics.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-gateway-canary
port:
number: 8000基于 Header 的灰度(内部测试)
yaml
# 只有带特定 Header 的请求走新版本
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-canary
namespace: production
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
ingressClassName: nginx
rules:
- host: api.robotics.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-gateway-canary
port:
number: 8000bash
# 内部测试新版本
curl -H "X-Canary: true" https://api.robotics.com/v1/health
# 普通请求仍走旧版本
curl https://api.robotics.com/v1/health灰度调整流程
bash
# 调整灰度权重:10% → 30% → 60% → 100%
kubectl annotate ingress api-gateway-canary \
nginx.ingress.kubernetes.io/canary-weight="30" \
--overwrite -n production
# 全量发布后:删除灰度 Ingress,更新主 Deployment
kubectl delete ingress api-gateway-canary -n production
kubectl set image deployment/api-gateway-stable api=<new-image> -n production七、发布监控与告警
发布期间 Grafana 仪表盘核心指标
┌─────────────────────────────────────────────────────┐
│ 发布监控仪表盘 │
│ │
│ ┌───────────────────┐ ┌───────────────────────┐ │
│ │ HTTP 5xx 错误率 │ │ 响应延迟 P50/P99 │ │
│ │ ≤ 0.1% ✅ │ │ P99 < 500ms ✅ │ │
│ │ > 1% 🔴 回滚! │ │ P99 > 2s 🔴 回滚! │ │
│ └───────────────────┘ └───────────────────────┘ │
│ │
│ ┌───────────────────┐ ┌───────────────────────┐ │
│ │ Pod 重启次数 │ │ CPU/内存使用率 │ │
│ │ = 0 ✅ │ │ < 80% ✅ │ │
│ │ ≥ 1 🟡 关注 │ │ > 90% 🔴 排查 │ │
│ └───────────────────┘ └───────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 业务指标(根据服务类型) │ │
│ │ API: QPS、成功率 │ │
│ │ LLM: tokens/s、推理延迟、GPU 利用率 │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘Prometheus 告警规则(发布期间增强)
yaml
# prometheus-release-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: release-alerts
namespace: monitoring
spec:
groups:
- name: release-canary
rules:
- alert: CanaryHighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5..", canary="true"}[2m]))
/
sum(rate(http_requests_total{canary="true"}[2m]))
> 0.01
for: 1m
labels:
severity: critical
annotations:
summary: "灰度版本错误率超过 1%,请立即检查"
runbook: "执行回滚:kubectl argo rollouts abort <rollout-name>"
- alert: CanaryHighLatency
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{canary="true"}[2m])) by (le)
) > 2
for: 2m
labels:
severity: warning
annotations:
summary: "灰度版本 P99 延迟超过 2 秒"
- alert: PodCrashDuringRelease
expr: |
increase(kube_pod_container_status_restarts_total[5m]) > 0
for: 0m
labels:
severity: critical
annotations:
summary: "发布期间 Pod 发生重启"八、回滚操作手册
回滚决策树
发布后发现异常
│
├── 5xx 错误率 > 1%? ──► 是 → 立即回滚
│
├── P99 延迟恶化 > 100%? ──► 是 → 立即回滚
│
├── Pod CrashLoopBackOff? ──► 是 → 立即回滚
│
├── 功能异常但不影响核心链路? ──► 是 → 暂停灰度,排查
│ │
│ ├── 能快速修复 → hotfix 分支
│ └── 不能 → 回滚
│
└── 指标正常 → 继续推进回滚命令速查
bash
# ==================== Argo Rollouts 回滚 ====================
# 灰度发布中止(灰度阶段)
kubectl argo rollouts abort api-gateway -n production
# 蓝绿部署回滚(已切换后)
kubectl argo rollouts undo llm-server -n production
# ==================== 原生 Deployment 回滚 ====================
# 回滚到上一版本
kubectl rollout undo deployment/api-gateway -n production
# 查看历史版本
kubectl rollout history deployment/api-gateway -n production
# 回滚到指定版本
kubectl rollout undo deployment/api-gateway --to-revision=5 -n production
# ==================== GitOps 回滚(最推荐) ====================
# 在 manifests repo 中 revert commit
cd robotics-k8s-manifests
git revert HEAD # 撤销最新的 image tag 变更
git push # ArgoCD 自动同步回旧版本
# ==================== 紧急回滚(绕过 GitOps) ====================
# 仅在极端情况下使用,事后必须同步 Git
kubectl set image deployment/api-gateway \
api=registry-vpc.cn-hangzhou.aliyuncs.com/robotics-serving/api-gateway:v3.1.0 \
-n production回滚后处理
回滚执行完毕
│
├── ① 确认服务恢复正常(监控指标回到基线)
├── ② 通知团队:"已回滚到 v3.1.0,服务恢复正常"
├── ③ 创建 Issue 记录回滚原因
├── ④ 排查根因(查日志、查监控、复现问题)
├── ⑤ 修复 → 走完整 CI/CD 流程重新发布
└── ⑥ 复盘会议(如果是 P0/P1 级别事故)九、发布记录模板
每次发布都应记录,建议在团队 Wiki 或 Git 中维护:
markdown
## 发布记录
### 2026-03-15 api-gateway v3.2.0
| 项目 | 内容 |
|------|------|
| **服务** | api-gateway |
| **版本** | v3.1.0 → v3.2.0 |
| **镜像** | robotics-serving/api-gateway:20260315-abc1234 |
| **发布策略** | Canary 灰度(10% → 30% → 60% → 100%) |
| **发布人** | @darren |
| **审批人** | @tech-lead |
| **开始时间** | 2026-03-15 14:00 |
| **全量时间** | 2026-03-15 14:45 |
| **主要变更** | 新增 XX 接口、优化 YY 性能 |
| **关联 PR** | #123, #125 |
| **发布结果** | ✅ 成功 |
| **异常记录** | 无 |十、不同团队角色的发布职责
┌─────────────────────────────────────────────────────────────┐
│ 发布流程中的角色 │
│ │
│ 开发工程师 │
│ ├── 编写代码,提交 PR │
│ ├── Code Review │
│ └── 确认 Staging 验证通过 │
│ │
│ Tech Lead / 发布负责人 │
│ ├── 审批 Production PR │
│ ├── 监控灰度指标 │
│ ├── 决定是否推进/回滚 │
│ └── 异常时协调排查 │
│ │
│ SRE / DevOps │
│ ├── 维护 CI/CD 基础设施 │
│ ├── 维护 ArgoCD、监控告警 │
│ ├── 紧急回滚操作 │
│ └── 发布后事故复盘 │
│ │
│ 算法工程师(AI 场景) │
│ ├── 训练任务提交 │
│ ├── 模型质量验证 │
│ └── LLM 推理服务的 preview 测试 │
│ │
└─────────────────────────────────────────────────────────────┘十一、发布成熟度演进路线
根据团队阶段选择合适的发布方式:
阶段 1(起步期)
├── 手动 kubectl apply
├── 简单 Rolling Update
├── 人工观察 kubectl get pods
└── 适合:团队 < 5 人,服务 < 5 个
↓ 团队和服务增长
阶段 2(标准化)
├── GitHub Actions CI + ACR
├── ArgoCD 自动同步
├── Kustomize 管理多环境
├── Grafana 基础监控
└── 适合:团队 5-15 人,服务 5-20 个
↓ 需要更高发布质量
阶段 3(成熟期)
├── Argo Rollouts 灰度发布
├── 自动分析(Prometheus 指标驱动)
├── 完善的告警 + 自动回滚
├── 发布 SOP + 记录
└── 适合:团队 15+ 人,核心业务服务
↓ 追求极致
阶段 4(卓越期)
├── 全自动 Progressive Delivery
├── Chaos Engineering 验证
├── SLO 驱动的发布决策
├── Feature Flag + A/B Testing
└── 适合:大规模生产系统对你们 AI 机器人公司的建议
当前阶段建议: 阶段 2 → 阶段 3 过渡
近期目标(1-2 个月):
├── ✅ GitHub Actions CI(已规划)
├── ✅ ArgoCD + Kustomize(已规划)
├── ⬜ 部署 Grafana 发布监控仪表盘
└── ⬜ 制定发布 SOP 文档
中期目标(3-6 个月):
├── ⬜ 引入 Argo Rollouts(API Gateway 先试点)
├── ⬜ LLM 推理服务 Blue-Green 部署
├── ⬜ 配置自动分析(AnalysisTemplate)
└── ⬜ 建立发布记录和复盘机制