最近更新时间:2022-07-25 10:36:55
在对服务进行版本发布或版本升级场景中,常会用到灰度发布、蓝绿发布等发布方式。本文将介绍如何在金山云容器服务中通过Nginx-ingress服务实现应用的灰度发布。
集群内完成nginx-ingress-controller的部署,并通过金山云的负载均衡服务暴露到集群外。部署方式可参考Nginx-ingress使用。
Ingress controller支持通过配置ingress annotations实现不同场景下的灰度发布和测试。Nginx annotations支持以下四种灰度发布(Canary)规则:
nginx.ingress.kubernetes.io/canary-by-header
:基于 Request Header 的流量切分,适用于灰度发布以及 A/B 测试。当 Request Header 设置为 always
时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never
时,请求不会被发送到 Canary 入口;对于任何其他 Header 值,将忽略 Header,并通过优先级将请求与其他 Canary 规则进行优先级的比较。nginx.ingress.kubernetes.io/canary-by-header-value
:要匹配的 Request Header 的值,用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。当 Request Header 设置为此值时,它将被路由到 Canary 入口。该规则允许用户自定义 Request Header 的值,必须与上一个 annotation (即:canary-by-header)一起使用。nginx.ingress.kubernetes.io/canary-weight
:基于服务权重的流量切分,适用于蓝绿部署,权重范围 0 - 100 按百分比将请求路由到 Canary Ingress 中指定的服务。权重为 0 意味着该金丝雀规则不会向 Canary 入口的服务发送任何请求。权重为 100 意味着所有请求都将被发送到 Canary 入口。nginx.ingress.kubernetes.io/canary-by-cookie
:基于 Cookie 的流量切分,适用于灰度发布与 A/B 测试。用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务的 cookie。当 cookie 值设置为 always
时,它将被路由到 Canary 入口;当 cookie 值设置为 never
时,请求不会被发送到 Canary 入口;对于任何其他值,将忽略 cookie 并将请求与其他金丝雀规则进行优先级的比较。注意:当同时使用多个Canary规则时,按如下优先顺序进行排序:
canary-by-header - > canary-by-cookie - > canary-weight
以下示例中将会部署helloworld服务的v1和v2版本,将v2版本作为canary版本,在ingress中设置canary规则,实现基于服务权重的流量切分。
helloworld-v1.yaml如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
version: v1
template:
metadata:
labels:
app: hello-world
version: v1
spec:
containers:
- name: hello-world
image: hub.kce.ksyun.com/kingsoft/hello-world:v1
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-world
name: hello-world-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: hello-world
version: v1
type: ClusterIP
helloworld-v2.yaml如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world-v2
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
version: v2
template:
metadata:
labels:
app: hello-world
version: v2
spec:
containers:
- name: hello-world
image: hub.kce.ksyun.com/kingsoft/hello-world:v2
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-world
name: hello-world-svc-v2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: hello-world
version: v2
type: ClusterIP
创建并验证v1,v2版本服务的部署情况:
[root@vm10-0-11-201 ~]# kubectl apply -f helloworld-v2.yaml
deployment.apps/hello-world-v2 created
service/hello-world-svc-v2 created
[root@vm10-0-11-201 ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 1/1 1 1 15s
hello-world-v2 1/1 1 1 9s
[root@vm10-0-11-201 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-svc ClusterIP 10.254.200.211 <none> 80/TCP 19s
hello-world-svc-v2 ClusterIP 10.254.14.130 <none> 80/TCP 13s
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 7d
[root@vm10-0-11-201 ~]# curl 10.254.200.211
Hello World v1!
[root@vm10-0-11-201 ~]# curl 10.254.14.130
Hello World v2!
对v1版本服务进行Ingress配置,创建helloworld-ingress.yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-world
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: hello.world.test
http:
paths:
- backend:
serviceName: hello-world-svc
servicePort: 80
对v2版本的canary规则进行配置,创建weight-ingress.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"
name: helloworld-weight
spec:
rules:
- host: hello.world.test
http:
paths:
- backend:
serviceName: hello-world-svc-v2
servicePort: 80
创建Ingress规则:
[root@vm10-0-11-201 ~]# kubectl apply -f helloworld-ingress.yaml
ingress.extensions/hello-world created
[root@vm10-0-11-201 ~]# kubectl apply -f weight-ingress.yaml
ingress.extensions/helloworld-weight created
[root@vm10-0-11-201 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
hello-world <none> hello.world.test 80 41s
helloworld-weight <none> hello.world.test 80 27s
通过以下命令获取EXTERNAL-IP及访问服务:
[root@vm10-0-11-201 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress LoadBalancer 10.254.28.54 120.92.xx.xx 80:31741/TCP,443:32754/TCP 3h19m
[root@vm10-0-11-201 ~]# for i in $(seq 1 10); do curl -H "Host: hello.world.test" http://120.92.xx.xx; done;
Hello World v2!
Hello World v2!
Hello World v1!
Hello World v2!
Hello World v2!
Hello World v1!
Hello World v1!
Hello World v1!
Hello World v2!
Hello World v2!
多次访问能发现约50%的流量会被分发到v2版本服务中。
纯净模式