通过Nginx-ingress实现灰度发布

最近更新时间:2021-02-03 14:52:22

查看PDF

在对服务进行版本发布或版本升级场景中,常会用到灰度发布、蓝绿发布等发布方式。本文将介绍如何在金山云容器服务中通过Nginx-ingress服务实现应用的灰度发布。

前提条件

集群内完成nginx-ingress-controller的部署,并通过金山云的负载均衡服务暴露到集群外。部署方式可参考Nginx-ingress支持

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版本服务的部署情况:

[[email protected] ~]# kubectl apply -f helloworld-v2.yaml
deployment.apps/hello-world-v2 created
service/hello-world-svc-v2 created
[[email protected] ~]# 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
[[email protected] ~]# 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
[[email protected] ~]# curl 10.254.200.211
Hello World v1!
[[email protected] ~]# curl 10.254.14.130
Hello World v2!

配置Ingress

基于服务权重进行流量切分

对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规则:

[[email protected] ~]# kubectl apply -f helloworld-ingress.yaml
ingress.extensions/hello-world created
[[email protected] ~]# kubectl apply -f weight-ingress.yaml
ingress.extensions/helloworld-weight created
[[email protected] ~]# 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及访问服务:

[[email protected] ~]# 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
[[email protected] ~]# 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版本服务中。

文档内容是否对您有帮助?

根本没帮助
文档较差
文档一般
文档不错
文档很好

在文档使用中是否遇到以下问题

  • 内容不全,不深入
  • 内容更新不及时
  • 描述不清晰,比较混乱
  • 系统或功能太复杂,缺乏足够的引导
  • 内容冗长

更多建议

0/200

评价建议不能为空

提交成功!

非常感谢您的反馈,我们会继续努力做到更好!

问题反馈