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 版本。