Nginx Ingress Controller 作为 Kubernetes 官方推荐的 ingress controller 实现,可以说是非常好用,尤其是在你之前如果使用 Nginx 作为反向代理或者负载均衡,那么对于 nginx ingress controller 的应用也会得心应手。Nginx ingress controller 对外暴露 kubernetes 中的服务,作为外部流量的入口,是集群中非常关键的组件。我们这篇文章关注 nginx ingress 通过 annotation 提供的流量管理功能,利用 annotation 的配置可以轻松帮助我们实现金丝雀发布和A/B test。
Nginx ingress annotations
假设我们现在部署了两个版本的服务,老版本和 canary 版本
- nginx.ingress.kubernetes.io/canary-by-header
请求头中如果包含了这个 annotation 设置的值,则流量被转发到 canary 版本的服务
- nginx.ingress.kubernetes.io/canary-by-header-value
这个 annotation 是配合
nginx.ingress.kubernetes.io/canary-by-header
来使用的,当请求头对应上面配置的 header 的值与这个 annotation 匹配, 则流量转发到 canary 版本
- nginx.ingress.kubernetes.io/canary-weight
根据权重来转发流量,配置的权重值为 0-100。如配置 30 ,则把 30% 的流量转发到 canary 版本
- nginx.ingress.kubernetes.io/canary-by-cookie
根据请求头中的 cookie 转发流量,如果 cookie 与配置的 annotation 的值匹配,且 cookie 的 value 是
always
, 则该请求会被转发到 canary 版本
部署服务
这里我们服务的 deployment 就不展示了,service 配置如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# 测试版本
apiVersion: v1
kind: Service
metadata:
name: hello-service
labels:
app: hello-service
spec:
ports:
- port: 80
protocol: TCP
selector:
app: hello-service
# canary 版本
apiVersion: v1
kind: Service
metadata:
name: canary-hello-service
labels:
app: canary-hello-service
spec:
ports:
- port: 80
protocol: TCP
selector:
app: canary-hello-service
|
根据权重转发
ingress 配置如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
spec:
rules:
- host: canary-service.abc.com
http:
paths:
- backend:
serviceName: canary-hello-service
servicePort: 80
|
测试结果如下
1
2
3
4
5
6
7
8
9
10
11
12
|
$ for i in $(seq 1 10); do curl http://canary-service.abc.com; echo '\n'; done
hello world-version1
hello world-version1
hello world-version2
hello world-version2
hello world-version1
hello world-version1
hello world-version1
hello world-version1
hello world-version1
hello world-version1
|
根据请求头转发
annotation
配置如下(ingress 其余部分省略)
1
2
3
4
|
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "test"
|
测试结果如下
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ for i in $(seq 1 5); do curl http://canary-service.abc.com; echo '\n'; done
hello world-version1
hello world-version1
hello world-version1
hello world-version1
hello world-version1
$ for i in $(seq 1 5); do curl -H 'test:always' http://canary-service.abc.com; echo '\n'; done
hello world-version2
hello world-version2
hello world-version2
hello world-version2
hello world-version2
|
根据特定的请求头和值转发
annotation 配置如下
1
2
3
4
|
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "test"
nginx.ingress.kubernetes.io/canary-by-header-value: "abc"
|
测试结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ for i in $(seq 1 5); do curl -H 'test:always' http://canary-service.abc.com; echo '\n'; done
hello world-version1
hello world-version1
hello world-version1
hello world-version1
hello world-version1
$ for i in $(seq 1 5); do curl -H 'test:abc' http://canary-service.abc.com; echo '\n'; done
hello world-version2
hello world-version2
hello world-version2
hello world-version2
hello world-version2
|
根据 cookie 转发
使用 cookie 来进行流量管理的场景比较适合用于 A/B test,比如用户的请求 cookie 中含有特殊的标签,那么我们可以把这部分用户的请求转发到特定的服务进行处理。
annotation 配置如下
1
2
3
|
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "like_music"
|
测试结果如下
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ for i in $(seq 1 5); do curl -b 'like_music=1' http://canary-service.abc.com; echo '\n'; done
hello world-version1
hello world-version1
hello world-version1
hello world-version1
hello world-version1
$ for i in $(seq 1 5); do curl -b 'like_music=always' http://canary-service.abc.com; echo '\n'; done
hello world-version2
hello world-version2
hello world-version2
hello world-version2
hello world-version2
|
三种 annotation
按如下顺序匹配
canary-by-header > canary-by-cookie > canary-weight
总结
我们从以上的测试结果来看,可以把流量的转发分成以下两类
- 根据权重
1
2
3
4
5
6
7
|
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
70%
|------> 生产版本
users --- 100% ---> Nginx Ingress ----| 30%
|------> canary 版本
|
- 根据用户
1
2
3
4
5
6
7
8
|
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "test"
nginx.ingress.kubernetes.io/canary-by-header-value: "abc"
others
|-----------> 生产版本
users ------> Nginx Ingress ------| "test:abc"
|-----------> canary 版本
|