1W字长文:蓝绿发布、金丝雀发布、滚动发布、A/B测试 原理和实操

背景:

蓝绿发布、金丝雀发布、滚动发布、A/B测试 ,是大家日常常见的发布工作。所以发布的原理和实操是一个非常、非常核心的面试知识点

在40岁老架构师 尼恩的读者交流群(50+)中,其相关面试题是一个非常、非常高频的交流话题。

只要一面试,基本就会问:

对灰度发布了解吗?

对蓝绿发布了解吗?

对金丝雀发布了解吗?

对滚动发布发布了解吗?

等等等等

很多小伙伴,回答起来,就是干巴巴的几点。 导致给面试官的用户体验,非常差。

这里尼恩给大家 调优,做一下系统化、体系化的梳理。

在面试之前,也可以复习一下,使得大家可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”

扫描二维码关注公众号,回复: 14582821 查看本文章

也一并把这些宝贵内容作为“K8S云原生学习”重要的内容,收入咱们的《K8S学习圣经》,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

注:本文以 PDF 持续更新,最新尼恩 架构笔记、面试题 的PDF文件,请从这里获取:码云

先介绍一下蓝绿发布、金丝雀发布、滚动发布、A/B测试 的概念

再介绍实操

蓝绿发布、金丝雀发布、滚动发布、A/B测试 核心原理

蓝绿发布(Blue-green Deployments) 核心原理

蓝绿发布的目的是减少发布时的中断时间能够快速撤回发布

It’s basically a technique for releasing your application in a predictable manner with an goal of reducing any downtime associated with a release. It’s a quick way to prime your app before releasing, and also quickly roll back if you find issues.

蓝绿发布中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。

两套系统都是功能完善的,并且正在运行的系统,只是系统版本和对外服务情况不同。

最初,没有任何系统,没有蓝绿之分。

然后,第一套系统开发完成,直接上线,这个过程只有一个系统,也没有蓝绿之分。

后来,开发了新版本,要用新版本替换线上的旧版本,在线上的系统之外搭建了一个使用新版本代码的全新系统。 这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。

蓝色系统不对外提供服务,用来做啥?

用来做发布前测试,测试过程中发现任何问题,可以直接在蓝色系统上修改,不干扰用户正在使用的系统。(注意,两套系统没有耦合的时候才能百分百保证不干扰)

蓝色系统经过反复的测试、修改、验证,确定达到上线标准之后,直接将用户切换到蓝色系统:

切换后的一段时间内,依旧是蓝绿两套系统并存,但是用户访问的已经是蓝色系统。这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。

当确信对外提供服务的蓝色系统工作正常,不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。 原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。

蓝绿发布只是上线策略中的一种,它不是可以应对所有情况的万能方案。 蓝绿发布能够简单快捷实施的前提假设是目标系统是非常内聚的,如果目标系统相当复杂,那么如何切换、两套系统的数据是否需要以及如何同步等,都需要仔细考虑。

BlueGreenDeployment中给出的一张图特别形象:

蓝绿发布缺点:

切换是全量的,如果新版本有问题,则对用户体验有直接影响, 需要双倍机器资源。

蓝绿发布需要路由或者ingress的配合。

金丝雀发布(anCanary Releases) 核心原理

金丝雀发布(Canary)也是一种发布策略,和国内常说的灰度发布是同一类策略。

蓝绿发布是准备两套系统,在两套系统之间进行切换,金丝雀策略是只有一套系统,逐渐替换这套系统。

譬如说,目标系统是一组无状态的Web服务器,但是数量非常多,假设有一万台。这时候,蓝绿发布就不能用了,因为你不可能申请一万台服务器专门用来部署蓝色系统(在蓝绿发布的定义中,蓝色的系统要能够承接所有访问)。

可以想到的一个方法是: 只准备几台服务器,在上面部署新版本的系统并测试验证。测试通过之后,担心出现意外,还不敢立即更新所有的服务器。 先将线上的一万台服务器中的10台更新为最新的系统,然后观察验证。确认没有异常之后,再将剩余的所有服务器更新。这个方法就是金丝雀发布。

金丝雀发布(canary release)的命名原因:

人们发现金丝雀这种生物对于有毒气体很敏感。因此矿工在下井采矿之前会把金丝雀鸟儿投入或携带到矿井中,如果鸟儿能够从矿井中飞出就表示井下有氧气,矿工就可以安心下井采矿了。

通过这个故事,我们就可以看出金丝雀部署就是先把新版本试水的一部分就叫金丝雀发布。金丝雀发布可以快速而有效地发现软件新版本存在的问题。

它的原理就是部署的时候让一小部分用户先试用功能 ,通过日志监控或者服务器监控,看下新用户的反馈。如果没有严重问题,尽快部署这个新版本,否则快速会退。小代价去试错

金丝雀发布(canary release)实际操作中还可以做更多控制,譬如说给最初更新的10台服务器设置较低的权重、控制发送给这10台服务器的请求数,然后逐渐提高权重、增加请求数。

这个控制叫做“流量切分”,既可以用于金丝雀发布,也可以用于后面的A/B测试。

金丝雀部署也就是灰度发布的一种方式。

蓝绿发布和金丝雀发布是两种发布策略,都不是万能的。

有时候两者都可以使用,有时候只能用其中一种。

上面的例子中可以用金丝雀,不能用蓝绿,那么什么时候可以用蓝绿呢?整个系统只有一台服务器的时候。或者说有足够的资源,同时支撑运行两套系统的时候。

金丝雀发布缺点: 自动化流程不够,发布期间需要人为去操作,可能会引起服务中断等。

滚动发布的 核心原理

滚动发布是在金丝雀发布基础上的进一步优化改进,是一种自动化程度较高的发布方式,用户体验比较平滑,是目前成熟型技术组织所采用的主流发布方式。

一次滚动式发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义)。

例如,第一批1台(金丝雀),第二批10%,第三批 50%,第四批100%。

每个批次之间留观察间隔,通过手工验证或监控反馈确保没有问题再发下一批次,所以总体上滚动式发布过程是比较缓慢的 (其中金丝雀的时间一般会比后续批次更长,比如金丝雀10 分钟,后续间隔 2分钟)。

A/B测试(A/B Testing) 核心原理

首先需要明确的是,A/B测试和蓝绿发布以及金丝雀,完全是两回事。

蓝绿发布和金丝雀是发布策略,目标是确保新上线的系统稳定,关注的是新系统的BUG、隐患。A/B测试是效果测试,同一时间有多个版本的服务对外服务,这些服务都是经过足够测试,达到了上线标准的服务,有差异但是没有新旧之分(它们上线时可能采用了蓝绿发布的方式)。

A/B测试关注的是不同版本的服务的实际效果,譬如说转化率、订单情况等。

A/B版本

一般A/B版本用在创业公司第一次发布新版本时,不清楚顾客更喜欢哪一个新版本的时候用的。

同时部署A和B两个版本,通过后台统计数据,分析顾客更喜欢哪一个版本,然后选择这个版本上线。在新产品抢占市场份额时作用巨大。

A/B测试时,线上同时运行多个版本的服务,这些服务通常会有一些体验上的差异,譬如说页面样式、颜色、操作流程不同。相关人员通过分析各个版本服务的实际效果,选出效果最好的版本。

在A/B测试中,需要能够控制流量的分配,譬如说,为A版本分配10%的流量,为B版本分配10%的流量,为C版本分配80%的流量。

蓝绿发布、金丝雀发布、滚动发布实操

spring cloud 灰度实操

spring cloud 灰度的实操方案比较多:

方案一:spring cloud gateway也可以实现灰度发布,

方案二:还有一款 spring cloud 的Discovery增强组件,可以实现灰度、蓝绿等功能(https://github.com/Nepxion/Discovery)

简单来说,灰度发布实质是让指定用户访问指定版本的服务。

spring cloud gateway也可以实现灰度发布大概的思路:

首先,需要指定用户匹配到指定的路由规则。

其次,服务的版本号信息可以通过HTTP请求头字段来指定。

最后,负载均衡算法需要能够根据版本号信息来做服务实例的选择。

在实操层面,spring cloud gateway 灰度发布的实现思路应该比较简单:

1、首先编写自己的Predicate,实现指定用户匹配到指定的路由规则中;

2、动态修改请求,添加版本号信息,版本号信息可以放在HTTP Header中(此处可以通过原生AddRequestHeaderGatewayFilterFactory来实现,无需自己写代码);

3、自定义路由规则,重写负载均衡算法,根据版本号信息从注册中心的服务实例上选择相应的服务版本进行请求的转发。

具体的方案,后面在尼恩的《SpringCloud 学习圣经》PDF中,进行补充。

反向代理网关灰度实操

利用云原生网关比如 APISIX :

  • https://apisix.apache.org/zh/docs/apisix/plugins/traffic-split/#蓝绿发布
  • https://apisix.apache.org/zh/docs/apisix/plugins/traffic-split/#灰度发布

Kubernetes 中的灰度策略

Kubernetes 中常见的发布策略主要有如下六种:

重建(recreate) :即停止一个原有的容器,然后进行容器的新建。

滚动更新(rollingUpdate) :停掉一个容器,然后更新一个容器。

蓝绿布署(blue/green ):准备一套蓝色的容器和一套绿色的容器,进行流量切换。

金丝雀发布(canary) :更新部分容器,没有问题后进行逐步替换,直到切完。

A/B测试发布:即将发布的结果面向部分用户,这块没有现成的组件,需要进行自行处理,比如使用 Istio、Linkerd、Traefik 等。这种方式采用在 Http 的 Header 上进行处理。

无损发布:现在很多发布都是将容器停掉,当没有请求的时候发布,实现无损发布。

Deployment金丝雀部署:按照流量比例

金丝雀部署就是将部分新版本发在旧的容器池里边,然后进行流量观察,比如 30% 的流量切到新服务上,60% 的流量还在旧服务上。

这里,采用 svc 的方式进行部署的选择,这里使用 label 进行 pod的选择。

两个 Deployment 文件如下:

app-v1-canary.yaml里边有 2 个 pod 支撑这个服务。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v1
  labels:
    app: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
      version: v1.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v1.0.0
            - name: env_flag
              value: VERSION-v1.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
    - name: http
      port: 8008   #对应deployment的容器端口
      targetPort: http
      nodePort: 30808 #外部端口
  selector:
    app: my-app

接下来,我们创建 v2 版本 app-v2-canary.yaml 文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v2
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
      version: v2.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v2.0.0
            - name: env_flag
              value: VERSION-v2.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5

说一下要执行的步骤:

  1. 启动 V1 的服务版本:2 个复本。
  2. 启动 V2 的服务版本:1 个复本。
  3. 观察 V2 流量正常的情况的话,那么启动 V2 的 2 个复本。
  4. 删除 V1 的 2 个复本,流量全部到 V2 上。

step1 :启动 V1 服务,查看服务是否正确,然后观察一下服务。

cd  /vagrant/chapter28/k8s/deployPolicy

kubectl apply -f app-v1-canary.yaml

kubectl get svc -l app=my-app

curl http://192.168.49.2:30808

watch kubectl get pod ,能看到两个 pod

step2:启动 V2 的服务版本:1 个复本

新打开容器,执行命令,启动 V2 服务。

上边的 watch 将观察到新增了 1 个 pod, 此时共有 3 个 pod, 2.0.0 的版本已经上来了。

cd  /vagrant/chapter28/k8s/deployPolicy

kubectl apply -f app-v2-canary.yaml

while sleep 1; do curl http://192.168.49.2:30808 | egrep VERSION; done

此时我们观察版本 2 的服务是否正确

step3: 观察 V2 流量正常的情况的话,那么启动 V2 的 2 个复本。

v2能收到分发的流量,是正确的

如果正确,那么我们将版本 2 扩展到 2个副本。

kubectl scale --replicas=2 deploy my-app-v2

执行如下

watch 将观察到新增了 1 个 pod, 此时共有4个 pod, 2.0.0 的版本已经上来了。

这个时候版本 1 和版本 2 一样了。

step4:删除 V1 的 2 个复本,流量全部到 V2 上。

我们再将老版本删除, 将 版本 1 的2个 pod 给清除掉

kubectl delete deploy my-app-v1

清除之后,watch的效果,只剩新版本的2个pod,到此为止, 金丝雀发布完成

注意:因为有部分版本在线上运行,我们能够对其日志进行观察和追踪、定位问题;如果有问题也能快速将新版本清理掉;

kubectl delete deploy my-app-v1

实操总结

从实操的过程中,发现金丝雀发布较慢;

但是风险比较小,如果对代码信心不足的情况, 可以采用此方法,影响范围较小。

具体的实操过程,可以参见 尼恩的视频。

实验完成,可以清理所有服务

kubectl delete all -l app=my-app

上面是按照流量的pod的比例,进行 流量的控制。

Service会对提供同一个服务的多个Pod进行聚合,并且提供一个统一的入口地址,通过访问Service的入口地址就能访问到后面的Pod服务。

Service底层的 流量分发策略,默认为随机或者 轮询,具体与proxy代理的策略有关系。但是无论 随机或者 轮询, 整体上都是按照pod的比例,进行流量的分发。

除了按照pod的比例分流,如果你想用更精细粒度的话,可以使用 滚动发布。如下图所示:

Deployment实现滚动发布

利用Deployment的滚动更新策略maxSurge和maxUnavailable设置最大可超期望的节点数和最大不可用节点数可实现简单的金丝雀发布。

rollingUpdate.maxSurge最大可超期望的节点数,百分比 10% 或者绝对数值 5

rollingUpdate.maxUnavailable最大不可用节点数,百分比或者绝对数值

滚动更新步骤:

  1. 准备一个新版本的 POD,比如新版本为 V2,旧版本为 V1。
  2. 当 V2 版本的 POD 准备好后,在负载均衡中的实例池中将 V2 的版本加入。
  3. 在实例池中剔除一个 V1 版本的 POD。
  4. 逐个实例替换,直到每个版本都是 V2 版本。

如下图所示:

滚动更新使用的 YAML 方式如下:

spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 一次可以添加多少个Pod
      maxUnavailable: 1  # 滚动更新期间最大多少个Pod不可用

我们准备两个版本, app-v1.yaml 文件。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v1
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: v1.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v1.0.0
            - name: env_flag
              value: VERSION-v1.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
    - name: http
      port: 8008   #对应deployment的容器端口
      targetPort: http
      nodePort: 30808 #外部端口
  selector:
    app: my-app

然后我们再准备一下滚动更新的 v2 版本,app-v2-rolling.yaml 文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v2
  labels:
    app: my-app
spec:
  replicas: 3
  # maxUnavailable设置为0可以完全确保在滚动更新期间服务不受影响,还可以使用百分比的值来进行设置。
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: my-app
      version: v2.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v2.0.0
            - name: env_flag
              value: VERSION-v2.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5

接下来,我们按如下步骤进行操作:

  1. 启动 app-v1 应用
  2. 启动 app-v2-rolling 应用
  3. 观察所有容器版本变为 V2 版本

step1 :启动 V1 服务,查看服务是否正确,然后观察一下服务。

cd  /vagrant/chapter28/k8s/deployPolicy

kubectl apply -f app-v1.yaml

watch kubectl get pod 

kubectl get svc -l app=my-app

curl http://192.168.49.2:30808

while sleep 1; do curl http://192.168.49.2:30808 | egrep VERSION; done

启动 app-v1 应用并观察,都已经启动,我们进行接口调用。

step2: 启动 app-v2-rolling 进行滚动发布

打开一个新的窗口,然后执行滚动更新命令

kubectl apply -f app-v2-rolling.yaml

在 watch 的终端观察,开始的时候并没删除旧的 pod,而是创建好新的 pod 后,

step3:观察所有容器版本变为 V2 版本

然后进行挨个替,我们可以使用如下命令观察接口请求, 渐渐的有了第二个版本的请求。

while sleep 1; do curl http://192.168.49.2:30808 | egrep VERSION; done

在这个过程中,我们发现第二个版本有问题,我们需要进行回滚,此时我们需要执行一下如下命令

kubectl rollout undo deploy my-app

如果想两个版本都观察一下,这个时候需要执行命令。

kubectl rollout pause deploy my-app

如果发现第二个版本没有问题,那么我们要恢复执行

kubectl rollout resume deploy my-app

最后我们清理一下所有的部署

kubectl delete -l app=my-app

实操总结

从实操的过程中,发现:滚动部署没有控制流量的情况;各个版本部署的时候需要一定的时间。

具体的实操过程,可以参见 尼恩的视频。

实验完成,可以清理所有服务

kubectl delete all -l app=my-app

Deployment实现蓝绿部署

我们需要准备两个版本,一个蓝版本,一个绿蓝本,这两个版本同时存在,如下图所示:

且两个版本是独立的,这个时候可以瞬间对两个版本的切换。

接下来,我们采用 svc 的方式,通过 label selector 来进行版本之间的选择。

selector:
  app: my-app
  version: v1.0.0

我们创建一下 app-v1-svc.yaml 文件,我们首先创建一个 svc 服务,然后通过 label selector 来指定一下版本。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v1
  labels:
    app: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
      version: v1.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v1.0.0
            - name: env_flag
              value: VERSION-v1.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
    - name: http
      port: 8008   #对应deployment的容器端口
      targetPort: http
      nodePort: 30808 #外部端口
  selector:
    app: my-app
    # 注意这里我们匹配 app 和 version 标签,当要切换流量的时候,我们更新 version 标签的值,比如:v2.0.0
    version: v1.0.0

接下来,我们再创建另一个版本 app-v2.yaml 文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v2
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
      version: v2.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
    spec:
      containers:
        - name: my-app
          image: nien/nginx-gateway:v0.0.1
          ports:
            - name: http
              containerPort: 8008
            - name: probe
              containerPort: 8008
          env:
            - name: VERSION
              value: v2.0.0
            - name: env_flag
              value: VERSION-v2.0.0
          livenessProbe:
            httpGet:
              path: /env
              port: probe
            initialDelaySeconds: 5
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /env
              port: probe
            periodSeconds: 5

接下来,我们按如下步骤执行:

  1. 启动版本 1 服务
  2. 启动版本 2 服务
  3. 将版本 1 服务切换到版本 2,观察服务情况

step1 :启动 V1 服务,查看服务是否正确,然后观察一下服务。

启动版本的服务并观察,没有问题。

cd  /vagrant/chapter28/k8s/blueGreenPolicy

kubectl apply -f app-v1-svc.yaml

watch kubectl get pod 

kubectl get svc -l app=my-app

curl http://192.168.49.2:30808

while sleep 1; do curl http://192.168.49.2:30808 | egrep VERSION; done

step2:启动 V2 的服务版本

启动版本 2 的服务, 因为版本 2 没有挂到 SVC,所以没有办法观察,但是我们可以先启动。

kubectl apply -f app-v2.yaml

step3:将版本 1 服务切换到版本 2,观察服务情况

这个时候我们进行版本的切换,通过切换标签的方式

kubectl patch service my-app   -p'{"spec":{"selector":{"version":"v2.0.0"}}}'  

同时,当发现问题的时候,我们再把版本切回到 v1.0.0 即可。

kubectl patch service my-app   -p'{"spec":{"selector":{"version":"v1.0.0"}}}'  

看看请求的变化

patch

如果一个pod已经在运行,这时需要对pod属性进行修改,又不想删除pod,或不方便通过replace的方式进行更新,这时就可以使用patch命令。

命令格式

kubectl patch \
        (-f FILENAME | TYPE NAME) \
        [-p PATCH|--patch-file FILE] \
        [options]

实操总结

从实操的过程中,发现:蓝绿部署需要准备两套资源,相对有的时候需要的资源会多; 这种情况可以快速还原版本,不会出现滚动更新那样,回滚需要的时间会很久。

具体的实操过程,可以参见 尼恩的视频。

实验完成,可以清理所有服务

kubectl delete all -l app=my-app

Ingress Annotations实现金丝雀发布

Ingress-Nginx 是一个K8S ingress工具,支持配置 Ingress Annotations 来实现不同场景下的灰度发布和测试。 Nginx Annotations 支持以下 4 种 Canary 规则:

  • nginx.ingress.kubernetes.io/canary-by-header:基于 Request Header 的流量切分,适用于灰度发布以及 A/B 测试。当 Request Header 设置为 always时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never时,请求不会被发送到 Canary 入口;对于任何其他 Header 值,将忽略 Header,并通过优先级将请求与其他金丝雀规则进行优先级的比较。
  • nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。当 Request Header 设置为此值时,它将被路由到 Canary 入口。该规则允许用户自定义 Request Header 的值,必须与上一个 annotation (即:canary-by-header)一起使用。
  • nginx.ingress.kubernetes.io/canary-weight:基于服务权重的流量切分,适用于蓝绿部署,权重范围 0 - 100 按百分比将请求路由到 Canary Ingress 中指定的服务。权重为 0 意味着该金丝雀规则不会向 Canary 入口的服务发送任何请求。权重为 100 意味着所有请求都将被发送到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分,适用于灰度发布与 A/B 测试。用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务的cookie。当 cookie 值设置为 always时,它将被路由到 Canary 入口;当 cookie 值设置为 never时,请求不会被发送到 Canary 入口;对于任何其他值,将忽略 cookie 并将请求与其他金丝雀规则进行优先级的比较。

注意:金丝雀规则按优先顺序进行如下排序:

canary-by-header - > canary-by-cookie - > canary-weight

我们可以把以上的四个 annotation 规则可以总体划分为以下两类:

  • 基于权重的 Canary 规则

  • 基于用户请求的 Canary 规则

注意: Ingress-Nginx 实在0.21.0 版本 中,引入的Canary 功能,因此要确保ingress版本OK

Ingress Annotations实现金丝雀发布 实操

在 《K8S学习圣经》 最新PDF中给出,具体请参见 公众号: 技术自由圈

华为云的金丝雀发布

采用金丝雀部署,你可以在生产环境的基础设施中小范围的部署新的应用代码。

一旦应用签署发布,只有少数用户被路由到它。最大限度的降低影响。

如果没有错误发生,新版本可以逐渐推广到整个基础设施。

下图示范了金丝雀部署:

下图为华为云的金丝雀发布界面:

步骤一:将流量从待部署节点移出,更新该节点服务到待发布状态,将该节点称为金丝雀节点;

步骤二:根据不同策略,将流量引入金丝雀节点。

策略可以根据情况指定,比如随机样本策略(随机引入)、狗粮策略(就是内部用户或员工先尝鲜)、分区策略(不同区域用户使用不同版本)、用户特征策略(这种比较复杂,需要根据用户个人资料和特征进行分流,类似于千人千面);

步骤三:金丝雀节点验证通过后,选取更多的节点称为金丝雀节点,

重复步骤一步骤二,直到所有节点全部更新

金丝雀部署和蓝绿有点像,但是它更加规避风险。

你可以阶段性的进行,而不用一次性从蓝色版本切换到绿色版本。

参考

1、《k8s学习圣经》PDF

2、https://blog.csdn.net/qq_42494960/article/details/119385952

技术自由的实现路径:

实现你的 架构自由:

吃透8图1模板,人人可以做架构

10Wqps评论中台,如何架构?B站是这么做的!!!

阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了

峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?

100亿级订单怎么调度,来一个大厂的极品方案

2个大厂 100亿级 超大流量 红包 架构方案

… 更多架构文章,正在添加中

实现你的 响应式 自由:

响应式圣经:10W字,实现Spring响应式编程自由

这是老版本 《Flux、Mono、Reactor 实战(史上最全)

实现你的 spring cloud 自由:

Spring cloud Alibaba 学习圣经》 PDF

分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)

一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)

实现你的 linux 自由:

Linux命令大全:2W多字,一次实现Linux自由

实现你的 网络 自由:

TCP协议详解 (史上最全)

网络三张表:ARP表, MAC表, 路由表,实现你的网络自由!!

实现你的 分布式锁 自由:

Redis分布式锁(图解 - 秒懂 - 史上最全)

Zookeeper 分布式锁 - 图解 - 秒懂

实现你的 王者组件 自由:

队列之王: Disruptor 原理、架构、源码 一文穿透

缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)

缓存之王:Caffeine 的使用(史上最全)

Java Agent 探针、字节码增强 ByteBuddy(史上最全)

实现你的 面试题 自由:

4000页《尼恩Java面试宝典 》 40个专题

猜你喜欢

转载自blog.csdn.net/crazymakercircle/article/details/129798023