Nginx Ingress 实现灰度需主/灰度两个 Ingress 共享 host/path,Go 服务仅透传 header(如 x-env)并统一注入下游调用,不可在 Go 层路由;canary-weight 与 canary-by-header 互斥,多级灰度需服务内二次判断,且全链路必须透传灰度标识。

Go 服务本身不直接参与 Nginx 的流量调度逻辑,灰度规则必须落在反向代理层(Nginx 或 Nginx Ingress Controller),Go 框架只需配合透传/识别关键标识即可。强行在 Go 层做路由决策会破坏分层职责,也绕过 Ingress 的可观测性与统一管控能力。
nginx.ingress.kubernetes.io/canary 注解必须成对出现
单独给一个 Ingress 加 nginx.ingress.kubernetes.io/canary: "true" 不生效。它必须和「主 Ingress」共存于同一 Host,并指向不同 Service:一个对应稳定版 Deployment,一个对应灰度版 Deployment。
- 主
Ingress不带 canary 注解,定义默认路由(如service: app-v1) - 灰度
Ingress必须带nginx.ingress.kubernetes.io/canary: "true",且只定义 canary 规则(如nginx.ingress.kubernetes.io/canary-by-header: "x-env"、nginx.ingress.kubernetes.io/canary-weight: "10"),不能重复定义rules或host - 两个
Ingress的host和path必须完全一致,否则 Nginx Ingress Controller 无法合并为一条路由规则
Go 服务需透传 x-forwarded-for 和自定义 header
Nginx Ingress 默认不转发原始请求头,x-env 或 cookie 等灰度标识若未显式透传,Go 服务收不到,后续链路(如 RPC 调用)也无法延续灰度上下文。
- 在
Ingress的 annotation 中加:nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header x-env $http_x_env; proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for; - Go 框架里别直接读
r.RemoteAddr判断来源 IP,应优先解析r.Header.Get("X-Forwarded-For")(注意多级代理时取第一个非内网 IP) - 如果用 Gin,建议封装中间件统一提取
x-env或cookie并写入c.Request.Context(),供下游业务逻辑判断
权重策略(canary-weight)和 header 策略(canary-by-header)互斥
同一个灰度 Ingress 中不能同时设置 nginx.ingress.kubernetes.io/canary-weight 和 nginx.ingress.kubernetes.io/canary-by-header,Nginx Ingress Controller 会忽略后者或报错。
立即学习“go语言免费学习笔记(深入)”;
- 需要“固定比例 + 特定用户强打灰度”时,用两级规则:先按
canary-weight: "5"分 5% 流量进灰度环境;再在 Go 服务内部检查x-env == "gray",命中则继续走灰度链路,否则 fallback 到稳定逻辑 -
canary-by-header: "x-env"的值必须是always或never才触发硬路由;若想用任意值(如gray/prod),得改用canary-by-header-value注解(v1.3+ 支持) - 旧版本 controller(如 0.30)不支持
canary-by-header-value,此时只能靠 Go 服务自己解析 header 做二次分发,但要注意这已脱离 Ingress 管控范围
灰度流量无法跨服务延续的常见盲区
Ingress 灰度只控制「入口流量」,Go 服务调用下游其他服务时,默认不会携带灰度标识,导致链路断开——比如用户被路由到灰度版 API,但该 API 调用的订单服务仍是稳定版。
- 必须在 Go 服务发起 HTTP 请求前,手动把
x-env注入到 outbound request header 中(例如用req.Header.Set("x-env", env)) - 如果下游是 gRPC,需通过
metadata.MD透传,且接收方要主动从 metadata 提取并向下继续传递 - 不要依赖 cookie 自动携带:浏览器 cookie 不会随服务间 HTTP 调用发送,那是客户端行为
- 最稳妥的方式是所有服务统一从
X-Env或X-Canaryheader 读取,并在出向调用中强制透传,形成闭环


















