基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布

前面有科普过灰度发布,那么本章将通过一个案例来给大家展示下实现的过程细节。

前置条件:

1、k8s集群

背景分析:

灰度及蓝绿发布是为新版本服务创建一个与老版本服务完全一致的生产环境,在不影老版本服务的前提下,按照一定的规则把部分流量切换到新版本,当新版本试运行一段时间没有问题后,将用户的全量流量从老版本迁移至新版本。

其中AB测试就是一种灰度发布方式,一部分用户继续使用老版本的服务,将一部分用户的流量切换到新版本,如果新版本运行稳定,则逐步将所有用户迁移到新版本。

应用场景

基于客户端请求的流量切分场景

例如当前线上环境,有一套服务nginx-v1对外提供7层服务,此时上线了一些新的特性,需要发布上线一个新的版本nginx-v2
,但又不想直接替换nginx-v1服务,而是希望将请求头中包含nginx=v2或者cookie中包含nginx=v2的客户端请求转发到nginx-v2服务中。待运行一段时间稳定后,可将所有的流量从nginx-v1切换到nginx-v2服务中,再平滑地将nginx-v1服务下线。

基于服务权重的流量切分场景

例如当前线上环境,有一套服务nginx-v1对外提供7层服务,此时修复了一些问题,需要发布上线一个新的版本nginx-v2。但又不想将所有客户端流量切换到新版本nginx-v2中,而是希望将20%的流量切换到新版本nginx-v2中。待运行一段时间稳定后,再将所有的流量从nginx-v1切换到nginx-v2服务中,再平滑地将nginx-v1服务下线。

针对以上多种不同的应用发布需求,ingress支持了多种流量切分方式:

  • 基于Request Header的流量切分,适用于灰度发布以及AB测试场景。
  • 基于Cookie的流量切分,适用于灰度发布以及AB测试场景。
  • 基于Query Param的流量切分,适用于灰度发布以及AB测试场景。
  • 基于服务权重的流量切分,适用于蓝绿发布场景。

注解说明

Ingress Controller通过下列Annotation来支持应用服务的灰度发布机制。

  • nginx.ingress.kubernetes.io/service-match该注解用来配置新版本服务的路由匹配规则。
nginx.ingress.kubernetes.io/service-match: | 
    <service-name>: <match-rule>
# 参数说明:
# service-name:服务名称,满足match-rule的请求会被路由到该服务中。
# match-rule:路由匹配规则
#
# 路由匹配规则:
# 1. 支持的匹配类型
# - header:基于请求头,支持正则匹配和完整匹配。
# - cookie:基于cookie,支持正则匹配和完整匹配。
# - query:基于请求参数,支持正则匹配和完整匹配。
#
# 2. 匹配方式
# - 正则匹配格式:/{regular expression}/,//表明采用正则方式匹配。
# - 完整匹配格式:"{exact expression}",""表明采用完整方式匹配。

路由匹配规则配置示例:

#请求头中满足foo正则匹配^bar$的请求被转发到新版本服务new-nginx中。
new-nginx: header("foo", /^bar$/)
#请求头中满足foo完整匹配bar的请求被转发到新版本服务new-nginx中。 
new-nginx: header("foo", "bar")
#cookie中满足foo正则匹配^sticky-.+$的请求被转发到新版本服务。
new-nginx中。 new-nginx: cookie("foo", /^sticky-.+$/)
#query param中满足foo完整匹配bar的请求被转发到新版本服务new-nginx中。
new-nginx: query("foo", "bar")

nginx.ingress.kubernetes.io/service-weight
该注解用来配置新旧版本服务的流量权重。

nginx.ingress.kubernetes.io/service-weight: | 
    <new-svc-name>:<new-svc-weight>, <old-svc-name>:<old-svc-weight>
参数说明: 
     new-svc-name:新版本服务名称 
     new-svc-weight:新版本服务权重 
     old-svc-name:旧版本服务名称
     old-svc-weight:旧版本服务权重

服务权重配置示例:

nginx.ingress.kubernetes.io/service-weight: | 
    nginx-v1: 50, nginx-v2: 50

步骤一:部署服务

部署Nginx服务并通过Ingress Controller对外提供7层域名访问。

1. 创建Deployment和Service。

cat nginx-v1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-v1
  template:
    metadata:
      labels:
        app: nginx-v1
        ms: nginx
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/my_image_repo/nginx:v1
        imagePullPolicy: Always
        name: nginx-v1
        ports:
        - containerPort: 80
          protocol: TCP
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-v1
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-v1
    ms: nginx
  sessionAffinity: None
  type: ClusterIP

2. 执行以下命令,创建Deployment和Service

kubectl apply -f nginx-v1.yaml

基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第1张图片

3. 部署Ingress

cat ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
spec:
  rules:
  - host: www.mynginx.com
    http:
      paths:
      # 老版本服务
      - path: /
        backend:
          service:
            name: nginx-v1
            port:
              number: 80
        pathType: ImplementationSpecific

在这里插入图片描述

4. 测试访问情况

在这里插入图片描述

curl -H "Host: www.mynginx.com"  http://<EXTERNAL_IP>

步骤二:灰度发布新版本服务

发布一个新版本的Nginx服务并配置路由规则。

1. 部署新版本的Deployment和Service。

cat nginx-v2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-v2
  template:
    metadata:
      labels:
        app: nginx-v2
        ms: nginx
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/my_image_repo/nginx:v2
        imagePullPolicy: Always
        name: nginx-v2
        ports:
        - containerPort: 80
          protocol: TCP
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-v2
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-v2
    ms: nginx
  sessionAffinity: None
  type: ClusterIP

2. 部署新版本的Deployment和Service。

kubectl apply -f nginx-v2.yaml

基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第2张图片

3. 设置访问新版本服务的路由规则。

ACK支持设置以下三种路由规则,您可以根据实际情况选择路由规则。

1) 设置满足特定规则的客户端才能访问新版本服务。

以下示例仅请求头中满足nginx=v2的客户端请求才能路由到新版本服务。修改Ingress文件如下:
cat ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nginx
  annotations:
  # 请求头中满足正则匹配nginx=v2的请求才会被路由到新版本服务nginx-v2中
    nginx.ingress.kubernetes.io/service-match: |
      nginx-v2: header("nginx", /^v2$/)
spec:
  rules:
  - host: www.mynginx.com
    http:
      paths:
      # 老版本服务
      - path: /
        backend:
          service:
            name: nginx-v1
            port:
              number: 80
        pathType: ImplementationSpecific
      # 新版本服务
      - path: /
        backend:
          service:
            name: nginx-v2
            port:
              number: 80
        pathType: ImplementationSpecific
kubectl replace -f ingress.yaml

查看路由访问情况

curl -H "Host: www.mynginx.com"  http://<EXTERNAL_IP>
curl -H "Host: www.mynginx.com"  -H "nginx: v2" http://<EXTERNAL_IP>
curl -H "Host: www.mynginx.com"  -H "nginx: v1" http://<EXTERNAL_IP>

基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第3张图片

2) 在满足特定规则的基础上设置一定比例的请求被路由到新版本服务中。

以下示例要求请求头中满足nginx=v2的客户端请求,且仅允许其中50%的流量被路由到新版本服务中。修改Ingress文件如下:
cat ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nginx
  annotations:
  # 请求头中满足正则匹配foo=bar的请求才会被路由到新版本服务new-nginx中
    nginx.ingress.kubernetes.io/service-match: |
        nginx-v2: header("nginx", /^v2$/)
  # 允许50%的流量被路由到新版本服务new-nginx中
    nginx.ingress.kubernetes.io/service-weight: |
      nginx-v1: 50, nginx-v2: 50
spec:
  rules:
  - host: www.mynginx.com
    http:
      paths:
      # 老版本服务
      - path: /
        backend:
          service:
            name: nginx-v1
            port:
              number: 80
        pathType: ImplementationSpecific
      # 新版本服务
      - path: /
        backend:
          service:
            name: nginx-v2
            port:
              number: 80
        pathType: ImplementationSpecific
kubectl apply -f ingress.yaml

查看路由访问情况
执行以下命令,访问服务。

curl -H "Host: www.mynginx.com"  http://<EXTERNAL_IP>

重复执行以上命令,可以看到没有匹配到header的请求流量全部路由原有服务中。
基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第4张图片
重复执行以下命令,可以看到仅请求头中满足nginx=v2的客户端请求,且只有50%的流量才能路由到新版本服务。

curl -H "Host: www.mynginx.com" -H "nginx: v2"   http://<EXTERNAL_IP>

基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第5张图片

3) 设置一定比例的请求被路由到新版本服务中。

以下示例中仅50%的流量被路由到新版本服务中。修改Ingress文件如如下:
cat ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nginx
  annotations:
  # 允许50%的流量被路由到新版本服务new-nginx中
    nginx.ingress.kubernetes.io/service-weight: |
      nginx-v1: 50, nginx-v2: 50
spec:
  rules:
  - host: www.mynginx.com
    http:
      paths:
      # 老版本服务
      - path: /
        backend:
          service:
            name: nginx-v1
            port:
              number: 80
        pathType: ImplementationSpecific
      # 新版本服务
      - path: /
        backend:
          service:
            name: nginx-v2
            port:
              number: 80
        pathType: ImplementationSpecific
在这里插入代码片
kubectl apply -f ingress.yaml

查看路由访问情况
执行以下命令,访问服务

curl -H "Host: www.mynginx.com"  http://47.241.211.60

重复执行以上命令,可以看到仅50%的流量路由到新版本服务。
基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布_第6张图片
系统运行一段时间后,当新版本服务已经稳定并且符合预期后,需要下线老版本的服务 ,仅保留新版本服务在线上运行。(删除ingress的老服务的配置)
cat ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nginx
spec:
  rules:
  - host: www.mynginx.com
    http:
      paths:
      # 新版本服务
      - path: /
        backend:
          service: 
            name: nginx-v2
            port:
              number: 80
        pathType: ImplementationSpecific

你可能感兴趣的:(k8s,运维,docker,kubernetes)