跳转到主要内容

nginx&&nginx-ingress实现灰度发布

一、名词解释

灰度发布:又名金丝雀发布、黑白发布。18世纪时,由于科技落后,矿井没有好的通风条件和瓦斯检测工具,旷工在矿井作业时经常出现瓦斯中毒现象,因此,旷工们在下井时,会携带一只金丝雀,因为金丝雀在状态好的时候,非常喜欢叫唤,通过观察金丝雀的状态,确定矿井的毒气状态。

软件新版本发布后,我们先开放给一部分用户先体验和测试,等系统稳定运行一段时间足够稳定了再逐渐全量上线新版本,最后平滑下线旧版本。称之为灰度发布

  • 基于用户体系的灰度发布,针对一些特定的人群,为其写入特定的header或者cookie。

  • 根据流量规则,随机抽取部分人群参与灰度测试

二、该选那个呢

建议优选cookie,理由如下

  • 可以控制
  • 基于header可能更便于c/s端,因为b/s无法直接设置header

三、基于nginx-ingress的灰度发布

  • 先创建2个nginx服务

    • 服务1

    • 服务2


  • 创建2个ingress

不出意外的话,第二个会创建不成功,需要在第二个ingress加入nginx-ingress注释

# 启用灰度发布
nginx.ingress.kubernetes.io/canary: "true"

# 启用基于header的灰度规则,并指定hearder包含指定键(version),客户端传递该hearder键并将值指定为always(总是)或者never(永远不)
nginx.ingress.kubernetes.io/canary-by-header: "version"

# 指定基于hearder规则时,需要包含的值,不在局限于值为always(总是)或者never(永远不)
nginx.ingress.kubernetes.io/canary-by-header-value: "2.0"


# 启用基于cookie的灰度规则,并指定cookie包含指定键(version),客户端传递该cookie键并将值指定为always(总是)或者never(永远不)
nginx.ingress.kubernetes.io/canary-by-cookie: "version"

# 网上有部分文章描述说有类似hearder规则的nginx.ingress.kubernetes.io/canary-by-cookie-value注解指定值,实际上没有这个注解

# 基于流量规则,值为0-100之间,既按百分比,0为不接受任何请求,其最大值(100)可以由canary-weight-total定义
nginx.ingress.kubernetes.io/canary-weight:10

# 基于流量规则时候的最大值,默认为100,该设置可以忽略
nginx.ingress.kubernetes.io/canary-weight-total

# 规则优先级
# canary-by-header -> canary-by-cookie -> canary-weight

# 官方帮助
# https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#canary


三、测试一下基于header的方式的灰度发布

  • 增加ingress注解

  • postman没有传值,查看返回结果

  • postmain传入设定的值,查看返回结果

四、测试一下基于cookie的方式灰度发布

  • 增加ingress注解

  • 浏览器没有指定的对应的cookie,返回默认页面

  • 浏览器写入设定的值,查看对应的返回页面

五、基于流量的规则

不推荐使用流量的规则,因为无法精确控制,因此不做测试

六、直接使用nginx灰度发布功能

如果你没有条件使用nginx-ingress,可以直接使用nginx配置文件以支持灰度发布

  • 基于权重的灰度发布

upstream backend_by_weight {  
    server v1.example.com weight=80;  
    server v2.example.com weight=20;  
}  
 
server {  
    listen 80;  
    location / {  
        proxy_pass http://backend_by_weight;  
    }  
}

  • 基于cookie的灰度发布
  • 基于headerd灰度发布

map $http_version $backend_by_hearder {  
    default             v1.example.com;  
    "2"                 v2.example.com;  
}  
 
server {  
    listen 80;  
    location / {  
        proxy_pass http://$backend_by_hearder;  
    }  
}