欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

nginx-ingress 的灰度发布

程序员文章站 2022-05-29 22:47:23
...

nginx-ingress 的灰度发布

基于Request Header的流量切分

nginx.ingress.kubernetes.io/canary-by-header:用于通知Ingress将请求路由到Canary Ingress中指定的服务的标头。当请求标头设置always为时,它将被路由到Canary。当标头设置never为时,它将永远不会被路由到Canary。对于任何其他值,将忽略标头,并通过优先级将请求与其他Canary规则进行比较。

nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的标头值,用于通知Ingress将请求路由到Canary Ingress中指定的服务。当请求标头设置为此值时,它将被路由到Canary。对于任何其他标头值,标头将被忽略,并且请求与其他Canary规则的优先级进行比较。此注释必须与canary-by-header一起使用。nginx.ingress.kubernetes.io/canary-by-header注释允许自定义标头值而不是使用硬编码值的扩展。如果nginx.ingress.kubernetes.io/canary-by-header注释未定义,则没有任何效果。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "new"
  labels:
    app: demo
  name: demo-ingress
  namespace: demo-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: demo-canary
          servicePort: 80
        path: /

上面这个示例,当你请求头加入new: always的时候就会访问demo-canary,当标头设置never为时,则不会访问。例如下面的这个curl

curl -s -H “new: always” http://canary.example.com
下面这个示例使用的是自定义的标头值

例2:使用canary-by-header-value

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "new"
    nginx.ingress.kubernetes.io/canary-by-header-value:"xxx"
  labels:
    app: demo
  name: demo-ingress
  namespace: demo-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: demo-canary
          servicePort: 80
        path: /

使用如下请求可以正常访问demo-canary

curl -s -H “new: xxx” http://canary.example.com

基于Cookie的流量切分

nginx.ingress.kubernetes.io/canary-by-cookie:用于通知Ingress将请求路由到Canary Ingress中指定的服务的cookie。当cookie值设置always为时,它将被路由到Canary。当cookie被设置never为时,它将永远不会被路由到Canary。对于任何其他值,cookie将被加入,并且请求与其他Canary规则的优先级进行比较。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "use_under_30_feature"
  labels:
    app: demo
  name: demo-ingress
  namespace: demo-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: demo-canary
          servicePort: 80
        path: /

上面的这个示例,当cookie设置为use_under_30_feature为always的时候,则会访问demo-canary

基于服务权重的流量切分

nginx.ingress.kubernetes.io/canary-weight:将路由到金丝雀Ingress中指定的服务的随机请求的整数(0 - 100)百分比。权重为0意味着该Canary规则不会向Canary入口中的服务发送任何请求。权重为100意味着所有请求都将被发送到Ingress中指定的替代服务。示例如下(使用20%的权重):

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"
  labels:
    app: demo
  name: demo-ingress
  namespace: demo-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: demo-canary
          servicePort: 80
        path: /

注意这里权重不是一个精确的百分比,使用过程当中,只是会看到一个近似分布。

实际案例

以下测试基于服务权重的流量切分,也可以将nginx.ingress.kubernetes.io/canary-weight: "30"改为基于 header 的流量切分。

准备老版本程序
老版本程序 app-old

app-old.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app-old
spec:
  replicas: 2
  selector:
    matchLabels:
      run: app-old
  template:
    metadata:
      labels:
        run: app-old
    spec:
      containers:
      - image: zouhl/app:v2.1
        imagePullPolicy: Always
        name: app-old
        ports:
        - containerPort: 80
          protocol: TCP
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: app-old
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: app-old
  sessionAffinity: None
  type: NodePor

老版本的 ingress

app-v1.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-app
  labels:
    app: my-app
  annotations:
    kubernetes.io/ingress.class: nginx
  namespace: default
spec:
  rules:
    - host: test.192.168.2.20.xip.io
      http:
        paths:
          - backend:
              serviceName: app-old
              servicePort: 80
            path: /

装备新版本程序

新版本app-new.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app-new
spec:
  replicas: 2
  selector:
    matchLabels:
      run: app-new
  template:
    metadata:
      labels:
        run: app-new
    spec:
      containers:
      - image: zouhl/app:v2.2
        imagePullPolicy: Always
        name: app-new
        ports:
        - containerPort: 80
          protocol: TCP
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: app-new
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: app-new
  sessionAffinity: None
  type: NodePort

新版本 canary-ingress

app-v2-canary.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-app-canary
  labels:
    app: my-app
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "30"
  namespace: default
spec:
  rules:
    - host: test.192.168.2.20.xip.io
      http:
        paths:
          - backend:
              serviceName: app-new
              servicePort: 80
            path: /

新版本 ingress yaml

app-v2.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-app
  labels:
    app: my-app
  annotations:
    kubernetes.io/ingress.class: nginx
  namespace: default
spec:
  rules:
    - host: test.192.168.2.20.xip.io
      http:
        paths:
          - backend:
              serviceName: app-new
              servicePort: 80
            path: /

流程

Created with Raphaël 2.2.0old ingresscanary ingress版本无问题new ingressyesno

发布流程

$ tree                                              
.
├── app-new.yaml
├── app-old.yaml
├── app-v1.yaml
├── app-v2-canary.yaml
└── app-v2.yaml

# 创建old pod 
kubectl create -f app-old.yaml
# 创建old ingress
kubectl create -f app-v1.yaml
# 创建new pod
kubectl create -f app-new.yaml
# 创建canary ingress
kubectl create -f app-v2-canary.yaml

检查

$ kubectl get ingresses.extensions   
NAME            HOSTS                       ADDRESS   PORTS   AGE
app-ingress     www.example.com                       80      109m
my-app          test.192.168.2.20.xip.io              80      25m
my-app-canary   test.192.168.2.20.xip.io              80      1s
nginx-test      nginx.192.168.2.20.xip.io             80      3h12m

在后台观察,70% to v1,30% to v2

如果一切正常则可以正式发布

# delete the canary ingress
kubectl delete -f app-v2-canary.yaml
# set 100% traffic to v2
kubectl apply -f app-v2.yaml
# delete the canary ingress kubectl delete -f app-v2-canary.yaml # set 100% traffic to v2 kubectl apply -f app-v2.yaml

检查 ingress

$ kubectl get ingresses.extensions    
NAME          HOSTS                       ADDRESS   PORTS   AGE
app-ingress   www.example.com                       80      109m
my-app        test.192.168.2.20.xip.io              80      25m
nginx-test    nginx.192.168.2.20.xip.io             80      3h13m
相关标签: 虚拟化