Flagger 自动金丝雀、指标门禁与退出治理手册
catalog Deployment 的镜像 digest 已由 Flux 更新,Flagger 创建的 canary Pod 也全部 Ready,但发布两个小时仍没有 promotion。事件里反复出现“new revision detected”:自动轮换的 ConfigMap 每隔几分钟变化一次,而 Flagger 正在跟踪并复制它,每次变化都会重启 analysis。系统没有坏在流量切分,而是 GitOps 更新频率与发布状态机的稳定窗口彼此冲突。
另一场发布在面板上保持 100% success rate,实际却没有一个请求进入 canary。Gateway API 的 HTTPRoute 已被 API Server 接受,目标 GatewayClass 不支持使用中的 filter,Prometheus 查询又没有匹配到 revision 标签。空样本被当成健康,最终把没有经过验证的版本复制成 primary。Flagger 的自动化价值来自每轮证据都可信,而不是来自“无人点击按钮”。
安装时先选 provider,再固定控制器与 CRD
Flagger 观察 Canary.spec.targetRef 指向的 Deployment 或 DaemonSet,生成 primary 工作负载、Service、HPA/config 副本和 provider-specific 路由。它不是 service mesh、ingress controller、Gateway API implementation 或指标平台;安装前必须确认目标数据面能提供需要的策略和遥测,并决定全局 meshProvider、metricsServer 以及少数 Canary 的 spec.provider 覆盖关系。
生产安装应固定 Flagger controller、Helm chart/OCI artifact、CRD、provider、Kubernetes、Gateway API 或 mesh 版本及镜像 digest,并验证签名。Flux 的示例可能使用宽泛 semver,适合展示持续更新,不适合受控变更窗口。CRD schema 与 controller 是一个兼容单元,先在隔离集群渲染 chart、审查 cluster-scoped RBAC 和 CRD diff,再提交生产仓库。
下面以 Flux 管理 OCI chart 为入口,版本与 digest 占位符必须换成审批后的值。CreateReplace 允许 Helm controller 更新 CRD,但也意味着 CRD 变化会进入自动调谐,需要和 controller 升级一起验证:
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: flagger
namespace: flux-system
spec:
interval: 1h
url: oci://ghcr.io/fluxcd/charts/flagger
ref:
tag: <PINNED_VERSION>
verify:
provider: cosign
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: flagger
namespace: flux-system
spec:
interval: 30m
chartRef:
kind: OCIRepository
name: flagger
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
values:
meshProvider: gatewayapi:v1
metricsServer: https://prometheus.monitoring.svc:9090
leaderElection:
enabled: true
replicaCount: 2controller 的 watch namespace、ServiceAccount 权限、GatewayClass/route class 和 provider override 要共同收窄管理面。同一集群并存 Istio、NGINX 与 Gateway API 时,不能仅靠相同 Service 名猜测归属。安装完成先验证 CRD、Deployment args、leader election 与 provider 连接,不创建业务 Canary 就直接宣布系统可用。
Canary 怎样把 Deployment 变成两套工作负载
对于 Deployment target,Flagger 创建 <target>-primary 作为稳定版本,原 Deployment 作为 canary;稳态时 target 通常缩到 0。默认还会创建 apex <service>、<service>-primary 和 <service>-canary 三个 ClusterIP Service:apex 对外提供稳定入口,后两个给路由器区分后端。若 target 引用 HPA,Flagger 会派生 primary HPA;被跟踪的 ConfigMap/Secret 也可能复制为 -primary 并改写 primary 引用。Secret 副本仍是 Kubernetes 明文对象,复制会扩大对象数量、备份面和可读主体,不能把“由 Flagger 自动生成”误认为加密或隔离;关闭 tracking 又会改变新 revision 触发与回退语义,必须用轮换实验选择。
初始化后的第一件事不是改镜像,而是保存对象图和 owner:
kubectl get canary -A
kubectl describe canary catalog -n delivery
kubectl get deploy,rs,pod,svc,hpa,configmap -n delivery -l app=catalog -o wide
kubectl get httproute,virtualservice,destinationrule -n delivery -o yaml
kubectl get events -n delivery --sort-by=.lastTimestamptarget selector 必须符合 Flagger 支持的标签约定,不能假设复杂 selector 会被安全推导。Canary.spec.service 决定生成 Service 的端口、selector 和 metadata;未声明的 annotation/label 可能在 reconcile 时被移除,需要通过 unmanagedMetadata 明确保留。Flux、Helm、其他 Operator 与人工脚本不得同时管理生成资源或同一字段。
状态证据要同时读取 Canary conditions、lastAppliedSpec/lastPromotedSpec、primary/target PodSpec、两组 endpoints、route backend 和真实请求版本。Initialized、Progressing、Promoted 或 Failed 描述的是 Flagger 状态机,不是业务 SLO 的替代品。
自动 Canary 循环如何推进和重新开始
新 revision 可以由 target PodSpec、被跟踪的 ConfigMap 或 Secret 变化触发。Flagger 扩容 canary,运行 pre-rollout/rollout webhook,每个 analysis.interval 查询 metrics;当前轮成功后按 stepWeight 增加流量,直到 maxWeight,再把候选配置复制到 primary 并把流量归回 primary。累计失败达到 threshold 时,流量回到 primary、canary 缩到 0、Canary 标记 Failed。
一个可审查的最小对象如下。threshold 是允许累计失败检查的次数,不是 3% 错误率;最长发布时间还受到 interval、weight 阶梯、webhook 超时、指标窗口和 promotion 等待影响:
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: catalog
namespace: delivery
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: catalog
provider: gatewayapi:v1
service:
port: 80
targetPort: http
gatewayRefs:
- name: public-gateway
namespace: ingress
analysis:
interval: 1m
threshold: 3
maxWeight: 30
stepWeight: 10
stepWeightPromotion: 20
metrics:
- name: request-volume
templateRef: { name: catalog-request-volume }
thresholdRange: { min: 200 }
interval: 1m
- name: request-success-rate
thresholdRange: { min: 99.5 }
interval: 1m
- name: request-duration
thresholdRange: { max: 0.5 }
interval: 1m分析期间 target 再次变化会重启流程。这能避免混合两个 revision 的测量,却会让高频 Git 提交、镜像机器人或 Secret 轮换制造永不完成的发布。应把同一兼容单元合并为一次 revision,冻结 active analysis 期间的自动更新,或为密钥轮换选择不触发 PodSpec/hash 的设计;不能通过无限增大超时掩盖输入持续变化。
stepWeightPromotion 能把流量从 canary 渐进迁向已经更新的 primary,减少 promotion 阶段瞬时切换,但 primary rollout、readiness、HPA 和 route 收敛仍要分别验证。最终 apex 指回 primary,并不说明所有长连接已经排空或旁路入口也已切换。
A/B、blue-green 与 mirror 不是同一种灰度
A/B 通过 Header 或 Cookie 把特定用户定向到 canary,需要 provider 明确支持匹配能力,也需要稳定、不可伪造且不含敏感信息的分群键。正向实验要证明命中与不命中请求分别进入候选和稳定版本;反向实验要覆盖缺失键、错误值、缓存和会话亲和,不能用一次带 Header 的 curl 证明分群可靠。
Flagger 的 blue-green 使用 iterations 运行候选测试与指标,成功后先把 live traffic 切到 canary,再把 promoted spec 复制到 primary,等待 primary Ready 后把流量切回 primary并缩 canary。Kubernetes provider 可通过 Service selector 做 0/100 切换,不依赖 L7 router;它不能提供普通 canary 的精细权重或 A/B。
Traffic mirroring 将请求副本发送到 canary,并丢弃 canary response。它不是无副作用的只读观察:POST 可能产生双写、消息、邮件、库存扣减、计费和审计污染。只有在候选路径使用隔离存储、合成身份或业务幂等与抑制开关时才能启用;还要确认 Gateway implementation 对 body、流式请求、超时和 mirror percentage 的具体语义。
副本比例始终不是流量权重。一个 canary Pod 可被路由 30% 请求,三个 canary Pod 也可能只接收 Header 定向用户;反过来,未经过目标 Gateway 的内部请求完全不受该权重控制。容量门禁应把路由权重、两侧副本、单 Pod QPS、HPA lag、连接类型与真实版本响应放在同一份观测中。
MetricTemplate 要把无样本作为显式状态
内置 request success rate 和 duration 依赖各 provider 的 Prometheus 查询与标签约定。应用没有暴露对应指标、route 没有产生遥测、revision label 不匹配或流量太低时,内置指标不会自动成为可信 SLO。自定义 MetricTemplate 应让查询返回单个可解释数值,并用独立的请求量门禁阻止零样本晋级。
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: catalog-request-volume
namespace: delivery
spec:
provider:
type: prometheus
address: https://prometheus.monitoring.svc:9090
secretRef:
name: flagger-prometheus-auth
query: |
sum(increase(http_requests_total{
namespace="{{ namespace }}",
service="{{ target }}-canary"
}[{{ interval }}]))正向实验先产生超过最小样本量的合成请求,让请求量、成功率与 P95/P99 延迟连续满足多个窗口;反向实验分别注入业务 5xx、依赖慢响应、空标签、Prometheus 401 和超时。业务阈值越界、provider 调用失败、查询无数据与人工确认等待应生成不同事件和告警,不能都压成“自动回滚”。观测后端不可用时应暂停或失败关闭,而不是把空值转换为 0 错误。
insecureSkipVerify 会关闭 provider TLS 校验,只适合一次性隔离实验。生产使用受信 CA、最小 Token/IAM、明确 tenant header 和受限网络出口。MetricTemplate 查询本身就是发布代码,应纳入版本评审、语法测试和合成序列测试;Secret、查询响应、Webhook body 和事件日志都要检查脱敏。
Webhook 把测试与人工门禁接进状态机
Flagger webhook 包括 confirm-rollout、pre-rollout、rollout、confirm-traffic-increase、confirm-promotion、post-rollout、rollback 与 event。HTTP 2xx 通常表示成功,所以 endpoint 身份、TLS、鉴权、超时、重试与幂等直接决定发布安全。load tester 只是一个可选 webhook 服务,不是 controller 内置流量源;测试命令同样可能制造生产写入与容量尖峰。
confirm 类 hook 未通过时会暂停等待,期间 metrics 与 rollout hooks 仍可继续执行,以防等待审批时候选版本已经恶化。rollback hook 成功会停止 analysis、切回 primary 并标记失败;post-rollout hook 失败只记录错误,不会撤销已经完成的 promotion。设计告警时必须保留这些差异。
Flagger 没有与 Argo Rollouts 完全对称的 promote/abort/undo CLI。人工批准通过 confirmation webhook,主动回退通过 rollback webhook,suspend: true 暂停完整 reconciliation,skipAnalysis: true 则会在健康检查后直接 promotion,甚至可取消正在运行的 analysis。skipAnalysis 不是“先停一下”,而是高风险 break-glass 字段,必须限制 Git/RBAC 修改权限并双人审批。
Gateway、mesh 与 ingress 必须逐实现验证
Flagger 可面向 Istio、NGINX、Kuma、Gateway API 等 provider 生成或维护路由资源,但不同 provider 对 A/B、blue-green、mirror、session affinity 和 filter 的支持集合不同。Gateway API provider 即使生成合法 HTTPRoute,也要查看 GatewayClass 对 weight、Header/Cookie、mirror、rewrite、CORS 等能力的 conformance。
发布门禁至少读取 HTTPRoute 的 Accepted、ResolvedRefs 和实现特定 condition,再检查网关数据面装载的配置以及真实请求分布。CRD schema 接受某个 filter,只证明 YAML 合法;route status 正常,也不能证明连接池、缓存、长连接和旁路流量按预期切换。Istio 同理,需要核对 VirtualService/DestinationRule、代理配置 ACK 和版本指标。
动态 backend weight、filter 和生成 Service 是 Flagger 写入面。Flux、Argo CD 或 Helm 应从管理清单中移除这些派生对象,或只保留 Canary spec 作为生成源;若必须共享 route 骨架,则对动态字段做精确 ignore,不能忽略整份对象。多入口场景要逐个验证并设置停止条件,避免公网已回退而内部 Gateway 仍把流量送往失败版本。
Flux 负责 desired state,Flagger 负责集群内 promotion
Flux 可以安装 Flagger,也可以把 Deployment、Canary、MetricTemplate 和 Secret 引用调谐到集群。Flagger 观察 target 变化,执行集群内分析、流量切分、primary promotion 和失败回退。两者相邻但责任不同:Flux 不应持续覆盖 Flagger 生成的 primary、Service 和 route 动态字段;Flagger 也不会自动把失败镜像写回 Git。
一次回退后,live traffic 已恢复到 last promoted primary,Git 中 target manifest 仍可能是失败 revision。下一次 target 变化又会触发 analysis。团队需要选择修复并 roll-forward,或由独立、有审计的自动化提交 desired rollback;不能因为 primary 当前正常就宣称 GitOps 已经闭环。
字段所有权矩阵至少包含 target PodSpec、target/primary replicas、HPA、三类 Service selector、tracked ConfigMap/Secret、HTTPRoute/VirtualService 和 Canary spec/status。CI 只生产不可变镜像与验证结果,Flux 写评审后的 desired manifest,Flagger 写发布过程动态对象,HPA 写 scale。任何人工紧急 patch 都应有到 Git 的回写或明确的到期清理。
Promote 与 rollback 的真正边界在业务状态
Flagger 的 promotion 把候选 spec 复制到 primary,并最终让 apex 流量回到 primary;rollback 则恢复到最后一次 promoted primary。它们能恢复 controller 管理的 Pod、Service 与 route,不能撤销数据库迁移、已发送消息、缓存格式、第三方调用或 mirror 造成的副作用。
新旧版本同时存在时,schema、事件、session、feature flag 和外部 API 必须覆盖完整分析与快速回退窗口。队列消费者、CronJob、数据库 migration Job 和单 leader 任务也不能照搬 HTTP 权重;它们需要任务分片、影子消费、显式 leader 切换或独立迁移门禁。
回退完成后要检查 primary/target replicas、三个 Service endpoints、所有 route backend、Canary condition、provider 恢复和真实业务请求。failed Canary 的 target 仍可能保留新 desired revision,因此还要检查 Flux reconciliation 与 Git diff。只有 live 与 desired 都进入明确后续路径,外部副作用已补偿或确认兼容,才算关闭故障。
HA、容量、凭证与成本一起治理
多副本 Flagger 必须同时启用 leader election;只有 leader reconcile,其他副本用于接管,不会分摊 Canary 吞吐。生产应配置 topology spread/anti-affinity、PDB、requests/limits 和 health probe,并观测 election、reconcile duration/error、provider latency、API throttling 与各 Canary phase。杀 leader 的反向实验要记录 active weight 停留时间和新 leader 接管后的首次成功 reconcile。
HA 仍依赖指标后端、Webhook、mesh/gateway controller、API Server 和 stable capacity。等待人工确认时 metrics 与 load test 继续运行,会持续产生查询、流量与日志成本;低流量应用可能长期保留双份副本,高基数 revision 标签又会扩大 Prometheus 和 Trace 存储。为每个 Canary 设置最长运行时间、最小样本、合成流量预算、历史保留与告警升级路径。
controller 可修改 Deployment、Service、HPA、Route,并可能读取 provider Secret 和被跟踪 Secret,权限很高。按 namespace 收窄 watch/RBAC,provider 使用短期 workload identity 或最小 Token,Webhook 采用 mTLS/OIDC 和出口白名单。跨集群 Istio 等拓扑若需要 remote kubeconfig,该 Secret 是跨集群控制凭据,必须单独轮换、审计和撤销。
升级与卸载要先解除每个 Canary 的所有权
升级前停止浮动 semver,冻结 target revision,导出 Canary status、lastAppliedSpec/lastPromotedSpec、primary/target replicas、Service selector、route weight、HPA 和 tracked config hash。某些版本的 hash 或 CRD 变化可能让全部 Canary 被识别为新 revision;必须阅读目标 release notes,并在隔离 namespace 验证 no-op 升级不会批量触发发布。active analysis 中停止 leader 会让流量停在当前权重,接管窗口应短于业务容忍时间。
卸载 HelmRelease 不等于应用退出。稳健顺序是先冻结更新,为每个 Canary 设置 revertOnDeletion: true 并等待一次成功 reconcile;随后逐个删除 Canary,让 finalizer 尝试把 target replicas、Service selector 和路由恢复到不依赖 Flagger 的状态。这个恢复不是跨工作负载、Service 与数据面的原子事务:provider 不可达、权限被提前撤销或 target 已被其他控制器改写,都可能留下中间态。必须用对象差异、endpoints、route status 和真实请求证明恢复完成,再清理已核实归 Flagger 所有的 primary Deployment/HPA、canary Service、配置副本和 route。
最后才由 Flux 删除 HelmRelease/controller,撤销 ServiceAccount、provider/Webhook/remote-cluster credential 与网络入口。Helm uninstall 不会自动删除 Canary CRD;直接删除 CRD 会级联删除 Flagger-owned Deployment、Service、VirtualService 等对象,可能瞬间切断流量。只有所有 Canary、finalizer 和派生资源清零,target 与 Git desired 一致、真实请求稳定且闲置容量和遥测费用已核销后,才能删除 CRD。
