Istio 实现灰度发布

一、部署bookinfo微服务示例

mark

Bookinfo 应用分为四个单独的微服务: - productpage : productpage 微服务会调用 details 和 reviews 两个微服务,用来生成页面。 - details :这个微服务包含了书籍的信息。 - reviews :这个微服务包含了书籍相关的评论。它还会调用ratings 微服务。 - ratings : ratings 微服务中包含了由书籍评价组成的评级信息。

reviews 微服务有 3 个版本: - v1 版本不会调用 ratings 服务。 - v2 版本会调用 ratings 服务,并使用 5个黑色五角星来显示评分信息。 - v3 版本会调用 ratings 服务,并使用5个红色五角星 来显示评分信息。

1.1、部署

kubectl create ns bookinfo

kubectl label namespace bookinfo istio-injection=enabled    # 针对命名空间注入

cd istio-1.4.2/samples/bookinfo

kubectl apply -f platform/kube/bookinfo.yaml -n bookinfo

kubectl get pod -n bookinfo     # 等待正常启动后会有2个pod(一个服务,一个sidecar的注入)

kubectl apply -f networking/bookinfo-gateway.yaml -n bookinfo       # 两个服务Gateway和VirtualService

访问地址: http://192.168.171.12:32217/productpage

mark

一旦部署完毕,刷新前端就可以看到3个版本是一直在轮训被展示的!

为了模拟现实工作的场景,我这边nginx的虚机IP是:192.168.171.10

nginx.conf

    upstream ingressgateway {
          server 192.168.171.12:32217;
          server 192.168.171.13:32217;
}

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
                proxy_pass http://ingressgateway;
                proxy_set_header Host $Host;    # 使用请求头来分流
                proxy_http_version 1.1;     # nginx默认是1.0
        }

mark
mark
mark
mark

如上这种方式虽然是都可以访问,但是不是我们最终的目的,必须要实现不同的域名访问不同的后端;

更改httbin这个服务的http-gateway.yaml

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
  - "httpbin.zhdya.cn"      # * 修改为域名
同理修改bookinfo的bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "bookinfo.zhdya.cn"
修改好之后 再次应用下
kubectl apply -f bookinfo-gateway.yaml -n bookinfo
kubectl apply -f http-gateway.yaml

再次访问就实现了httpbin访问的就是httpbin应用,bookinfo同理;

二、发布方案

主流发布方案: - 蓝绿发布 - 滚动发布 - 灰度发布(金丝雀发布) - A/B Test

2.1、蓝绿发布(早期用的比较广泛)

项目逻辑上分为AB组,在项目升级时,首先把A组从负载均衡中摘除,进行新版本的部署。 B组仍然继续提供服务。 A组升级完成上线, B组从负载均衡中摘除。

特点: - 策略简单 - 升级/回滚速度快 - 用户无感知,平滑过渡

缺点: - 需要 两倍以上服务器资源 - 短时间内浪费一定资源成本 - 故障影响范围大

mark

2.2、滚动发布(K8S默认更新策略)

每次只升级一个或多个服务,升级完成后加入生产环境,不断执行这个过程,直到集群中的全部旧版升级新版本。 Kubernetes的默认发布策略。

特点: - 用户无感知,平滑过渡

缺点: - 部署周期长 - 发布策略较复杂 - 不易回滚

mark

2.3、灰度发布(金丝雀发布)<当前主流方式>

只升级部分服务,即让一部分用户继续用老版本,一部分用户开始用新版本,如果用户对新版本没有什么意见,那么逐步扩大范围,把所有用户都迁移到新版本上面来。

特点: - 保证整体系统稳定性 - 用户无感知,平滑过渡

缺点: - 自动化要求高

mark

2.4、A/B Test(灰度发布的一种)

灰度发布的一种方式,主要对特定用户采样后,对收集到的反馈数据做相关对比,然后根据比对结果作出决策。用来测试应用功能表现的方法,侧重应用的可用性,受欢迎程度等, 最后决定是否升级。

mark

三、Istio实现灰度发布

3.1、基于权重的路由(灰度发布)

需求

1、流量全部发送到reviews v1版本(不带五角星); # virtual-service-all-v1.yaml

mark
cat networking/virtual-service-all-v1.yaml
···省略
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews     # 后端的svc
  http:
  - route:
    - destination:  # 流量的转发
        host: reviews
        subset: v1
···省略

kubectl apply -f networking/virtual-service-all-v1.yaml -n bookinfo

------------

cat networking/destination-rule-all.yaml
···省略
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1   # 选择的标签是v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
···省略

kubectl apply -f networking/destination-rule-all.yaml -n bookinfo

再来看下,刚刚我们线上部署了3套不同版本的应用:
cat platform/kube/bookinfo.yaml
···省略
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-reviews
  labels:
    account: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
···省略

再次刷新前端页面就会发现,所有的流量一直停留在V1版本!
-----------------

2、将90%的流量发送到reviewsv1版本,另外10%的流量发送到reviewsv2版本(5个黑色五角星),最后完全切换到v2版本。

# cat networking/virtual-service-reviews-90-10.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 90    # 90%权重
    - destination:
        host: reviews
        subset: v2
      weight: 10


kubectl apply -f networking/virtual-service-reviews-90-10.yaml -n bookinfo

3、将50%的流量发送到v2版本,另外50%的流量发送到v3版本(5个红色五角星)。

# cat networking/virtual-service-reviews-v2-v3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50


kubectl apply -f networking/virtual-service-reviews-v2-v3.yaml -n bookinfo


假如测试没有任何问题,这样我们就可以通过权重调整全部切为V3版本

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
      weight: 0
    - destination:
        host: reviews
        subset: v3
      weight: 100

或者一旦有任何异常,我们可以通过权重直接修改,apply即可!

3.2、基于请求内容的路由(A/B Test)

需求: 1. 将特定用户的请求发送到reviews v2版本(5个黑色五角星),其他用户则不受影响(v3)

mark
# cat networking/virtual-service-reviews-jason-v2-v3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason      # 只要是jason这个用户登录就会显示V2版本,其余均是V3版本
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v3

# kubectl apply -f networking/virtual-service-reviews-jason-v2-v3.yaml -n bookinfo
mark
mark

四、总结

实现灰度发布: - 引入服务版本标签(version:v3); - 使用deployment部署,pod标签加上version; - 创建istio资源; - 创建一个灰度版本,version; - 创建DestinationRule规则,关联所有版本(在用版本和灰度版本); - 创建VirtualService规则,路由策略(请求内容,百分比?)

mark

之所以没有被大量应用的主要原因,就是人工修改量太大,误操作概率高,如果把如上全部自动化后,我相信这简直就是和K8S的珠联璧合!!