Kubernetes—使用nginx-ingress实现灰度发布

1,825 阅读3分钟

Ingress-Nginx 是一个K8S ingress控制器,支持配置 Ingress Annotations 来实现不同场景下的灰度发布和测试。 Nginx Annotations 支持以下 4 种 Canary 规则:

  • nginx.ingress.kubernetes.io/canary-by-header:基于 Request Header 的流量切分,适用于灰度发布以及 A/B 测试。当 Request Header 设置为 always时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never时,请求不会被发送到 Canary 入口;对于任何其他 Header 值,将忽略 Header,并通过优先级将请求与其他金丝雀规则进行优先级的比较。
  • 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-by-header - > canary-by-cookie - > canary-weight

minikube 配置

开启nginx-ingress

由于我使用的是minikube来搭建集群环境,首先要在minikube中开启nginx-ingress控制器,可以运行下面的命令

minikube addons enable ingress

添加docker 私有仓库访问凭证

首先我们的K8S需要从docker hub中拉取自己域下的镜像,我们必须生成一个凭证。

  • 登录docker
docker login -u 用户名
  • 为k8s集群创建Secret
kubectl delete secret registry-key // 如果有的话先删除
kubectl -n default create secret docker-registry registry-key \
--docker-server=hub.docker.com \
--docker-username=docker账号 \
--docker-password=docker账号密码 \
--docker-email=邮箱

注意 -n default 为指定命名空间,一般搭建k8s集群时,建议新建一个命名空间来隔离资源。

然后就可以在K8S控制台中,看到我们刚刚创建的secret,详情参考从私有仓库拉取镜像

image.png

然后在我们的Deplyment中配置imagePullSecrets为registry-key

正常版本

  • Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-app
spec:
  selector:
    matchLabels:
      app: product-app
  replicas: 1
  template:
    metadata:
      labels:
        app: product-app
    spec:
      imagePullSecrets:
        - name: registry-key
      containers:
        - name: product-app
          image: djlxs/gray-app:v2
          ports:
            - containerPort: 80
  • Service
apiVersion: v1
kind: Service
metadata:
  name: product-app
spec:
  selector:
    app: product-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort
  • Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: product-app
 annotations:
   kubernetes.io/ingress.class: nginx
spec:
 rules:
   - host: app-ingress.info
     http:
       paths:
       - backend:
           service:
             name: product-app
             port:
               number: 80
         path: /
         pathType: Prefix

灰度版本

  • Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gray-app
spec:
  selector:
    matchLabels:
      app: gray-app
  replicas: 1
  template:
    metadata:
      labels:
        app: gray-app
    spec:
      imagePullSecrets:
        - name: registry-key
      containers:
        - name: gray-app
          image: djlxs/gray-app:v1
          ports:
            - containerPort: 80
  • Service
apiVersion: v1
kind: Service
metadata:
  name: gray-app
spec:
  selector:
    app: gray-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort
  • Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gray-app
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "canary"
spec:
  rules:
    - host: app-ingress.info
      http:
        paths:
        - backend:
            service:
              name: gray-app
              port:
                number: 80
          path: /
          pathType: Prefix

测试

curl http://app-ingress.info
curl http://app-ingress.info -H "canary:always"

这里设置灰度cookie的值为always,nginx-ingress的方案只支持发布一个灰度版本

参考资料

Nginx Annotations

从私有仓库拉取镜像

使用 Ingress-Nginx 进行灰度发布