第 16/19 天
引言:让发布拥有”自动驾驶”能力
在上一篇文章《金丝雀发布实战》中,我们通过 setWeight 与 pause 步骤实现了流量分割的渐进式发布。但这种模式有一个明显短板——所有决策都依赖人工值守:运维人员需要盯着 Grafana 看板,一旦发现异常指标(错误率飙升、延迟骤增),再手动执行 kubectl rollout undo 回滚。在凌晨发布窗口或大规模灰度场景下,人工判断既慢又不可靠。
今天我们引入 Argo Rollouts 的核心能力之一:AnalysisTemplate。它能把 Prometheus 指标分析嵌入 Rollout 发布流程,实现”指标达标则继续推进、指标异常则自动回滚”的闭环,让金丝雀发布真正拥有自动驾驶能力。这是从”半自动渐进交付”迈向”全自动安全发布”的关键一跃。

核心概念解析
AnalysisTemplate 是什么
AnalysisTemplate 是 Argo Rollouts 提供的一种 CRD 资源,它定义了一组”成功/失败条件”以及获取指标的查询方法。在 Rollout 发布过程中,AnalysisRun 资源会被自动实例化,根据 AnalysisTemplate 的定义周期性地执行指标查询,并根据结果判定当前发布是否应该继续推进、暂停还是回滚。
简单说:AnalysisTemplate 是”体检问卷”,AnalysisRun 是实际执行的”体检报告”,Rollout 则是”按体检结果决定是否继续上班”的决策者。
三种使用模式
Argo Rollouts 提供三种集成方式将分析嵌入发布流程:
- Background Analysis(后台分析):在整个发布周期内持续运行指标分析,与金丝雀权重推进并行执行。一旦分析失败,立即中断发布并触发回滚。
- Inline Analysis(内联分析):作为 Rollout 步骤中的一个独立阶段,只有分析通过才会推进到下一步。适合需要严格卡关的场景。
- Step-level Analysis(步骤级分析):在特定
setWeight步骤后紧跟分析,实现”切流量→观察→决策”的精细控制。
关键字段速览
一个 AnalysisTemplate 通常包含以下核心字段:
metrics:指标定义列表,每个指标包含 name、interval、successCondition、failureCondition 以及 provider。args:模板参数,允许 Rollout 在引用时动态传入值(如 Service Name)。provider.prometheus:声明 Prometheus 查询地址与 PromQL 表达式。successCondition/failureCondition:用 Go 表达式书写的结果判定逻辑,例如result[0].value >= 0.95。
实战步骤
前置条件检查
在开始前,确认集群中已安装 Argo Rollouts(第 14 天已完成)并具备可用的 Prometheus 实例(第 11 天已部署 kube-prometheus-stack)。执行以下命令验证:
# 检查 Argo Rollouts 控制器运行状态
kubectl get pods -n argo-rollouts
# 期望输出: argo-rollouts-xxx-xxx 1/1 Running
# 检查 Rollout CRD 是否就绪
kubectl get crd rollouts.argoproj.io analysistemplates.argoproj.io analysisruns.argoproj.io
# 确认 Prometheus Service 可达
kubectl get svc -n monitoring prometheus-operated
# 记录 ClusterIP 与端口,后续 AnalysisTemplate 要引用该地址
PROM_URL=$(kubectl get svc -n monitoring prometheus-operated -o jsonpath='{.spec.clusterIP}')
echo "Prometheus URL: http://${PROM_URL}:9090"
步骤一:定义 AnalysisTemplate
创建文件 analysis-template.yaml,定义两个关键指标——请求成功率与 P99 延迟。成功率低于 95% 判定失败,P99 延迟超过 500ms 判定失败。
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: canary-metrics-analysis
namespace: demo-app
spec:
args:
– name: service-name
valueFrom:
fieldRef:
fieldPath: metadata.name
metrics:
– name: success-rate
interval: 30s
count: 5
successCondition: result[0].value >= 0.95
failureCondition: result[0].value < 0.95
provider:
prometheus:
address: "http://prometheus-operated.monitoring.svc.cluster.local:9090"
query: |
sum(rate(http_requests_total{service="{{args.service-name}}",code=~"2.."}[2m]))
/
sum(rate(http_requests_total{service="{{args.service-name}}"}[2m]))
– name: p99-latency
interval: 30s
count: 5
successCondition: result[0].value <= 500
failureLimit: 2
provider:
prometheus:
address: "http://prometheus-operated.monitoring.svc.cluster.local:9090"
query: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{service="{{args.service-name}}"}[2m])) by (le)
) * 1000
关键字段说明:
interval: 30s:每 30 秒查询一次指标。count: 5:总共查询 5 次,全部通过才算成功。failureLimit: 2:允许失败 2 次,超过则判定整体失败(用于容忍偶发抖动)。args.service-name:从 Rollout 元数据动态注入服务名,实现模板复用。
应用模板:
kubectl apply -f analysis-template.yaml
kubectl get analysistemplate -n demo-app
# NAME AGE
# canary-metrics-analysis 5s
步骤二:在 Rollout 中引用 AnalysisTemplate
修改上一篇文章中的 Rollout 资源,在每个金丝雀权重步骤后嵌入 analysis 阶段,实现”切 25% 流量→分析→通过则切 50%→分析→通过则完成”的闭环。
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: demo-app
namespace: demo-app
spec:
replicas: 4
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
– name: demo-app
image: registry.stellardata.top/demo/demo-app:v2
ports:
– containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
strategy:
canary:
steps:
– setWeight: 25
– pause: { duration: 1m }
– analysis:
templates:
– templateName: canary-metrics-analysis
– setWeight: 50
– pause: { duration: 1m }
– analysis:
templates:
– templateName: canary-metrics-analysis
– setWeight: 100
执行更新并观察:
kubectl apply -f rollout-with-analysis.yaml
kubectl argo rollouts get rollout demo-app -n demo-app –watch
在 watch 输出中你会看到如下步骤流转:
# 预期输出
NAME STATUS CANARY WEIGHT
demo-app Progressing – 25%
# → Pause 1m
# → Analysis (Running) canary-metrics-analysis
# → Analysis (Successful)
demo-app Progressing – 50%
# → Analysis (Running) canary-metrics-analysis
# → Analysis (Successful)
demo-app Healthy – 100%
步骤三:模拟异常触发自动回滚
为验证自动回滚机制,部署一个故意返回 500 错误的”故障版本”镜像,观察 AnalysisTemplate 如何在成功率跌破 95% 时自动中断并回滚。
# 触发故障版本发布
kubectl argo rollouts set image demo-app demo-app=registry.stellardata.top/demo/demo-app:broken -n demo-app
# 实时查看发布状态与分析结果
kubectl argo rollouts get rollout demo-app -n demo-app –watch
# 单独查看 AnalysisRun 资源(每次 analysis 步骤会生成一个)
kubectl get analysisrun -n demo-app
# NAME STATUS AGE
# demo-app-canary-metrics-analysis Failed 35s
当 AnalysisRun 状态变为 Failed,Rollout 控制器会立即将 ReplicaSet 回滚到上一个稳定版本,无需人工介入。查看回滚事件:
kubectl describe rollout demo-app -n demo-app | tail -n 30
# 关键事件:
# Warning RolloutAborted … metric "success-rate" failed: result[0].value=0.82 < 0.95
# Normal RolloutRolledBack … Rolled back to revision 1
步骤四:多指标联合分析与失败策略
生产环境通常需要组合多个指标。下面的 JSON 配置展示了一个更完整的 AnalysisTemplate,同时监控 错误率、CPU 使用率、内存使用率 三个维度,任一指标失败即触发回滚:
{
"apiVersion": "argoproj.io/v1alpha1",
"kind": "AnalysisTemplate",
"metadata": { "name": "full-health-check", "namespace": "demo-app" },
"spec": {
"metrics": [
{
"name": "error-rate",
"interval": "30s",
"count": 3,
"successCondition": "result[0].value <= 0.05",
"failureLimit": 1,
"provider": {
"prometheus": {
"address": "http://prometheus-operated.monitoring.svc.cluster.local:9090",
"query": "sum(rate(http_requests_total{service="demo-app",code=~"5.."}[1m])) / sum(rate(http_requests_total{service="demo-app"}[1m]))"
}
}
},
{
"name": "cpu-usage",
"interval": "30s",
"count": 3,
"successCondition": "result[0].value <= 0.80",
"failureLimit": 2,
"provider": {
"prometheus": {
"address": "http://prometheus-operated.monitoring.svc.cluster.local:9090",
"query": "sum(rate(container_cpu_usage_seconds_total{pod=~"demo-app-.*"}[1m])) / count(kube_pod_container_resource_limits{pod=~"demo-app-.*",resource="cpu"})"
}
}
},
{
"name": "memory-usage",
"interval": "30s",
"count": 3,
"successCondition": "result[0].value <= 0.85",
"failureLimit": 2,
"provider": {
"prometheus": {
"address": "http://prometheus-operated.monitoring.svc.cluster.local:9090",
"query": "sum(container_memory_working_set_bytes{pod=~"demo-app-.*"}) / sum(kube_pod_container_resource_limits{pod=~"demo-app-.*",resource="memory"})"
}
}
}
]
}
}
不同指标可设置不同的 failureLimit:错误率容忍 1 次失败(严格),资源类指标容忍 2 次(宽松),避免因瞬时抖动误杀正常发布。
步骤五:使用 ClusterAnalysisTemplate 实现跨命名空间复用
当多个业务团队各自部署应用时,逐个为每个 Rollout 维护 AnalysisTemplate 太繁琐。Argo Rollouts 提供 ClusterAnalysisTemplate——集群级别的全局模板,任意 namespace 的 Rollout 均可引用。
apiVersion: argoproj.io/v1alpha1
kind: ClusterAnalysisTemplate
metadata:
name: global-canary-check
spec:
args:
– name: service-name
metrics:
– name: success-rate
interval: 30s
count: 5
successCondition: result[0].value >= 0.95
failureLimit: 1
provider:
prometheus:
address: "http://prometheus-operated.monitoring.svc.cluster.local:9090"
query: |
sum(rate(http_requests_total{service="{{args.service-name}}",code=~"2.."}[2m]))
/
sum(rate(http_requests_total{service="{{args.service-name}}"}[2m]))
—
# 业务 Rollout 引用集群级模板
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payment-service
namespace: payment
spec:
strategy:
canary:
steps:
– setWeight: 20
– analysis:
templates:
– templateName: global-canary-check
clusterScope: true
args:
– name: service-name
value: payment-service
– setWeight: 100
注意 clusterScope: true 这个关键字段——它告诉 Argo Rollouts 去集群级别查找模板而非命名空间级别。
步骤六:使用 Python 脚本批量验证 AnalysisRun 状态
当集群中有大量应用同时进行灰度时,手动 kubectl get analysisrun 逐个查看效率很低。下面这段 Python 脚本通过 Kubernetes API 批量拉取所有 AnalysisRun 状态并输出汇总报告:
#!/usr/bin/env python3
"""批量汇总集群中所有 AnalysisRun 的执行状态"""
from kubernetes import client, config
from collections import Counter
def main():
config.load_kube_config()
crd_api = client.CustomObjectsApi()
all_runs = crd_api.list_cluster_custom_object(
group="argoproj.io",
version="v1alpha1",
plural="analysisruns"
)
status_counter = Counter()
failed_details = []
for run in all_runs.get("items", []):
name = run["metadata"]["name"]
ns = run["metadata"]["namespace"]
status = run.get("status", {}).get("phase", "Unknown")
status_counter[status] += 1
if status == "Failed":
metrics = run.get("status", {}).get("metricResults", [])
for m in metrics:
if m.get("phase") == "Failed":
failed_details.append(
f" ✗ {ns}/{name} -> metric '{m.get('name')}' "
f"failed (measured={m.get('measurements', [{}])[-1].get('value', 'N/A')})"
)
print("=" * 60)
print("AnalysisRun Status Summary")
print("=" * 60)
for status, count in status_counter.most_common():
print(f" {status:12s}: {count}")
if failed_details:
print("nFailed Analysis Details:")
for line in failed_details:
print(line)
else:
print("nNo failed analysis runs detected.")
if __name__ == "__main__":
main()
运行后输出示例:
$ python3 check_analysis_runs.py
============================================================
AnalysisRun Status Summary
============================================================
Successful : 8
Running : 2
Failed : 1
Failed Analysis Details:
✗ demo-app/demo-app-canary-metrics-analysis -> metric 'success-rate' failed (measured=0.82)
常见问题
Q1:AnalysisTemplate 一直显示 Running 不收敛怎么办?
最常见原因是 PromQL 查询没有返回任何数据。Prometheus 在目标 Service 刚启动时可能还没有足够样本(rate() 需要至少两个采样点)。解决方法:
- 在 Rollout 前加
pause: { duration: 2m }步骤,让指标先积累。 - 将
interval调大(如 60s),给采样窗口更多时间。 - 使用
failureLimit容忍初始几次失败。
Q2:successCondition 报错 “no result returned”
当 PromQL 返回空向量(如标签不匹配)时,result 数组为空,result[0] 会越界。在表达式里加默认值兜底:
# 使用 promql 的 or 向量逻辑提供默认值
query: |
(sum(rate(http_requests_total{service="{{args.service-name}}",code=~"2.."}[2m]))
/ sum(rate(http_requests_total{service="{{args.service-name}}"}[2m])))
or vector(1)
# vector(1) 确保无数据时返回 1(100% 成功),避免误判
Q3:自动回滚太快,想先告警再回滚
可以在 AnalysisTemplate 里用 consecutiveSuccessLimit 替代 count,要求连续 N 次成功才算通过,避免单次抖动导致假阳性。同时把 failureLimit 设为 1,配合 Alertmanager 告警规则,实现”告警先行、回滚兜底”的温和策略。
Q4:ClusterAnalysisTemplate 修改后不生效?
ClusterAnalysisTemplate 的修改只影响后续新创建的 AnalysisRun,已存在的 AnalysisRun 不会重新执行。需要重新触发 Rollout(如更新镜像 tag)才会生成新的 AnalysisRun 使用最新模板。
总结
今天我们掌握了 Argo Rollouts 最具生产价值的能力——AnalysisTemplate 指标分析与自动回滚。核心要点回顾:
- AnalysisTemplate 定义成功/失败条件与 Prometheus 查询,AnalysisRun 在发布时实例化执行。
- 三种集成模式:后台分析、内联分析、步骤级分析,覆盖从宽松到严格的各类场景。
- 多指标联合监控(错误率、延迟、资源)+ 差异化
failureLimit,兼顾安全性与抗抖动能力。 - ClusterAnalysisTemplate 实现跨团队模板复用,降低运维成本。
- PromQL 空结果兜底、连续成功限制等技巧,让自动回滚在生产环境稳定可靠。
当发布系统能够”自己判断是否健康、自己决定是否回滚”时,运维团队的夜间值班压力将大幅降低,这正是 GitOps + 渐进式交付的终极价值。
下期预告
明天我们将迎来第 17 天:全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程。这一篇会把前 16 天搭建的所有组件串联成一条完整的发布管道,从开发者 git push 代码开始,到 GitLab CI 构建、SonarQube 检查、Harbor 推送、Argo CD 同步、Argo Rollouts 灰度、Prometheus 监控、Alertmanager 告警的全流程实演,敬请期待。
系列大纲
- 全链路架构总览:从代码提交到灰度发布的完整管道设计
- K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
- Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
- GitLab CE 自托管部署:代码仓库与项目管理平台
- GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
- GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
- Harbor 镜像版本管理与 Tag 策略配置
- Argo CD 部署与 GitOps 配置仓库创建
- CI 与 CD 联动:从代码提交到部署的全自动闭环
- SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成
- Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
- Grafana 看板搭建:K8s 标准面板与自定义业务看板
- 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
- Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
- 金丝雀发布实战:setWeight 流量分割与 pause 步骤
- AnalysisTemplate 指标分析与自动回滚机制(今天)
- 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
- 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
- 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

















暂无评论内容