跳到主要内容

使用 Flagger 自动执行金丝雀发布

Flagger 可以自动分析 Kubernetes Deployment 的金丝雀版本。它会协调候选版本和主版本、加权路由、测试流量、指标以及提升或回滚。

本指南配置的金丝雀发布每次增加 10% 流量,最高达到 30%;要求请求成功率为 99%,最大请求耗时为 500 毫秒。请选择使用 HTTPRoute 的 Gateway API 提供方,或使用 ApisixRoute 的 APISIX 提供方,并在整篇指南中保持一致。

Gateway API 集成成熟度

Gateway API 将 Flagger 集成列为公开预览阶段。采用 Gateway API 路径前,请在非生产集群中验证具体的控制器、网关和 Flagger 版本,以及初始化、提升和回滚行为。

了解 Flagger 管理的资源

对于名为 podinfo 的目标 Deployment,Flagger 会管理以下资源:

资源用途
podinfo Deployment源 Pod 模板;Flagger 初始化后会将其缩容,并用于候选版本
podinfo-primary Deployment最近一次成功提升的 Pod 模板
podinfopodinfo-primarypodinfo-canary Service分别作为公共、稳定版和金丝雀 Service
生成的 HTTPRouteApisixRoute由 Flagger 控制稳定版和金丝雀权重

不要把生成的资源加入其他 Helm Release、Kustomize Base 或 GitOps 应用。请继续修改源 Deployment;Flagger 会把成功的变更复制到主 Deployment。

提供方决定 Flagger 如何构建发布 Route:

  • 使用 gatewayapi:v1 时,Flagger 根据 Canary 中的主机名和 Gateway 引用生成名为 podinfoHTTPRoute
  • 使用 apisix 时,Flagger 把源 ApisixRoute 复制为名为 podinfo-podinfo-canary 的生成 Route。

前提条件

  • 完成设置 Ingress Controller 和网关
  • 安装 Helmkubectl
  • 确保网关能够访问应用命名空间中的 Service。
  • 使用 HTTPRoute 时,创建一个状态为 Programmed=TrueGateway,其监听器允许应用命名空间中的 Route。
  • 使用 ApisixRoute 时,确保能够安全修改集群范围的默认 IngressClass
  • 使用已公开 APISIX Prometheus 指标的 APISIX 网关或 API7 Gateway。

以下命令使用 Flagger Chart 1.44.0 和负载测试器 Chart 0.38.0。如果使用更新版本,请先查看发布说明并验证兼容性。

公开 APISIX 指标

分析会查询 apisix_http_statusapisix_http_latency_bucket。稍后安装的 Prometheus 服务器通过标准抓取注解发现网关 Pod。

如果使用 Chart 2.16.0 安装 APISIX,请把以下配置添加到网关 Release Values 中:

apisix-values.yaml
apisix:
prometheus:
enabled: true

podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9091"
prometheus.io/path: /apisix/prometheus/metrics

对于 API7 Gateway Chart 3.10.11,请改为添加以下配置:

api7-gateway-values.yaml
pluginAttrs:
prometheus:
enable_export_server: true
export_addr:
ip: 0.0.0.0
port: 9091

apisix:
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9091"
prometheus.io/path: /apisix/prometheus/metrics

显式配置 API7 导出地址后,Prometheus Pod 能够访问该端点,而不再局限于网关 Pod 内部。请通过负责网关 Release 的 Helm 或 GitOps 工作流应用这些配置。不要对 GitOps 管理的 Release 单独运行 helm upgrade

如果使用其他 Chart 版本或 APISIX 软件包,请在应用前确认 Prometheus 属性和 Pod 注解的 Values 路径。不同 Chart 的 Values 路径并不通用。

验证网关 Pod 注解:

kubectl get pods --namespace <gateway-namespace> \
--selector <gateway-pod-label-selector> \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.prometheus\.io/scrape}{"\t"}{.metadata.annotations.prometheus\.io/port}{"\n"}{end}'

对于上述 Chart 版本,APISIX 使用 app.kubernetes.io/name=apisix,API7 Gateway 使用 app.kubernetes.io/name=gateway

从网关 Pod 转发指标端口,并确认指标可用:

kubectl port-forward pod/<gateway-pod> \
9091:9091 \
--namespace <gateway-namespace>

如果网关 Chart 公开了指标 Service,也可以改为转发 Service 端口:

kubectl port-forward service/<gateway-metrics-service> \
9091:9091 \
--namespace <gateway-namespace>

在另一个终端中:

curl "http://127.0.0.1:9091/apisix/prometheus/metrics"

只有当端点返回 Prometheus 文本指标后,才能继续。

安装 Flagger 和 Prometheus

添加仓库:

helm repo add flagger https://flagger.app
helm repo update

选择安装的默认提供方。本指南中的每个 Canary 都会设置 spec.provider 并覆盖 meshProvider,因此一个 Flagger 控制器可以协调两种提供方。只有需要独立的命名空间范围或运维隔离时,才使用多个安装。

helm upgrade --install flagger flagger/flagger \
--version 1.44.0 \
--namespace flagger-system \
--create-namespace \
--set meshProvider=gatewayapi:v1 \
--set prometheus.install=true

该 Chart 从 crds 目录安装 CRD。使用 Helm 3 时不要设置 crd.create=true;这个旧版 Helm 2 选项会把相同 CRD 作为 Helm 模板再次渲染。

等待两个 Deployment 就绪:

kubectl rollout status deployment/flagger \
--namespace flagger-system \
--timeout 2m

kubectl rollout status deployment/flagger-prometheus \
--namespace flagger-system \
--timeout 2m

确认 Flagger 可以查询 Prometheus:

kubectl logs deployment/flagger --namespace flagger-system | \
grep 'all the metrics providers are available'

配置 Route 提供方

Gateway API 未定义 APISIX 插件配置,且生成的 HTTPRoute 由 Flagger 管理。请通过 Route 的 GatewayProxy 启用 Prometheus 插件,把以下条目添加到现有 spec.plugins 列表:

gateway-proxy.yaml
spec:
plugins:
- name: prometheus
enabled: true
config:
disable: false
prefer_name: true

这会为与该 GatewayProxy 关联的 Route 全局启用 Prometheus 指标。应用到共享生产网关前,请评估指标基数和公开范围的影响。

通过负责该资源的工作流应用更新后的 GatewayProxy,然后验证普通网关请求会生成 apisix_http_status 样本。prefer_name 配置会生成本指南指标模板所选择的 Route 标签。

部署示例应用

创建 podinfo-deployment.yaml

podinfo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
namespace: flagger-demo
spec:
minReadySeconds: 5
progressDeadlineSeconds: 120
selector:
matchLabels:
app: podinfo
template:
metadata:
labels:
app: podinfo
spec:
containers:
- name: podinfo
image: ghcr.io/stefanprodan/podinfo:6.14.0
ports:
- name: http
containerPort: 9898
readinessProbe:
httpGet:
path: /readyz
port: http
resources:
requests:
cpu: 10m
memory: 32Mi

创建命名空间并应用 Deployment:

kubectl create namespace flagger-demo
kubectl apply -f podinfo-deployment.yaml

如果 Gateway 监听器按标签选择命名空间,请先向 flagger-demo 添加所需标签。生产发布策略应使用不可变镜像摘要。版本标签能让教程更易读,但可变标签无法证明评估的是哪个制品。

安装负载测试器

负载测试器会在整个分析期间执行 Flagger Webhook 中的命令。请将其安装到应用命名空间:

helm upgrade --install flagger-loadtester flagger/loadtester \
--version 0.38.0 \
--namespace flagger-demo

kubectl rollout status deployment/flagger-loadtester \
--namespace flagger-demo \
--timeout 2m

生产环境应使用有代表性的流量或经过审查的测试命令。请确认负载测试不会修改数据、压垮依赖或绕过正常授权。

配置路由和指标

不要创建源 HTTPRoute。Flagger 会根据 Canary 中的主机名和 gatewayRefs 生成该资源。

Gateway API 提供方内置的 HTTP 观察器不会查询 APISIX 网关指标。将以下 APISIX 专用查询保存为 apisix-metric-templates.yaml

apisix-metric-templates.yaml
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: apisix-request-success-rate
namespace: flagger-system
spec:
provider:
type: prometheus
address: http://flagger-prometheus.flagger-system:9090
query: |
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ target }}_.+",
code!~"5.."
}[{{ interval }}]
)
)
/
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ target }}_.+"
}[{{ interval }}]
)
) * 100
---
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: apisix-request-duration
namespace: flagger-system
spec:
provider:
type: prometheus
address: http://flagger-prometheus.flagger-system:9090
query: |
histogram_quantile(
0.99,
sum(
rate(
apisix_http_latency_bucket{
type="request",
route=~"{{ namespace }}_{{ target }}_.+"
}[{{ interval }}]
)
) by (le)
)

应用模板:

kubectl apply -f apisix-metric-templates.yaml

该模板会选择生成的 Route 标签,例如 flagger-demo_podinfo_0-0。如果你的标签不同,请检查实时 apisix_http_status 样本,并在开始发布前把表达式限定到生成的 Route。

创建金丝雀策略

把所选 Route API 对应的策略保存为 podinfo-canary.yaml。请根据环境替换主机和网关 Service 地址。

请把 gatewayRefs 的名称和命名空间替换为应接收生成 Route、且状态为 Programmed=TrueGateway

podinfo-canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
namespace: flagger-demo
spec:
provider: gatewayapi:v1
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
progressDeadlineSeconds: 120
service:
port: 80
targetPort: http
hosts:
- podinfo.example.com
gatewayRefs:
- name: <gateway-name>
namespace: <gateway-namespace>
analysis:
interval: 30s
threshold: 5
maxWeight: 30
stepWeight: 10
metrics:
- name: apisix-success-rate
templateRef:
name: apisix-request-success-rate
namespace: flagger-system
thresholdRange:
min: 99
interval: 1m
- name: apisix-request-duration-p99
templateRef:
name: apisix-request-duration
namespace: flagger-system
thresholdRange:
max: 500
interval: 1m
webhooks:
- name: smoke-test
type: pre-rollout
url: http://flagger-loadtester.flagger-demo/
timeout: 5s
metadata:
type: bash
cmd: >-
curl -fsS -d anon
http://podinfo-canary.flagger-demo/token | grep token
- name: load-test
type: rollout
url: http://flagger-loadtester.flagger-demo/
timeout: 5s
metadata:
cmd: >-
hey -z 2m -q 20 -c 2 -host podinfo.example.com
http://<gateway-service>.<gateway-namespace>/

自定义分析名称有意避开 Flagger 保留名称 request-success-raterequest-duration。使用任一保留名称时,都会在引用的 APISIX 模板之前调用 Gateway API 提供方的通用内置观察器,可能产生误导性的 no values found 失败。

示例使用较短间隔和五次失败检查,使行为容易观察,同时为 Prometheus 收集第一批样本留出时间。生产配置应考虑正常流量、指标延迟、应用预热和误回滚成本。

应用策略:

kubectl apply -f podinfo-canary.yaml

验证初始化

等待 Canary 阶段变为 Initialized

kubectl get canary podinfo --namespace flagger-demo --watch

检查生成的 Route。

kubectl get httproute podinfo \
--namespace flagger-demo \
-o yaml

Route 应包含权重为 100podinfo-primary 和权重为 0podinfo-canary。只有当它针对当前 generation 报告 Accepted=TrueResolvedRefs=True 时,才能继续。

发布新版本前,验证 Prometheus 已有生成 Route 的样本:

kubectl port-forward service/flagger-prometheus \
9090:9090 \
--namespace flagger-system

在另一个终端中:

curl -G "http://127.0.0.1:9090/api/v1/query" \
--data-urlencode 'query=count by (route) (apisix_http_status)'

如果 Route 尚未收到流量,请先通过负载测试 Webhook 使用的同一网关主机和路径发送请求。

自动提升版本

更新源 Deployment:

kubectl set image deployment/podinfo \
podinfo=ghcr.io/stefanprodan/podinfo:6.14.1 \
--namespace flagger-demo

观察 Canary:

watch kubectl get canary podinfo --namespace flagger-demo

在另一个终端中,使用适合所选 Route 类型的命令观察生成 Route 的权重:

ApisixRoute
watch kubectl get apisixroute podinfo-podinfo-canary \
--namespace flagger-demo \
-o jsonpath='{range .spec.http[0].backends[*]}{.serviceName}={.weight}{" "}{end}{"\n"}'

对于 HTTPRoute,改为观察后端引用:

HTTPRoute
watch kubectl get httproute podinfo \
--namespace flagger-demo \
-o jsonpath='{range .spec.rules[0].backendRefs[*]}{.name}={.weight}{" "}{end}{"\n"}'

指标检查通过时,Flagger 应依次把权重推进到 10、20 和 30。随后它会把金丝雀 Pod 模板复制到 podinfo-primary,将路由恢复为 100/0,并把 Canary 标记为 Succeeded

验证已提升的镜像:

kubectl get deployment podinfo-primary \
--namespace flagger-demo \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'

验证自动回滚

在生产环境依赖回滚策略之前,请先在安全环境中测试。触发另一个候选版本,等待其权重大于零,然后通过同一 Route 生成 5xx 响应:

kubectl set env deployment/podinfo \
'PODINFO_UI_COLOR=#ff0000' \
--namespace flagger-demo

# 等待 kubectl get canary 报告权重大于零。
kubectl exec deployment/flagger-loadtester \
--namespace flagger-demo \
-- \
hey -z 2m -q 20 -c 2 \
-host podinfo.example.com \
http://<gateway-service>.<gateway-namespace>/status/500

观察 Flagger 事件:

kubectl describe canary podinfo --namespace flagger-demo
kubectl logs deployment/flagger --namespace flagger-system --follow

达到失败检查阈值后,Flagger 应执行以下操作:

  1. 将生成的 Route 恢复为主版本权重 100、金丝雀权重 0
  2. 缩容失败的金丝雀 Deployment。
  3. podinfo-primary 中保留先前镜像。
  4. 将 Canary 阶段标记为 Failed

回滚后,请通过网关确认应用流量。Canary 为 Failed 说明策略已经介入,但并不能单独证明所有依赖都已恢复。

设计生产分析

网关检查只是起点。请为服务专用指标添加 MetricTemplate 资源,并在适当时结合 Webhook。生产策略应考虑:

  • 计算百分比之前所需的最小请求数。
  • 查询窗口和抓取延迟。第一批样本到达前可能出现初始 no values found 事件,不能将其视为成功。
  • 相同 Route 标签下近期的失败。新发布开始时可能观察到仍处于指标查询窗口内的旧样本。
  • 低流量服务,可能需要合成流量或更长间隔。
  • 冷启动、缓存、连接池和依赖预热。
  • 仅靠网关 HTTP 状态无法发现的业务和依赖指标。
  • 针对 Failed、卡在 Progressing 以及指标提供方不可用状态的告警。
  • 高风险环境的人工批准。

失败阈值应足够低以限制影响,又要足够高以容忍预期测量延迟。用分析间隔乘以允许的失败检查次数,可以估算 Flagger 拒绝失败发布所需的最长时间。

Route 和提供方限制

对于 APISIX 提供方:

  • 生成的 Route 不会保留 spec.ingressClassName,因此需要默认 APISIX IngressClass
  • 选定的源 HTTP 规则必须恰好包含一个后端。
  • Flagger 通过其维护的 APISIX CRD 模型复制源 Route,该模型可能落后于新版 Ingress Controller 增加的字段。
  • 额外 Route 插件和复杂插件配置都应经过初始化、提升和回滚测试。Flagger issue #1388 记录了与数值型 APISIX 插件配置相关的资源冲突循环。

对于 Gateway API 提供方:

  • Flagger 生成并管理 HTTPRoute,不会接管现有 Route。
  • Route 行为必须能够通过 Flagger Canary 服务配置和受支持的 Gateway API 字段表达。
  • APISIX 专用分析需要自定义指标模板;通用 Gateway API 观察器并非 APISIX 指标集成。
  • 生成的标准 HTTPRoute 无法挂载 Route 级 Prometheus 插件,因此本指南在 GatewayProxy 范围启用该插件。

每次升级 Flagger 后都应检查生成的资源。不要假设 Canary 成功准入就代表 Route、策略和指标行为仍完全相同。

故障排查

使用以下检查定位 Route 准入、指标收集、协调或发布进度问题。

生成的 Route 未被接受

对于 ApisixRoute,检查生成的 Route 和默认 IngressClass:

kubectl get apisixroute podinfo-podinfo-canary \
--namespace flagger-demo \
-o yaml
kubectl get ingressclass -o yaml

对于 HTTPRoute,检查其父级条件,并确认 Gateway 监听器允许该 Route 命名空间:

kubectl get httproute podinfo --namespace flagger-demo -o yaml
kubectl get gateway <gateway-name> \
--namespace <gateway-namespace> \
-o yaml

Flagger 报告没有指标值

验证 Prometheus 目标、网关注解、Route 流量和 Route 标签:

kubectl port-forward service/flagger-prometheus \
9090:9090 \
--namespace flagger-system

curl -G "http://127.0.0.1:9090/api/v1/query" \
--data-urlencode 'query=apisix_http_status'

负载测试 URL 必须经过 Canary 所测量的同一 Route。直接请求 Pod 或 Service 不会生成 APISIX Route 指标。对于 HTTPRoute,还要确认自定义分析名称不是保留的内置指标名称。

Route 更新重复或冲突

检查生成的 Route 和 Flagger 日志中的重复更新。不要用 Git 或其他包管理器管理生成的 Route。对于 APISIX 提供方,可简化额外插件配置,以找出无法通过 Flagger 中 APISIX 类型往返保留的字段。不要全局禁用协调冲突处理。

提升时间超出预期

Flagger 等待 Pod 就绪、第一批指标样本、Webhook 或下一个分析间隔时可能暂停推进。请检查 Canary 事件,不要只根据 maxWeightstepWeight 估算进度。

清理

删除示例命名空间:

kubectl delete namespace flagger-demo

仅当没有其他 Canary 资源依赖 Flagger 时,才能将其删除:

helm uninstall flagger --namespace flagger-system
kubectl delete namespace flagger-system

Helm 会保留从 Chart crds 目录安装的 CRD。如果其他安装可能使用 Flagger CRD,请保留它们。只有确认不存在 CanaryMetricTemplateAlertProvider 资源后,才能单独删除。

如果选择了 ApisixRoute,只有当 APISIX 不应再作为集群默认类时,才移除默认注解:

kubectl annotate ingressclass apisix \
ingressclass.kubernetes.io/is-default-class-

如果选择了 HTTPRoute,只有当没有其他监控工作流依赖全局 Prometheus 插件时,才将其移除。

相关内容