参考1:www.xubaojin.com/post/391.ht… 参考2:www.cnblogs.com/klvchen/art…
关于nginx-ingress注解
我们通过给 Ingress 资源指定 Nginx Ingress 所支持的一些 annotation 可以实现金丝雀发布,需要给服务创建两个 Ingress,一个正常的 Ingress,另一个是带 nginx.ingress.kubernetes.io/canary: "true" 这个固定的 annotation 的 Ingress,我们姑且称它为 Canary Ingress,一般代表新版本的服务,结合另外针对流量切分策略的 annotation 一起配置即可实现多种场景的金丝雀发布,以下对这些 annotation 详细介绍下:
nginx.ingress.kubernetes.io/canary-by-header: 表示如果请求头中包含这里指定的 header 名称,并且值为 always 的话,就将该请求转发给该 Ingress 定义的对应后端服务;如果值为 never 就不转发,可以用于回滚到旧版;如果是其它值则忽略该 annotation。
nginx.ingress.kubernetes.io/canary-by-header-value: 这个可以作为 canary-by-header的补充,允许指定请求头的值可以自定义成其它值,不再只能是 always 或 never;当请求头的值命中这里的自定义值时,请求将会转发给该 Ingress 定义的对应后端服务,如果是其它值则将会忽略该 annotation。
nginx.ingress.kubernetes.io/canary-by-header-pattern: 这个与上面的 canary-by-header-value 类似,唯一的区别是它是用正则表达式对来匹配请求头的值,而不是只固定某一个值;需要注意的是,如果它与 canary-by-header-value 同时存在,这个 annotation 将会被忽略。
nginx.ingress.kubernetes.io/canary-by-cookie: 这个与 canary-by-header 类似,只是这个用于 cookie,同样也是只支持 always 和 never 的值。
nginx.ingress.kubernetes.io/canary-weight: 表示 Canary Ingress 所分配流量的比例的百分比,取值范围 [0-100],比如设置为 10,意思是分配 10% 的流量给 Canary Ingress 对应的后端服务。
上面的规则会按优先顺序进行评估,优先顺序如下:canary-by-header -> canary-by-cookie -> canary-weight
注意: 当 Ingress 被标记为 Canary Ingress 时,除了nginx.ingress.kubernetes.io/load-balance和 nginx.ingress.kubernetes.io/upstream-hash-by 之外,所有其他非 Canary 注释都将被忽略。
实践总结:
虽然我们使用 Nginx Ingress 实现了几种不同姿势的金丝雀发布,但还存在一些缺陷:
- 相同服务的 Canary Ingress 只能定义一个,所以后端服务最多支持两个版本。
- Ingress 里必须配置域名,否则不会有效果。
- 即便流量完全切到了 Canary Ingress 上,旧版服务也还是必须存在,不然会报错。
实现
Ingress-Nginx 在 0.21 版本引入了 Canary 功能,可以为网关入口配置多个版本的应用程序,使用annotation来控制多个后端服务的流量分配。
如果想启用Canary功能,要先设置 nginx.ingress.kubernetes.io/canary: "true",然后可以启用以下注释来配置Canary
nginx.ingress.kubernetes.io/canary-weight 请求到 Canary ingress 中指定的服务的请求百分比,值为 0-100 的整数,根据设置的值来决定大概有百分之多少的流量会分配Canary Ingress中指定的后端服务。
先说测试结论
可以实现金丝雀发布,但是是入口网关级别的,只能针对配置了 ingress nginx 的那个 svc 服务,不是接入流量的普通 K8S svc 并适用。
测试
mkdir -p /data/yaml/echoserver && cd /data/yaml/echoserver
cat echoserverv1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
labels:
app: echoserverv1
name: echoserverv1
namespace: echoserver
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: echoserverv1
port:
number: 8080
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv1
namespace: echoserver
spec:
selector:
name: echoserverv1
type: ClusterIP
ports:
- name: echoserverv1
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv1
namespace: echoserver
labels:
name: echoserverv1
spec:
replicas: 1
selector:
matchLabels:
name: echoserverv1
template:
metadata:
labels:
name: echoserverv1
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv1
ports:
- containerPort: 8080
name: echoserverv1
cat echoserverv2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" # 开启canary功能
nginx.ingress.kubernetes.io/canary-weight: "50" # 将v2版本的权重设置为50%,这个百分比并不能精确的将请求平均分配到两个版本的服务,而是在50%上下浮动
labels:
app: echoserverv2
name: echoserverv2
namespace: echoserver
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: echoserverv2
port:
number: 8080
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
namespace: echoserver
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
namespace: echoserver
labels:
name: echoserverv2
spec:
replicas: 1
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
kubctl apply -f echoserverv1.yaml -f echoserverv2.yaml