前提环境:
- kubernetes
- ingress
涉及参考文档:
- kubernetes 官方文档
- NGINX Ingress Controlle 官方手册
- kubernetes基于nginx-ingress进行蓝绿部署/金丝雀发布(canary)
- Kubernetes 使用Nginx-Ingress实现蓝绿发布/金丝雀发布/AB测试
一、Ingress-Nginx-Annotation Canary 功能简介
如果想启用Canary功能,要先设置nginx.ingress.kubernetes.io/canary: "true",
然后可以启用以下注释来配置Canary
nginx.ingress.kubernetes.io/canary-weight:
请求到Canary ingress中指定的服务的请求百分比,值为0-100的整数,根据设置的值来决定大概有百分之多少的流量会分配Canary Ingress中指定的后端服务nginx.ingress.kubernetes.io/canary-by-header:
基于request header 的流量切分,适用于灰度发布或者A/B测试,当设定的hearder值为always是,请求流量会被一直分配到Canary入口,当hearder值被设置为never时,请求流量不会分配到Canary入口,对于其他hearder值,将忽略,并通过优先级将请求流量分配到其他规则nginx.ingress.kubernetes.io/canary-by-header-value:
这个配置要和 nginx.ingress.kubernetes.io/canary-by-header 一起使用,当请求中的hearder key和value 和nginx.ingress.kubernetes.io/canary-by-header nginx.ingress.kubernetes.io/canary-by-header-value匹配时,请求流量会被分配到Canary Ingress入口,对于其他任何hearder值,将忽略,并通过优先级将请求流量分配到其他规则nginx.ingress.kubernetes.io/canary-by-cookie:
这个配置是基于cookie的流量切分,也适用于灰度发布或者A/B测试,当cookie值设置为always时,请求流量将被路由到Canary Ingress入口,当cookie值设置为never时,请求流量将不会路由到Canary入口,对于其他值,将忽略,并通过优先级将请求流量分配到其他规则
金丝雀规则按优先顺序进行如下排序
:canary-by-header - > canary-by-cookie - > canary-weight
二、部署服务
1、书写部署两个服务Pod的Yaml文件
- 老版本服务
vim echoserverv1.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
labels:
app: echoserverv1
name: echoserverv1
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv1
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv1
spec:
selector:
name: echoserverv1
type: ClusterIP
ports:
- name: echoserverv1
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv1
labels:
name: echoserverv1
spec:
selector:
matchLabels:
name: echoserverv1
template:
metadata:
labels:
name: echoserverv1
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv1
ports:
- containerPort: 8080
name: echoserverv1
- 新版本服务
vim echoserverv2.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
labels:
app: echoserverv2
name: echoserverv2
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv2
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
labels:
name: echoserverv2
spec:
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
2、生成两个Pod服务
kubectl apply -f echoserverv1.yaml -f echoserverv2.yaml
3、查看两个Pod服务的信息
kubectl get po,svc -o wide |grep echoserverv
可以看到两个可以正常访问服务。
4、查看ingress 详细信息
kubectl get ingress
5、测试访问
for i in `seq 10`;do curl -s http://echo.chulinx.com:30080|grep Hostname;done
三、Ingress-Nginx 权重的小规模版本测试
1、重新修改Ingress的 canary-weight流量权重
vim echoserverv2.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" #启动Canary功能,
nginx.ingress.kubernetes.io/canary-weight: "50" #求百分比
labels:
app: echoserverv2
name: echoserverv2
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv2
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
labels:
name: echoserverv2
spec:
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
2 、更新 echoserverv2服务权重流量
kubectl apply -f echoserverv2.yaml
3 、访问测试
for i in `seq 20`;do curl -s http://echo.chulinx.com:30080|grep Hostname;done
可以看到流量已有分流到第二个Pod上,权重值越高访问的越多。
四、基于header的A/B测试
1、拷贝权重测试的yaml文件
mkdir -P /root/kubernetes/ingress/基于header的AB测试
cp -r /root/kubernetes/ingress/蓝绿部署/* /root/kubernetes/ingress/基于header的AB测试
2、编辑v2服务yaml文件
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"
nginx.ingress.kubernetes.io/canary-by-header: "v2" # 新增定义的header值
labels:
app: echoserverv2
name: echoserverv2
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv2
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
labels:
name: echoserverv2
spec:
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
kubectl apply -f echoserverv2.yaml
3、更新后访问测试
nginx.ingress.kubernetes.io/canary-by-header:
:基于request header 的流量切分,适用于灰度发布或者A/B测试,当设定的hearder值为always是,请求流量会被一直分配到Canary入口
,当hearder值被设置为never时,请求流量不会分配到Canary入口
,对于其他hearder值,将忽略,并通过优先级将请求流量分配到其他规则
。对此进行验证是否符合
。
- always
for i in `seq 20`;do curl -s -H "v2:always" http://echo.chulinx.com:30080|grep Hostname;done
- never
for i in `seq 20`;do curl -s -H "v2:never" http://echo.chulinx.com:30080|grep Hostname;done
- 其他hearder值
for i in `seq 20`;do curl -s -H "v2:other" http://echo.chulinx.com:30080|grep Hostname;done
这里可以验证出: canary-by-header —> canary-weight
自定义header-value
nginx.ingress.kubernetes.io/canary-by-header-value:
这个配置要和nginx.ingress.kubernetes.io/canary-by-header 一起使用
,当请求中的hearder key和value 和nginx.ingress.kubernetes.io/canary-by-header nginx.ingress.kubernetes.io/canary-by-header-value匹配时,请求流量会被分配到Canary Ingress入口
,对于其他任何hearder值,将忽略,并通过优先级将请求流量分配到其他规则
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"
nginx.ingress.kubernetes.io/canary-by-header: "v2"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
labels:
app: echoserverv2
name: echoserverv2
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv2
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
labels:
name: echoserverv2
spec:
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
kubectl apply -f echoserverv3.yaml
- true value值
for i in `seq 8`;do curl -s -H "v2:true" http://echo.chulinx.com:30080|grep Hostname;done
- always value值
for i in `seq 8`;do curl -s -H "v2:always" http://echo.chulinx.com:30080|grep Hostname;done
- never value值
for i in `seq 8`;do curl -s -H "v2:never" http://echo.chulinx.com:30080|grep Hostname;done
如上发现: 符合key—value 值 全部流量才全部流入,always/never 本来是要不全部流入或者全部拒绝,在这里变成了随机,这里可以看出来如果设置的 key对应的value值always/never默认的value受到影响,已自定义的value为标准
五、基于cookie的流控
1、拷贝权重测试的yaml文件
mkdir -p /root/kubernetes/ingress/cookie
cp -r ../基于header的AB测试/echoserverv3.yaml ./echoserverv4.yaml
2、编辑v2服务yaml文件
vim echoserverv4.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"
nginx.ingress.kubernetes.io/canary-by-header: "v2"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_shanghai"
labels:
app: echoserverv2
name: echoserverv2
spec:
rules:
- host: echo.chulinx.com
http:
paths:
- backend:
serviceName: echoserverv2
servicePort: 8080
path: /
---
kind: Service
apiVersion: v1
metadata:
name: echoserverv2
spec:
selector:
name: echoserverv2
type: ClusterIP
ports:
- name: echoserverv2
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserverv2
labels:
name: echoserverv2
spec:
selector:
matchLabels:
name: echoserverv2
template:
metadata:
labels:
name: echoserverv2
spec:
containers:
- image: mirrorgooglecontainers/echoserver:1.10
name: echoserverv2
ports:
- containerPort: 8080
name: echoserverv2
3、更新后访问测试
kubectl apply -f echoserverv4.yaml
- user_from_shanghai always 值
for i in `seq 8`;do curl -s --cookie "user_from_shanghai=always" http://echo.chulinx.com:30080|grep Hostname;done
-
user_from_shanghai never 值
-
user_from_shanghai other 值
可以看和header的访问效果是一样的,只不过cookie不能自定义value
3、canary-by-header 与canary-by-cookie 优先级测试
- header 【v2: true】 、 cookie 【never】
for i in `seq 8`;do curl -s -H "v2:true" --cookie "user_from_shanghai=never" http://echo.chulinx.com:30080|grep Hostname;done
胜利者 header
- header 【v2: other】 、 cookie 【always】
**胜利者 cookie **
- header 【v2: other】 、 cookie 【other】
**平局 **