Istio 灰度发布

金丝雀发布也被称为灰度发布,实际上就是将少量的生产流量路由到线上服务的新版本中,以验证新版本的准确性和稳定性。

Istio和 Kubernetes 实现金丝雀发布的方式不太一样,Istio 通过 Envoy 强大的路由规则管理能力,可以灵活地控制对应版本的流量百分比。通过创建其它的路由规则实现灰度,比如根据 header 中标记的特定用户进行流量路由。

用户访问 productpage 的请求,内部流量会分别路由到 reviews-v1 和 v2 两个版本。

查看 Pod,也可以看到 reviews 这个服务一共启动了三个版本:

kubectl get pods
NAME                               READY   STATUS            RESTARTS   AGE
details-v1-b87bfc85d-nd8v7         2/2     Running           0          2m12s
productpage-v1-65576bb7bf-hj6mw    1/2     Running           0          2m11s
ratings-v1-645b477958-gtrqd        0/2     PodInitializing   0          2m12s
reviews-v1-987d495c-2x5rh          2/2     Running           0          2m12s
reviews-v2-6c5bf657cf-t66hz        2/2     Running           0          2m12s
reviews-v3-5f7b9f4f77-gcrsj        2/2     Running           0          2m12s

通过查看 samples/bookinfo/platform/kube/bookinfo.yaml 的部署配置文件,可以看到:有三个 reviews 服务的部署类型资源,通过配置不同的 labels,可以让同一个服务的三个部署资源同时存在。

这三个部署资源的服务镜像指向了三个不同的地址,分别是 examples-bookinfo-reviews-v1:1.16.2、examples-bookinfo-reviews-v2:1.16.2 和 examples-bookinfo-reviews-v3:1.16.2:

---
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.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
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.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
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.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}

通过上面的请求结果,Istio 确实将流量路由到了不同的 reviews 版本上,但是这里还没有对 Istio 的路由规则做特殊配置,所以这里的流量是均分的,也可以理解为和 Kubernetes 的版本灰度策略是一致的。

下面创建一个 reviews 的路由规则,为了方便验证,这个配置将所有流量指向 reviews 的 v1 版本:

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reivews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
EOF

下面再做出一些改动,修改 Istio 路由配置,将 90% 的流量指向 v1 版本,10% 的流量指向 v2 版本,以达到最开始的需求——精准流量的金丝雀发布:

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reivews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 90
    - destination:
        host: reviews
        subset: v2
      weight: 10
EOF

成功执行上述命令,反复刷新 productpage 页面,可以发现大概有 10% 的流量被路由到了新的 reviews v2 版本。

在现实场景中,可以根据需求灵活地设置 reviews v1 版本和 v2 版本的流量比例,比如设置 v2 版本流量比例为 1%,用于金丝雀发布,这样的方式相较于 Kubernetes 启动 100 个 pod 进行金丝雀发布,要灵活得多。

在金丝雀发布的过程中,通过不断增加 v2 的流量比例达到精准流量灰度发布的目的,配合 Metrics 监控指标,可以随时自动调整 v2 的比例,以减少新版本出问题时对生产环境的影响。随着 v2 版本的流量不断增大,最终彻底替代 v1 版本成为线上正式版本,整个金丝雀发布也就结束了。

当然需要注意的是,在整个过程中应该灵活调整 v1 和 v2 版本的 Kubernetes 副本数量,或者配合 Kubernetes 的 HPA,以达到自动扩缩容的目的:

$ kubectl autoscale deployment reviews-v1 --cpu-percent=50 --min=1 --max=10
$ kubectl autoscale deployment reviews-v2 --cpu-percent=50 --min=1 --max=10

Istio 灰度测试

Istio 中另一个强大的功能:针对 header 设置路由策略,以达到金丝雀测试的目的。简单来说,就是针对不同用户或不同的客户端版本(针对测试人员单独发布的测试版本),进行精准的流量路由。

首先创建一个 VirtualService 配置,将登录用户名为 testuser 的用户指向测试版本 v2 和 v3,其中 v3 流量占比 90%,v2 流量占比 10%。这个版本专门用于 testuser 的测试人员进行新版本的测试,其他登录用户全部路由到 v1 版本:

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: testuser
    route:
    - destination:
        host: reviews
        subset: v2
      weight: 10
    - destination:
        host: reviews
        subset: v3
      weight: 90
  - route:
    - destination:
        host: reviews
        subset: v1
EOF

执行成功后,反复访问 productpage 页面,发现流量大部分都路由到了 v3 版本,少量流量路由到了 v2 版本。

 

posted @ 2023-01-19 10:01  muzinan110  阅读(297)  评论(0编辑  收藏  举报