基于istio的灰度发布实验

简介: 灰度发布又叫A/B测试,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。因为最近刚好有灰度发布的需求,我又学了一遍istio,记录了本次灰度发布的实施过程(只包括应用,不包括数据库升级)

背景

灰度发布又叫A/B测试,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。

因为最近刚好有灰度发布的需求,我又学了一遍istio,记录了本次灰度发布的实施过程(只包括应用,不包括数据库升级)


实验过程

  1. 先确定目前的应用版本为V1
  2. 通过helm包部署应用版本为V2的pod到K8S集群中
  3. 确定V2版本灰度的用户,方法包括IP,或者特定用户
  4. 通过istio的virtualservice功能把特定用户的流量指向V2版本
  5. 检查特定用户使用一段时间后,是否出现问题
  6. 若无问题,通过istio将所有用户的流量都指向V2版本
  7. 若所有用户都使用V2无问题,删除掉V1版本的pod

示例介绍

前端应用frontend,后端应用mqtt-server,后端应用mqtt-server 通过mqtt协议与设备相连接。

前端部署3个版本,分别是V1,V2,V3,后端同样部署3个版本,也是V1,V2,V3。3个前端版本,按钮文字不一样。3个后端版本,连接的mqtt设备不一样

版本 前端页面 后端返回参数
V1 显示V11按钮
{"message":["wsytest010","wsytest002", "wsytest003","wsytest007","wsytest006", "wsytest001","wsytest005","wsytest009", "wsytest008","wsytest004"]}
V2 显示V22按钮
{"message":["wsytest019","wsytest020", "wsytest017","wsytest012","wsytest011", "wsytest014","wsytest018","wsytest015", "wsytest013","wsytest016"]}
V3 显示V33按钮
{"message":["wsytest024","wsytest028", "wsytest022","wsytest026","wsytest027", "wsytest021","wsytest025","wsytest030", "wsytest023","wsytest029"]}

v1-Image-12.pngImage-13-4.png根据需求,版本不能串,比如前端V1->后端V1,不允许出现前端V1→后端V2这样的情况发生

Image-3-3.pngImage-5-1.png这里我们在选择分配流量方式时,不能使用权重的方式进行分配,只能选择指定用户或者指定IP,如果选择权重的方式,可能会出现如下的问题:

前端会访问多个js,css等文件,如果使用权重的方式,会出现一部分js来源于v1版本,一部分css来源于v2版本。

后端也同理,如果一个页面打开时,触发多个后端请求,部分来源于V2,部分来源于V1,肯定会导致前端显示出现问题。

所以只有把前后端通过某种方式一一对应,才能正常使用Image-6-1-1024x532.png


代码实现与注意事项

1.部署前端的3个应用程序,所有的pod都加上 labels:[app:frontend,version:#{对应版本}]

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  labels:
    app: frontend
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
      version: v1
  template:
    metadata:
      labels:
        app: frontend
        version: v1
    spec:
      containers:
      - name: frontend
        image: 前端镜像:v1
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]    # 按照istio的说明,最好把这个pod安全策略加上
        imagePullPolicy: Always
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v2
  labels:
    app: frontend
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
      version: v2
  template:
    metadata:
      labels:
        app: frontend
        version: v2
    spec:
      containers:
      - name: frontend
        image: 前端镜像:v2
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        imagePullPolicy: Always
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v3
  labels:
    app: frontend
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
      version: v3
  template:
    metadata:
      labels:
        app: frontend
        version: v3
    spec:
      containers:
      - name: frontend
        image: 前端镜像:v3
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        imagePullPolicy: Always
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  selector:
    app: frontend
  type: ClusterIP   #这个不用NodePort,因为流量如果是从NodePort进来的,就控不住的
  ports:
    - port: 80
      targetPort: 80
      name: http-web

2.部署后端应用程序,与前端应用类似

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mqtt-server-v1
  labels:
    app: mqtt-server
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mqtt-server
      version: v1
  template:
    metadata:
      labels:
        app: mqtt-server
        version: v1
    spec:
      serviceAccountName: mqtt-server
      containers:
      - name: mqtt-server
        image: 后端镜像:latest
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]    # 按照istio的说明,最好把这个pod安全策略加上
        imagePullPolicy: Always
        ports:
        - containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mqtt-server-v2
  labels:
    app: mqtt-server
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mqtt-server
      version: v2
  template:
    metadata:
      labels:
        app: mqtt-server
        version: v2
    spec:
      serviceAccountName: mqtt-server
      containers:
      - name: mqtt-server
        image: 后端镜像:latest
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        imagePullPolicy: Always
        ports:
        - containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mqtt-server-v3
  labels:
    app: mqtt-server
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mqtt-server
      version: v3
  template:
    metadata:
      labels:
        app: mqtt-server
        version: v3
    spec:
      serviceAccountName: mqtt-server
      containers:
      - name: mqtt-server
        image: 后端镜像:latest
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        imagePullPolicy: Always
        ports:
        - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: mqtt-server
spec:
  selector:
    app: mqtt-server
  type: NodePort   #这个不用NodePort,因为流量如果是从NodePort进来的,就控不住的
  ports:
    - port: 8000
      targetPort: 8000
      name: http-web

3.区分外部流量和内部流量。我们将浏览器到前端的称为外部流量,K8S里的例如前端到后端的称为内部流量Image-24.png4.外部流量出去,需要被istio的ingress gateway管控起来,所以需要配置一个gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

5.配置后端的virtualservice和destination,确保后端程序能与前端程序产生一对一的关系,在无对应关系时,默认使用V1版本

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: mqtt-server-internal
spec:
  hosts:
  - "mqtt-server"     #此处是关键,把匹配到该url的流量,全部走到这个特定的virtualservice里
  http:
  - match:
    - sourceLabels:
        version: v1
    route:
    - destination:
        host: mqtt-server
        subset: v1             # 将匹配到的流量,转向subset的v1版本,这个subset: v1在destination.yaml里定义
      headers:
        response:
          add:
            user: v1
  - match:
    - sourceLabels:
        version: v2
    route:
    - destination:
        host: mqtt-server
        subset: v2
      headers:
        response:
          add:
            user: v2
  - match:
    - sourceLabels:
        version: v3
    route:
    - destination:
        host: mqtt-server
        subset: v3
      headers:
        response:
          add:
            user: v3
  - route:
    - destination:
        host: mqtt-server
        subset: v1
      headers:
        response:
          add:
            user: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: mqtt-server
spec:
  host: mqtt-server.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      version: v1    # 根据pod的 version: v1 的label来进行匹配
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3

6.配置前端的virtualservice和destination,我们可以设置来源于192.168.0.58这个IP的走V2版本,其余IP走V1版本

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: frontend-server
spec:
  hosts:
  - "外网域名"     #此处是关键,把匹配到该url的流量,全部走到这个特定的virtualservice里
  gateways:
  - bookinfo-gateway              #此处必须对应上gateway的名字
  http:
  - match:
    - headers:
      X-Forwarded-For:
          exact: "192.168.0.58"            #此处表示匹配header里有{"user":"v1"}
    route:
    - destination:
        host: mqtt-server
        subset: v2             # 将匹配到的流量,转向subset的v1版本,这个subset: v1在destination.yaml里定义
      headers:
        response:
          add:
            user: v2
  - route:
    - destination:
        host: frontend
        subset: v1             # 将匹配到的流量,转向subset的v1版本,这个subset: v1在destination.yaml里定义
      headers:
        response:
          add:
            user: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: frontend
spec:
  host: frontend
  subsets:
  - name: v1
    labels:
      version: v1    # 根据pod的 version: v1 的label来进行匹配
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3

7.因为我们的浏览器访问的时候,会经过istio,所以前端收到的IP并不是真是的IP,我们需要修改istio的ingress文件,把spec.externalTrafficPolicy设置成Local,如下图所示Image-25.png8.最终情况Image-26-1024x231.png

实验效果图

1.当本机IP地址不符合条件时,前端和后端都是V1版本的结果,第一张图是实际效果,第二张图是kiali显示的流量图Image-15-2.pngImage-18-2-1024x529.png2.当本机IP符合条件时,前端和后端都是V2版本的结果,左图是实际效果,右图是kiali显示的流量图Image-20-1.pngImage-19-1.png3.当同时有满足IP和不满足IP条件的机器访问时,流量图效果如下Image-21-1-1024x695.png

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
测试技术 开发者
KubeVela 对接 Istio 实现应用灰度发布实践|学习笔记(二)
快速学习 KubeVela 对接 Istio 实现应用灰度发布实践
362 0
KubeVela 对接 Istio 实现应用灰度发布实践|学习笔记(二)
|
Prometheus 监控 Kubernetes
进阶:对接 Istio 实现应用灰度发布实践| 学习笔记
快速学习进阶:对接 Istio 实现应用灰度发布实践。
150 0
进阶:对接  Istio 实现应用灰度发布实践| 学习笔记
|
设计模式 Kubernetes Cloud Native
干货分享|使用 Istio 实现灰度发布
Kubernetes 作为基础平台,提供了强大的容器编排能力。但是在其上部署业务和服务治理上,仍然会面对一些复杂性和局限性。在服务治理上,已经有许多成熟的 ServiceMesh 框架用于扩充其能力,如 Istio、Linkerd、Dapr 等。本文将主要介绍如何使用 Istio 扩充 Kubernetes 灰度发布的能力。
|
Kubernetes 监控 网络协议
Istio:灰度发布与技术实现
Istio:灰度发布与技术实现
631 0
Istio:灰度发布与技术实现
|
存储 Kubernetes Dubbo
基于 Istio 的全链路灰度方案探索和实践
本文介绍的基于“流量打标”和“按标路由” 能力是一个通用方案,基于此可以较好地解决测试环境治理、线上全链路灰度发布等相关问题,基于服务网格技术做到与开发语言无关。同时,该方案适应于不同的7层协议,当前已支持 HTTP/gRpc 和 Dubbo 协议。
基于 Istio 的全链路灰度方案探索和实践
|
存储 Kubernetes Dubbo
基于Istio 的全链路灰度方案探索和实践
# 背景 微服务软件架构下,业务新功能上线前搭建完整的一套测试系统进行验证是相当费人费时的事,随着所拆分出微服务数量的不断增大其难度也俞大。这一整套测试系统所需付出的机器成本往往也不低,为了保证应用新版本上线前的功能正确性验证效率这套系统还必须一直单独维护好。当业务变得庞大且复杂时,往往还得准备多套,这是整个行业共同面临且难解的成本和效率挑战。如果能在同一套生产系统中完成新版本上线前的功能验证的
854 1
基于Istio 的全链路灰度方案探索和实践
|
负载均衡 Kubernetes 监控
Istio,灰度发布从未如此轻松!!!
ServiceMesh解决什么问题?
643 0
Istio,灰度发布从未如此轻松!!!
|
Kubernetes 测试技术 微服务
Istio流量管理实践之(2): 通过Istio管理应用的灰度发布
Istio 服务网格提供了管理流量分配所需的基础控制,并完全独立于AutoScaler,从而允许简单而强大的方式来进行诸如金丝雀、蓝绿、AB测试和上线。
4086 0
|
6月前
|
Kubernetes 监控 Go
在Kubernetes上安装和配置Istio:逐步指南,展示如何在Kubernetes集群中安装和配置Istio服务网格
在Kubernetes上安装和配置Istio:逐步指南,展示如何在Kubernetes集群中安装和配置Istio服务网格
84 0
|
6月前
|
存储 Kubernetes 负载均衡
【Kubernetes的Service Mesh发展历程及Istio架构、存储供应使用NFS flexvolume CSI接口】
【Kubernetes的Service Mesh发展历程及Istio架构、存储供应使用NFS flexvolume CSI接口】