使用 Istio 进行金丝雀部署

标签: | 发表时间:2021-06-04 18:08 | 作者:
出处:https://istio.io
本篇博客最后更新时间 2018 年 5 月 16 号,采用了最新版本的流量管理模型。

采用 Istio项目的一大好处就是为服务金丝雀方式部署提供了控制便利。金丝雀部署(或上线)背后的想法是通过让一小部分用户流量引入的新版本进行测试,如果一切顺利,则可以增加(可能逐渐增加)百分比,逐步替换旧版本。如在过程中出现任何问题,则可以中止并回滚到旧版本。最简单的方式,是随机选择百分比请求到金丝雀版本,但在更复杂的方案下,则可以基于请求的区域,用户或其他属性。

基于领域的专业水平,您可能想知道为什么需要 Istio 来支持金丝雀部署,因为像 Kubernetes 这样的平台已经提供了进行 版本上线金丝雀部署的方法。问题解决了吗 ?不完全是。虽然以这种方式进行部署可以在简单的情况下工作,但功能非常有限,特别是在大规模自动缩放的云环境中大流量的情况下。

Kubernetes 中的金丝雀部署

假设我们有一个已部署的 helloworld服务 v1版本,我们想要测试(或简单上线)新版本 v2。使用 Kubernetes,您可以通过简单地更新服务的 Deployment中的镜像并自动进行部署来 上线新版本的 helloworld服务。如果我们特能够小心保证在启动并且在仅启动一个或两个 v2 副本 暂停上线时有足够的 v1副本运行,则能够保持金丝雀发布对系统的影响非常小。后续我们可以观察效果,或在必要时进行 回滚。最好,我们也能够对 Deployment 设置 HPA,在上线过程中减少或增加副本以处理流量负载时,也能够保持副本比例一致。

尽管这种机制能够很好工作,但这种方式只适用于部署的经过适当测试的版本,也就是说,更多的是蓝/绿发布,又称红/黑发布,而不是 “蜻蜓点水“ 式的金丝雀部署。实际上,对于后者(例如,并没有完全准备好或者无意对外暴露的版本),Kubernetes 中的金丝雀部署将使用具有 公共 pod 标签的两个 Deployment 来完成。在这种情况下,我们不能再使用自动缩放器,因为是有由两个独立的自动缩放器来进行控制,不同负载情况下,副本比例(百分比)可能与所需的比例不同。

无论我们使用一个或者两个部署,使用 Docker,Mesos/Marathon 或 Kubernetes 等容器编排平台进行的金丝雀发布管理都存在一个根本问题:使用实例扩容来管理流量;版本流量分发和副本部署在上述平台中并独立。所有 pod 副本,无论版本如何,在 kube-proxy循环池中都被一视同仁地对待,因此管理特定版本接收的流量的唯一方法是控制副本比例。以小百分比维持金丝雀流量需要许多副本(例如,1% 将需要至少 100 个副本)。即使我们可以忽略这个问题,部署方式功能仍然非常有限,因为它只支持简单(随机百分比)金丝雀部署。如果我们想根据某些特定规则将请求路由到金丝雀版本上,我们仍然需要另一种解决方案。

使用 Istio

使用 Istio,流量路由和副本部署是两个完全独立的功能。服务的 pod 数量可以根据流量负载灵活伸缩,与版本流量路由的控制完全正交。这在自动缩放的情况下能够更加简单地管理金丝雀版本。事实上,自动缩放管理器仍然独立运行,其在响应因流量路由导致的负载变化与其他原因导致负载变化的行为上没有区别。

Istio 的 路由规则也带来了其他的便利;你可以轻松实现细粒度控制流量百分比(例如,路由 1% 的流量而不需要 100 个 pod),当然也可以使用其他规则来控制流量(例如,将特定用户的流量路由到金丝雀版本)。作为展示,让我们看一下采用这种方式部署 helloworld服务的简单便捷。

首先我们定义 helloworld服务,和普通 Kubernetes服务一样,如下所示:

      apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
  app: helloworld
spec:
  selector:
    app: helloworld
  ...

然后我们添加 2 个 Deployment,分别为版本 v1v2,这两个版本都包含服务选择标签 app:helloworld

      kind: Deployment
metadata:
  name: helloworld-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: helloworld
        version: v1
    spec:
      containers:
      - image: helloworld-v1
        ...
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: helloworld-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: helloworld
        version: v2
    spec:
      containers:
      - image: helloworld-v2
        ...

需要注意的是,这与使用普通 Kubernetes 进行 金丝雀部署的方式完全相同,但是在 Kubernetes 方式下控制流量分配需要调整每个 Deployment 的副本数目。例如,将 10% 的流量发送到金丝雀版本(v2),v1 和 v2 的副本可以分别设置为 9 和 1。

但是在 启用 Istio的集群中,我们可以通过设置路由规则来控制流量分配。如将 10% 的流量发送到金丝雀版本本,我们可以使用 kubectl来设置以下的路由规则:

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

当规则设置生效后,Istio 将确保只有 10% 的请求发送到金丝雀版本,无论每个版本的运行副本数量是多少。

部署中的自动缩放

由于我们不再需要保持副本比例,所以我们可以安全地设置 Kubernetes HPA来管理两个版本 Deployment 的副本:

      $ kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10
deployment "helloworld-v1" autoscaled
      $ kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10
deployment "helloworld-v2" autoscaled
      $ kubectl get hpa
NAME           REFERENCE                 TARGET  CURRENT  MINPODS  MAXPODS  AGE
Helloworld-v1  Deployment/helloworld-v1  50%     47%      1        10       17s
Helloworld-v2  Deployment/helloworld-v2  50%     40%      1        10       15s

如果现在对 helloworld服务上产生一些负载,我们会注意到,当扩容开始时, v1扩容副本数目远高于 v2,因为 v1pod 正在处理 90% 的负载。

      $ kubectl get pods | grep helloworld
helloworld-v1-3523621687-3q5wh   0/2       Pending   0          15m
helloworld-v1-3523621687-73642   2/2       Running   0          11m
helloworld-v1-3523621687-7hs31   2/2       Running   0          19m
helloworld-v1-3523621687-dt7n7   2/2       Running   0          50m
helloworld-v1-3523621687-gdhq9   2/2       Running   0          11m
helloworld-v1-3523621687-jxs4t   0/2       Pending   0          15m
helloworld-v1-3523621687-l8rjn   2/2       Running   0          19m
helloworld-v1-3523621687-wwddw   2/2       Running   0          15m
helloworld-v1-3523621687-xlt26   0/2       Pending   0          19m
helloworld-v2-4095161145-963wt   2/2       Running   0          50m

如果更改路由规则将 50% 的流量发送到 v2,我们则可以在短暂的延迟后注意到 v1副本数的减少,而 v2副本数相应地增加。

      $ kubectl get pods | grep helloworld
helloworld-v1-3523621687-73642   2/2       Running   0          35m
helloworld-v1-3523621687-7hs31   2/2       Running   0          43m
helloworld-v1-3523621687-dt7n7   2/2       Running   0          1h
helloworld-v1-3523621687-gdhq9   2/2       Running   0          35m
helloworld-v1-3523621687-l8rjn   2/2       Running   0          43m
helloworld-v2-4095161145-57537   0/2       Pending   0          21m
helloworld-v2-4095161145-9322m   2/2       Running   0          21m
helloworld-v2-4095161145-963wt   2/2       Running   0          1h
helloworld-v2-4095161145-c3dpj   0/2       Pending   0          21m
helloworld-v2-4095161145-t2ccm   0/2       Pending   0          17m
helloworld-v2-4095161145-v3v9n   0/2       Pending   0          13m

最终结果与 Kubernetes Deployment 上线非常相似,只是整个流程并不是集中地进行编排和管理。相反,我们看到几个组件独立完成工作,虽然它们有因果关系。

有一点不同的是,当我们停止负载时,无论设置路由规则如何,两个版本的副本数最终都会缩小到最小值(1)。

      $ kubectl get pods | grep helloworld
helloworld-v1-3523621687-dt7n7   2/2       Running   0          1h
helloworld-v2-4095161145-963wt   2/2       Running   0          1h

聚焦金丝雀测试

如上所述,Istio 路由规则可用于根据特定规则准进行流量路由,从而能够提供更复杂的金丝雀部署方案。例如,与简单通过将金丝雀版本暴露给任意百分比的用户方式不同,我们希望在内部用户上尝试,甚至可能只是内部用户的一部分。

以下命令可将特定网站上 50% 的用户流量路由到金丝雀版本,而其他用户则不受影响:

      $ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: helloworld
spec:
  hosts:
    - helloworld
  http:
  - match:
    - headers:
        cookie:
          regex: "^(.*?;)?(email=[^;]*@some-company-name.com)(;.*)?$"
    route:
    - destination:
        host: helloworld
        subset: v1
        weight: 50
    - destination:
        host: helloworld
        subset: v2
        weight: 50
  - route:
    - destination:
        host: helloworld
        subset: v1
EOF

和以前一样,绑定到 2 个版本 Deployment 的自动缩放器会相应地自动管理副本,但这对流量分配没有影响。

总结

本文中,我们看到了 Istio 如何支持通用可扩展的金丝雀部署,以及与 Kubernetes 部署的差异。Istio 服务网格提供了管理流量分配所需的基础控制,并完全独立于部署缩放。这允许简单而强大的方式来进行金丝雀测试和上线。

支持金丝雀部署的智能路由只是 Istio 的众多功能之一,它将使基于大型微服务的应用程序的生产部署变得更加简单。查看 istio.io了解更多信息。

可在 此处查看示例代码。

相关 [istio 金丝雀] 推荐:

使用 Istio 进行金丝雀部署

- -
本篇博客最后更新时间 2018 年 5 月 16 号,采用了最新版本的流量管理模型. Istio项目的一大好处就是为服务金丝雀方式部署提供了控制便利. 金丝雀部署(或上线)背后的想法是通过让一小部分用户流量引入的新版本进行测试,如果一切顺利,则可以增加(可能逐渐增加)百分比,逐步替换旧版本. 如在过程中出现任何问题,则可以中止并回滚到旧版本.

使用istio对spring cloud kubernetes项目进行金丝雀发布_水中加点糖-CSDN博客_istio springcloud

- -
(一)基础k8s yaml脚本发布. (二)helm+shell脚本优化大量冗余配置发布. (三)jenkins用户审核的流水化方式部署. (四)service mesh(istio)服务网格化发布. (五)istio对项目进行金丝雀部署. spring-cloud-kubernetes之开发环境搭建.

istio 原理简介

- - 掘金 架构
由于 istio 自 1.5 版本以后架构上有了较大变化,控制面从多组件变成了单体的 istiod 组件,所以下文会先介绍 1.5 之前的架构,再介绍 1.5 之后的,是一个由繁到简的过程. istio 1.5 之前架构. Istio 的架构分为控制平面和数据平面. 数据平面:由一组智能代理(Envoy)以 sidecar 模式部署,协调和控制所有服务之间的网络通信.

Istio 常见的 10 个异常分析

- - DockOne.io
本文总结了使用 Istio 常见的 10 个异常. Istio 支持多平台,不过 Istio 和 Kubernetes 的兼容性是最优的,不管是设计理念,核心团队还是社区, 都有一脉相承的意思. 但 Istio 和 Kubernetes 的适配并非完全没有冲突,一个典型问题就是 Istio 需要 Kubernetes Service 按照协议进行端口命名(Port Naming).

Istio究竟是干嘛的? - 知乎

- -
当微服务架构体系越来越复杂的时候,需要将“业务服务”和“基础设施”解耦,将一个微服务进程一分为二:. 一个进程实现业务逻辑,biz,即上图白色方块. 一个进程实现底层技术体系,proxy,即上图蓝色方块,负载均衡、监控告警、服务发现与治理、调用链…等诸多基础设施,都放到这一层实现. biz不管是调用服务,还是提供服务,都只与本地的proxy进行本地通信.

实践k8s istio熔断 - fat_girl_spring - 博客园

- -
熔断主要是无感的处理服务异常并保证不会发生级联甚至雪崩的服务异常. 在微服务方面体现是对异常的服务情况进行快速失败,它对已经调用失败的服务不再会继续调用,如果仍需要调用此异常服务,它将立刻返回失败. 与此同时,它一直监控服务的健康状况,一旦服务恢复正常,则立刻恢复对此服务的正常访问. 这样的快速失败策略可以降低服务负载压力,很好地保护服务免受高负载的影响.

知乎落地的 Service Mesh Istio

- -
在知乎,我们很早就进行了非常彻底的容器化部署. 全站在线运行的微服务数量高达两千多个. 这些微服务通过我们自己维护的 RPC 框架和 Kodor 体系来实现服务互联的能力. 在这其中,我们也存在一系列的问题:. 各种基础组件维护成本比较高,单点风险存在. 各语言客户端特性难以统一,熔断、重试等特性实现颇有不同,且不能做到动态线上进行调整.

如何理解 Istio 中的 VirtualService 和 DestinationRule?

- - Jimmy Song - 专注于探索后 Kubernetes 时代的云原生新范式 – 博客
Istio 在刚开源的时候就定义了几十个 CRD,其中用于流量治理的有 RouteRule、 DestinationPolicy、 EgressRule 等,后来推出了 v1alpha3 API 使用 VirtualService 和 DestinationRule 等取代了之前的 API.

Spring Cloud实践:降级、限流、滚动、灰度、AB、金丝雀的实现思路

- - 程序猿DD | 博客
之前在我博客的 问答平台和 Spring4All社区均有关于Spring Cloud的发布策略实现问题. 虽然大家都给力很多不错的思路和建议,但是都没有 Charles He的这篇文章详细. 因此经得作者同意,在这里转载了该篇内容,为了更好的阅读体验,稍作一些格式调整,分享给更多Spring Cloud爱好者.

spring cloud 实践-降级、限流、滚动、灰度、AB、金丝雀等等等等 - 简书

- -
spring cloud 实践. 源码地址:https://github.com/charlesvhe/spring-cloud-practice. 端口:8888,方便起见直接读取配置文件,生产环境可以读取git. application-dev.properties为全局配置. 先启动配置中心,所有服务的配置(包括注册中心的地址)均从配置中心读取.