灰度更新的设计

  

 

  在聊了上面的这些知识后,来看一下灰度更新。上图是灰度更新的简易示例图,流程是从左开始到右边结束。

  第一步是创建灰度服务,创建后可以更新灰度。比如刚才的 Nginx 的例子,我们创建的版本号是 1.19。但是在灰度过程中发现当前版本有 bug,而在对这个 bug 进行修复后,确认无误就可以将原服务更新到版本号 1.20,然后删除灰度服务。如果发现 1.20 版本依然有 bug,也可以选择删除灰度服务,让你原服务接管所有流量。这就是 CRD 对开发步骤的简化。

  灰度更新一共有以下 4 个阶段:

  创建

  更新

  替换

  删除

  创建

  因为 Kubernetes 是水平触发的,所有它创建和更新的处理逻辑是相同的,只看最终状态即可。

  

 

  这张图比较重要,大家可以仔细看一下。图中右上部分是原服务,原服务包含 Kubernetes 无状态服务、Service 内部域名、ApisixRoute、Apisix 路由规则、ApisixUpstrean,以及 Apisix 上游的一些配置。原服务下方是灰度服务,左边的 controller 是之前提到的 CRD 控制器。

  原服务创建好后,创建无状态服务,配置对应的 http 转发规则后转到 ApisixRoute 服务站中进行对应路由的配置,之后只有转到容器网关就会自动定位到指定服务。然后大家可以看到,我们自定义的 CRD 类型名是 CanaryDeployment,是灰度的无状态服务。创建这个无状态服务的流程和原服务是相同的。

  CRD 的定义是如何设计的?下图是一个简单示例:

  

 

  apiVersion 我们先不讲,具体看一下下面的部分:

  kind:类型,上图类型为 CanaryDeployment(无状态服务)

  name:名称

  namespace:位置,在 mohb-test 这个测试空间下

  version:版本

  replicas:灰度实例个数,这个个数是可配的

  weight:权重,影响了灰度服务接管多少流量

  apisix:服务对应的 hb 转化规则

  apisixRouteMatches:相关功能

  parentDeployment:原无状态服务名称

  template:这里定义了刚刚讲的镜像、其他命令、开放端口等配置

  在定义 CRD 的时候可能会遇到几个问题。第一个问题是如果删除了原服务,那灰度服务不会自动删除,会被遗留。出现这个问题是因为没有做 Kubernetes 的回收技术,而解决这个问题需要 Kubernetes 的 ownerReferences。它可以帮助你把灰度服务的 CRD 指到原服务的无状态服务中,也就是灰度服务的 owner 由原服务负责。

  

 

  这样当删除原服务的时候,owner 会负责删除灰度服务。而删除 CanaryDeployment的时候,只会删除它右边的 Deployment。

  ownerReferences 的具体设置如下图:

  

 

  我们在定义 CRD 时加入红框部分的字段,这个字段会指定它是谁的 owner,以及它的指向。到这里创建阶段基本就完成了。

  替换

  接下来看第二阶段——替换。

  

 

  我通过加入字段 replace 进行控制,默认情况下它是 false,如果值是 true 那控制器就会知道要用 deployment 的进行替换。这里有个问题是什么时候进行替换?也就是什么时候把流量切过去。虽然直接切也可以,但是等原服务完全运行起来后再切无疑是更好的。

  那具体要怎么做呢?

  这就涉及到 informer 的部分逻辑了。这需要控制器能够感知到灰度服务的 parentDeployment 是否发生变更。这部分 operator-sdk 和 Kubebuilder 就很好,它可以把不是 CRD 事件的变动也导入到调和函数内,让控制器可以监听无状态服务。

  

 

  具体可以看一下代码。首先注册一些 watch 来监听无状态服务,然后写一个函数让无状态服务对应到 CanaryDeployment,比如在 text back 内对无状态服务进行了标记,这样当感知到事件后可以看一下是哪个无状态服务进行了替换,并推算出对应的 CanaryDeployment,然后通过调用调和函数对比和预期是否有差距。

  取消

  接下来看最后一个阶段——取消阶段。郑州哪家精神病医院好http://www.juenpt.com/

  如果直接把 CanaryDeployment 对应的对象删掉,就会发现它的右边多了一个 deletionTimestamp 的字段,这是 Kubernetes 打的删除时间标记。而对于控制器来讲,就是知道这个已经是删除状态了,需要调整对应内容。

  

 

  这有个问题,删除是瞬间的操作,可能等不到控制器运行起来,删除就已经完成了。因此 Kubernetes 提供了 Finalizer,Finalizer 决定了最终由谁来做释放。

posted @ 2021-12-14 11:22  顾延笙  阅读(469)  评论(0编辑  收藏  举报