乐趣区

关于java:你知道什么叫金丝雀分布吗你知道如何在Service-Mesh微服务架构中实现吗

什么是金丝雀公布

既然要聊具体的实现,那么在开始之前,先科普下什么是“金丝雀公布”。金丝雀公布也叫“灰度公布”,具体来说就是在公布线上版本时,先将大量的生产流量打到服务的新版本,以验证新版本的准确性和可靠性,待发布的新版本失去线上流量的全面验证后,在逐渐将所有流量放入新版本,以实现生产服务版本的稳固更新。

为什么叫金丝雀公布呢,是因为金丝雀对矿场中的毒气比拟敏感,所以在矿场动工前工人们会放一只金丝雀进去,以验证矿场是否存在毒气,这便是金丝雀公布名称的由来。

在不同技术栈场景中,金丝雀公布的实现形式也不尽相同:有通过 nginx 实现的、也有借助 A/ B 测试 实现的。而随着以 Kubernetes 为代表的云原生基础设施的遍及,金丝雀公布作为一项根本的服务公布性能,其实现形式也有了一些新的趋势——那就是逐渐与云原生基础设施融为一体,成为基础设施服务的一部分。

Kubernetes 中的金丝雀(灰度)公布

接下来,先看看在 Kubernetes 中是如何实现版本更新的。以下内容假如你曾经有了一套可用的 Kubernetes 环境,如果没有能够查看文末举荐浏览的文章链接,参考相干分享自行部署。

1. 滚动更新

在介绍 Kubernetes 中的金丝雀(灰度)公布之前,先来理解下 Kubernetes 中最重要的利用部署形式——“滚动降级”

所谓“滚动降级 ”:是指当更新了 Kubernetes 中 Deployment 编排资源的 Pod 模版(例如更新镜像版本号)之后,Deployment 就须要遵循一种叫做“滚动更新(rolling update)” 的形式,来降级现有的容器,从而实现利用对外服务的“不中断更新部署”。Kubernetes 实现“滚动降级”的示意图如下:

如上图所示,滚动降级的过程为:

1)当容器开始降级时,集群中会先启动一个新版本的 Pod,并终止一个旧版本的 Pod。

2)如果此时,新版本的 Pod 有问题启动不了,那么“滚动降级”就会进行,并容许开发和运维人员染指。而在这个过程中,因为利用自身还有两个旧版本的 Pod 在线,所以服务并不会受到太大的影响。

3)而如果新版本的 Pod 启动胜利,且服务拜访失常,则持续滚动降级,直至依照 Deployment 编排器设置的正本数量,实现后续旧版本 Pod 的降级。

在 Kubernetes 中 Deployment 还能够通过相应地“滚动降级”策略,来管制 Pod 的滚动降级行为,以进一步保障服务的连续性。例如:“在任何工夫窗口内,只有指定比例的 Pod 处于离线状态;在任何工夫窗口内,只有指定比例的新 Pod 被创立进去“。能够通过相应地控制参数进行设置,如下:

...
spec:
  selector:
    matchLabels:
      app: micro-api
  replicas: 3
  #设置滚动降级策略
  #Kubernetes 在期待设置的工夫后才开始进行降级,例如 5 秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #降级过程中最多能够比原先设置多出的 Pod 数量
      maxSurge: 1
      #降级过程中 Deployment 控制器最多能够删除多少个旧 Pod,次要用于提供缓冲工夫
      maxUnavailable: 1
...

在下面 RollingUpdate Strategy(滚动降级策略)的配置中:

  • maxSurge:指定的是,除了设定的 Pod 正本数量之外,在一次“滚动”中,Deployment 控制器还能够创立多少个新的 Pod。
  • maxUnavailable:指的是,在一次“滚动”中,Deployment 控制器能够删除多少个旧 Pod。

通过这种准确的“滚动降级”策略,能够使得 Kubernetes 服务版本公布的过程更加平滑。此外,这两个配置还能够通过百分比的形式来示意,比方 “maxUnavailable=50%”, 指的是 Deployment 控制器最多能够一次删除“50%* 设定 Pod 正本数”个 Pod。

接下来具体演示下在 Kubernetes 中进行服务滚动降级的具体过程。

应用的示例代码阐明:

我的项目以 Spring Boot 编写的 Java 服务为主,在体验上更靠近实在的我的项目开发场景。我的项目的构造如下:

该我的项目所在的 GitHub 地址为:

https://github.com/manongwudi/istio-micro-service-demo

“滚动降级”演示:

这里先借助示例我的项目中的“micro-api”服务来演示其在 Kubernetes 中进行“滚动降级”的过程,步骤如下:

(1)首先筹备“micro-api”服务的 k8s 公布文件(如:micro-api.yaml)。代码如下:

apiVersion: v1
kind: Service
metadata:
  name: micro-api
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 19090
      targetPort: 9090
  selector:
    app: micro-api

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-api
spec:
  selector:
    matchLabels:
      app: micro-api
  replicas: 3
  #设置滚动降级策略
  #Kubernetes 在期待设置的工夫后才开始进行降级,例如 5 秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #降级过程中最多能够比原先设置多出的 Pod 数量
      maxSurge: 1
      #降级过程中 Deployment 控制器最多能够删除多少个旧 Pod
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: micro-api
    spec:
      #设置的阿里云公有镜像仓库登陆信息的 secret(对应 2.1.2 的设置)
      imagePullSecrets:
        - name: regcred
      containers:
        - name: micro-api
          image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.0-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19090

上述部署文件设置了“micro-api”服务的 Pod 正本个数为“3”,并且设置了相应地滚动降级策略。

(2)接下来执行 k8s 部署命令如下:

$ kubectl apply -f micro-api.yaml 

胜利后,查看 Deployment 创立后的状态信息,命令成果如下:

$ kubectl get deployments
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
micro-api     3/3     3            3           190d

从上述命令的返回后果中,能够看到三个状态字段,它们的含意如下所示:

  • READY:示意用户冀望的 Pod 正本个数,以及以后处于 Running 状态的 Pod 个数。
  • UP-TO-DATE:以后处于最新版本的 Pod 个数。所谓最新版本,指的是 Pod 的 Spec 局部与 Deployment 中 Pod 模版里定义的完全一致。
  • AVAILABLE:以后曾经可用的 Pod 的个数——既是 Running 状态,又是最新版本,并且曾经处于 Ready(监控查看正确)状态的 Pod 个数。

(3)模仿服务版本升级,触发滚动降级。

接下来从新构建“micro-api”服务的版本,并将其上传至公有镜像仓库。之后,通过命令批改“micro-api”的 Deployment 所应用的镜像,并触发滚动降级。

批改 Deployment 所应用的镜像的命令如下:

$ kubectl set image deployment/micro-api micro-api=registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.1-SNAPSHOT
deployment.apps/micro-api image updated

这里应用了“kubectl set image”指令,次要是为了不便操作,也能够间接在 k8s 部署文件中进行镜像版本的批改。

批改完 Deployment 的镜像版本后,Kubernetes 会立刻触发“滚动降级”的过程。能够通过“kubectl rollout status”指令来查看 Deployment 资源的状态变动。具体如下:

$ kubectl rollout status deployment/micro-api

Waiting for deployment "micro-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "micro-api" rollout to finish: 2 out of 3 new replicas have been updated...

Waiting for deployment "micro-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "micro-api" rollout to finish: 2 of 3 updated replicas are available...
Waiting for deployment "micro-api" rollout to finish: 2 of 3 updated replicas are available...
deployment "micro-api" successfully rolled out

这时,也能够通过查看 Deployment 的 Events,看到这个“滚动降级”的过程。具体如下:

$ kubectl describe deployment micro-api
...
OldReplicaSets:  <none>
NewReplicaSet:   micro-api-d745d8649 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  12m   deployment-controller  Scaled up replica set micro-api-677dd4d5b6 to 1
  Normal  ScalingReplicaSet  12m   deployment-controller  Scaled down replica set micro-api-57c7cb5b74 to 2
  Normal  ScalingReplicaSet  12m   deployment-controller  Scaled up replica set micro-api-677dd4d5b6 to 2
  Normal  ScalingReplicaSet  5m1s  deployment-controller  Scaled down replica set micro-api-677dd4d5b6 to 0
  Normal  ScalingReplicaSet  5m    deployment-controller  Scaled up replica set micro-api-d745d8649 to 2
  Normal  ScalingReplicaSet  56s   deployment-controller  Scaled down replica set micro-api-57c7cb5b74 to 0
  Normal  ScalingReplicaSet  56s   deployment-controller  Scaled up replica set micro-api-d745d8649 to 3

能够看到,当你批改了 Deployment 里的 Pod 定义后,”Deployment Controller” 会应用这个批改后的 Pod 模版,创立一个新的 ReplicaSet,这个新的 ReplicaSet 的初始 Pod 正本数是:0。

而后在 Age=12 m 的地位,开始将这个新的 ReplicaSet 所管制的 Pod 正本数从 0 个变成 1 个。

紧接着,在 Age=12 m 的地位,又将旧 ReplicaSet 所管制的 Pod 正本数缩小 1 个,即“程度膨胀”成两个正本。

如此交替进行,新 ReplicaSet 所治理的 Pod 的正本数,从 0 个变成 1 个,再变成 2 个,最初变成 3 个;而旧 ReplicaSet 所治理的 Pod 的正本数则从 3 个变成 2 个,最初变成 0 个。

这样,就实现了一组 Pod 的版本升级过程。而像这样 将一个 Kubernetes 集群中正在运行的多个 Pod 版本,交替逐个降级的过程,就是“滚动降级”。

2. 金丝雀(灰度)公布

后面“1.”小标题中,比拟具体的演示了 Kubernetes 的“滚动降级”的形式,尽管通过滚动降级的形式能够不便、平滑的实现版本更新,然而这个过程,并没有灰度性能 。滚动降级的形式,尽管两头有缓冲交替的过程,但 这种过程是主动的、迅速的,滚动降级过程完结就相当于间接进行了新版本的全量公布

而对于须要进行金丝雀(灰度)公布的场景,“滚动降级”的形式很显然是不够用的。那么,在 Kubernetes 中应该如何联合版本更新做到金丝雀(灰度)公布呢?

具体步骤如下:

(1)编写实现新版本灰度公布的部署文件。

为了实现在 Kubernetes 中的金丝雀(灰度)公布过程的可观测,咱们从新定义下具体的 k8s 公布文件(如:micro-api-canary.yaml)的内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-api
spec:
  selector:
    matchLabels:
      app: micro-api
  replicas: 3
  #设置滚动降级策略
  #Kubernetes 在期待设置的工夫后才开始进行降级,例如 5 秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #降级过程中最多能够比原先设置多出的 Pod 数量
      maxSurge: 1
      #降级过程中 Deployment 控制器最多能够删除多少个旧 Pod,次要用于提供缓冲工夫
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: micro-api
        #减少新的标签(演示 k8s 的灰度公布)track: canary
    spec:
      #设置的阿里云公有镜像仓库登陆信息的 secret(对应 2.1.2 的设置)
      imagePullSecrets:
        - name: regcred
      containers:
        - name: micro-api
          image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.3-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19090

上述公布文件与“1.”小标题中演示滚动降级时,公布文件的内容统一,只是 为了不便察看灰度公布过程的实现,这里通过“track: canary”对新公布的 Pod 版本进行标记。

设置新版本的镜像为:“micro-api:1.3-SNAPSHOT”。并且通过spec.selector.matchLabels.app:micro-api”与历史版本 Pod 所对应的 Service(micro-api.yaml 文件中定义的 Service)资源定义匹配。

(2)执行 ” 滚动降级 ” 发布命令,实现“灰度公布”成果。

$ kubectl apply -f micro-api-canary.yaml && kubectl rollout pause deployment/micro-api

下面通过 “kubectl rollout pause” 命令实现对 Deployment 的金丝雀(灰度公布)。执行发布命令之后的运行成果如下:

$ kubectl get pods --show-labels -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP          NODE         NOMINATED NODE   READINESS GATES   LABELS
micro-api-57c7cb5b74-mq7m9   1/1     Running   0          6m20s   10.32.0.3   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=57c7cb5b74
micro-api-57c7cb5b74-ptptj   1/1     Running   0          6m20s   10.32.0.4   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=57c7cb5b74
micro-api-7dbb6c5d66-4rbdc   1/1     Running   0          5m33s   10.32.0.6   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=7dbb6c5d66,track=canary
micro-api-7dbb6c5d66-cfk9l   1/1     Running   0          5m33s   10.32.0.5   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=7dbb6c5d66,track=canary

查看 Deployment 的滚动降级状况,命令如下:

$ kubectl get deployments
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
micro-api       4/3     2            4           194d

能够看到此时“micro-api”ready 的数量为 4,其中两个旧版本 Pod,两个新版本 Pod。

(3)接下来进行流量测试。

查问两组 Pod 版本所对应的 Service 资源的 IP,命令如下:

# kubectl get svc micro-api
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
micro-api   ClusterIP   10.110.169.161   <none>        19090/TCP   194d

接下来,模仿对服务的接口进行批量拜访,命令如下:

$ for i in {1..10}; do curl 10.110.169.161:19090/test/test; done

{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}

能够看到,此时流量会随机的流向旧版本和新版本(日志标记为 V3)的服务。

(4)将服务版本升级为新版本。

如果新版本的服务通过线上流量测试验证没有问题,则能够通过 “rollout resume” 命令将整体服务的版本升级为新版本。命令如下:

$ kubectl rollout resume deployment micro-api
deployment.apps/micro-api resumed

降级后的成果如下:

$ kubectl get pods --show-labels -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP          NODE         NOMINATED NODE   READINESS GATES   LABELS
micro-api-7dbb6c5d66-4rbdc   1/1     Running   0          18m   10.32.0.6   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=7dbb6c5d66,track=canary
micro-api-7dbb6c5d66-bpjtg   1/1     Running   0          84s   10.32.0.3   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=7dbb6c5d66,track=canary
micro-api-7dbb6c5d66-cfk9l   1/1     Running   0          18m   10.32.0.5   kubernetes   <none>           <none>            app=micro-api,pod-template-hash=7dbb6c5d66,track=canary

能够看到,此时指标服务曾经通过“滚动降级”的形式实现了全量更新。而如果存在问题,则通过“kubectl rollout undo”命令进行回滚即可!

从上述过程能够看到,Kubernetes 中的金丝雀(灰度公布)次要是通过操纵(如:pause)“滚动降级”的过程来实现的——通过公布肯定数量的新版本 Pod,并利用 Service 资源类型自身的负载平衡能力来实现流量在新 / 旧 Pod 之间的随机交替。

这样的形式尽管曾经能够满足一些简略的场景,然而没有方法做到 更精准的灰度流量管制。这时候就须要借助 Service Mesh 中的解决方案了,上面咱们来看看在 Istio 中如何做到精准流量的金丝雀(灰度)公布。

Istio 中的金丝雀(灰度)公布

Istio 与 Kubernetes 实现金丝雀(灰度)公布的形式不一样,Istio 通过 Envoy(SideCar)弱小的路由规定治理能力,能够非常灵活地管制对应版本的流量占比,从而实现具备精准流量控制能力的金丝雀(灰度)公布性能。

Istio 通过 Envoy(SideCar)实现金丝雀(灰度)公布的流量路由示意图如下(持续以“micro-api”服务为例):

从上图中能够大抵看出,Istio 具备弱小的流量治理能力,而这种能力对于实现流量精准管制的金丝雀(灰度)公布性能来说,天然是瓜熟蒂落的。

具体来说,在 Istio 中是通过 VirtualService(虚构服务) 这种特定的资源在服务网格中实现流量路由的。通过 VirtualService 能够不便地定义流量路由规定,并在客户端试图连贯到服务时利用这些规定,并最终达到指标服务。

接下来,具体演示如何在 Istio 中通过 VirtualService 实现金丝雀(灰度)公布。步骤如下:

(1)首先公布一个 v1 版本的服务。

要在 Istio 中实现更精准的版本控制,须要在公布 Pod 资源时,通过明确的 “版本标签” 进行指定。筹备“micro-api”服务 v1 版本的 k8s 部署文件(micro-api-canary-istio-v1.yaml):

apiVersion: v1
kind: Service
metadata:
  name: micro-api
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 19090
      targetPort: 9090
  selector:
    app: micro-api

---

apiVersion: apps/v1
kind: Deployment
meta data:
  name: micro-api-v1
spec:
  selector:
    matchLabels:
      app: micro-api
      #这里是要害,须要设置版本标签,以便实现灰度公布
      version: v1
  replicas: 3
  #设置滚动降级策略
  #Kubernetes 在期待设置的工夫后才开始进行降级,例如 5 秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #降级过程中最多能够比原先设置多出的 Pod 数量
      maxSurge: 1
      #降级过程中 Deployment 控制器最多能够删除多少个旧 Pod,次要用于提供缓冲工夫
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: micro-api
        #设置版本标签,便于灰度公布
        version: v1
    spec:
      #设置的阿里云公有镜像仓库登陆信息的 secret
      imagePullSecrets:
        - name: regcred
      containers:
        - name: micro-api
          image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.1-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19090

“spec.selector.matchLabels.version:v1”标签用来标注服务的版本,该标签是后续 Istio 的流量治理规定中,辨认服务版本的次要根据。

筹备好公布文件后,执行发布命令:

$ kubectl apply -f micro-api-canary-istio-v1.yaml

此时,一个低版本的服务就运行胜利了!接下来咱们模仿对其施行金丝雀(灰度)公布。

(2)公布一个 v2 版本的服务(降级的指标版本)。

与 v1 版本服务一样,公布的 v2 版本的服务也须要明确版本标签,其公布文件(micro-api-canary-istio-v2.yaml)的内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-api-v2
spec:
  selector:
    matchLabels:
      app: micro-api
      #设置好版本标签,便于灰度公布
      version: v2
  replicas: 3
  #设置滚动降级策略
  #Kubernetes 在期待设置的工夫后才开始进行降级,例如 5 秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #降级过程中最多能够比原先设置多出的 Pod 数量
      maxSurge: 1
      #降级过程中 Deployment 控制器最多能够删除多少个旧 Pod,次要用于提供缓冲工夫
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: micro-api
        #设置好版本标签,便于灰度公布
        version: v2
    spec:
      #设置的阿里云公有镜像仓库登陆信息的 secret
      imagePullSecrets:
        - name: regcred
      containers:
        - name: micro-api
          image: registry.cn-hangzhou.aliyuncs.com/wudimanong/micro-api:1.3-SNAPSHOT
          imagePullPolicy: Always
          tty: true
          ports:
            - name: http
              protocol: TCP
              containerPort: 19090

执行发布命令:

$ kubectl apply -f micro-api-canary-istio-v2.yaml 
deployment.apps/micro-api-v2 created

此时,零碎中就存在了 两组版本 的 Pod 资源,具体如下:

# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
micro-api-v1-565d749dd4-7c66z   1/1     Running   2          13h
micro-api-v1-565d749dd4-7dqfb   1/1     Running   2          13h
micro-api-v1-565d749dd4-l62wc   1/1     Running   2          13h
micro-api-v2-6f98c598c9-5stlw   1/1     Running   0          82s
micro-api-v2-6f98c598c9-f2ntq   1/1     Running   0          82s
micro-api-v2-6f98c598c9-l8g4j   1/1     Running   0          82s

接下来将演示如何 利用 Istio 弱小的流量治理性能,来实现流量在这两组版本 Pod 资源之间的准确管制!

(3)创立 Istio 网关资源。

在 Istio 中要实现流量的准确管制,须要 将 VirtualService 绑定到具体的 Ingressgateway(入口网关)资源。因而在创立 VirtualService 资源实现流量路由及管制前,须要创立一个 Istio 网关。部署文件(micro-gateway.yaml)的内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: micro-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"

上述部署文件执行后将创立一个名称为“micro-gateway”的 Istio 网关,并容许所有主机(hosts:”*” 指定)通过该网关。

(4)创立 Istio 虚构服务资源 VirtualService。

后面提到过 在 Istio 中次要是通过 VirtualService(虚构服务)来实现服务网格内的流量路由及管制。接下来咱们看看 VirtualService 资源的具体创立形式,筹备资源文件(如 virtual-service-all.yaml),内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: micro-api-route
spec:
  #用于定义流量被发送到的指标主机(这里为部署在 k8s 中的 micro-api 服务)hosts:
    - micro-api.default.svc.cluster.local
  #将 VirtualService 绑定到 Istio 网关, 通过网关来裸露路由指标
  gateways:
    - micro-gateway
  http:
    - route:
        #设置旧版本(V1)版本的流量占比为 70%
        - destination:
            host: micro-api.default.svc.cluster.local
            subset: v1
          #通过权重值来设置流量占比
          weight: 70
        #设置新版本(V2)版本的流量占比为 30%
        - destination:
            host: micro-api.default.svc.cluster.local
            subset: v2
          weight: 30

如上所示,VirtualService 资源具备针对 http 的精准流量控制能力,能够将指定占比的流量路由到特定的“subset”指定的版本。而为了实现这一能力,VirtualService 资源还须要与 Istio 网关绑定,通过 Istio 网关来裸露路由指标。

(5)创立 Istio 指标路由规定资源。

虚构服务 VirtualService 在 Istio 中次要用于管制流量的行为,而定义流量行为的路由规定则须要通过“DestinationRule”路由规定资源来定义。创立路由规定文件(destination-rule-all.yaml),具体内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: micro-api-destination
spec:
  #与 Deployment 资源对应的 Service 资源名称关联
  host: micro-api
  #流量策略设置:负载平衡策略、连接池大小、部分异样检测等,在路由产生后作用于流量
  trafficPolicy:
    #限流策略
    connectionPool:
      tcp:
        maxConnections: 10
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
    #设置目的地的负债平衡算法
    loadBalancer:
      simple: ROUND_ROBIN
  #目的地指的是不同的子集 (subset) 或服务版本。通子集(subset), 能够辨认应用程序的不同版本,以实现流量在不同服务版本之间的切换
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

如上所示,通过 subsets 属性,定义了 VirtualService 资源用于路由的具体版本标签匹配信息。至此,针对两个版本服务的灰度流量管制规定就设置好了,接下来测试具体的金丝雀(灰度)公布成果。

(6)测试 Istio 实现金丝雀(灰度)公布的流量管制成果。

在正式测试之前,能够通过命令查看下以后的部署资源状况:

# 查看部署的 Deployment 资源
kubectl get deploy  | grep micro-api

micro-api-v1             3/3     3            3           21h
micro-api-v2             3/3     3            3           8h
# 查看两组版本 Pod 资源对应的 K8s-Service 的服务 IP
kubectl get svc micro-api

NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
micro-api   ClusterIP   10.110.169.161   <none>        19090/TCP   205d
# 查看 VirtualService 资源定义
kubectl get vs

NAME              GATEWAYS          HOSTS                                   AGE
micro-api-route   [micro-gateway]   [micro-api.default.svc.cluster.local]   7h34m
# 查看定义的路由规定资源
kubectl get dr

NAME                    HOST        AGE
micro-api-destination   micro-api   7h27m

通过下面的资源信息查看,这里咱们曾经能够查到 Deployments 对应的 K8s-Service 资源的 IP,但如果 通过 K8s-Service 资源来进行测试的话,会发现流量的管制并不精准,并不能达到咱们设置的 70% 流量流向 v1,30% 的流量流向 v2(因为这是随机流量)

因而,要应用 Istio 的精准流量管制性能,还须要应用 Istio 的 Ingressgateway。查看 Istio 的 Ingressgateway 资源 IP 的命令如下:

# 查看 ingress 的 IP
kubectl get svc -n istio-system | grep ingress

istio-ingressgateway   LoadBalancer   10.98.178.61     <pending>     15021:31310/TCP,80:32113/TCP,443:31647/TCP,31400:30745/TCP,15443:30884/TCP   7h54m

接下来,通过 Ingress 的 IP 来拜访“micro-api”服务,命令及成果如下:

# for i in {1..10}; do curl -H "Host:micro-api.default.svc.cluster.local" 10.98.178.61:80/test/test; done

{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}

如上所示,流量依照设定的比例(v1:70%;v2:30%)进行了分流。

(7)测试将流量全副切向新版本。

为了更显著地验证 Istio 的流量管制成果,接下来,咱们通过变更 VirtualService 资源的流量设置占比,将流量全副切到新版本。变更后的 VirtualService 资源的配置文件内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: micro-api-route
spec:
  #用于定义流量被发送到的指标主机(这里为部署在 k8s 中的 micro-api 服务)hosts:
    - micro-api.default.svc.cluster.local
  #将 VirtualService 绑定到 Istio 网关, 通过网关来裸露路由指标
  gateways:
    - micro-gateway
  http:
    - route:
        #设置旧版本(V1)版本的流量占比为 70%
        - destination:
            host: micro-api.default.svc.cluster.local
            subset: v1
          #通过权重值来设置流量占比
          weight: 0
        #设置新版本(V2)版本的流量占比为 30%
        - destination:
            host: micro-api.default.svc.cluster.local
            subset: v2
          weight: 100

持续通过 Istio 网关拜访指标服务,命令如下:

# for i in {1..10}; do curl -H "Host:micro-api.default.svc.cluster.local" 10.98.178.61:80/test/test; done

{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}
{"code":0,"data":"V3| 无依赖测试接口返回 ->OK!","message":"胜利"}

能够察看到,此时流量曾经全副切换到了新版本服务!

后记

在微服务时代,不同的服务之间互相分割,关系盘根错节,部署降级一个服务,可能造成整个零碎的瘫痪,因而,须要抉择适合的部署形式,从而将危险降到最低。金丝雀(灰度)公布只是多种部署形式的一种,还有蓝绿部署、滚动部署(如 K8s 的滚动降级)等,能够依据不同的业务场景抉择不同的公布模式。

退出移动版