k8s 应用更新策略:灰度发布和蓝绿发布

Posted 笨小孩@GF 知行合一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s 应用更新策略:灰度发布和蓝绿发布相关的知识,希望对你有一定的参考价值。

  • 生产环境如何实现蓝绿部署?

  • 什么是蓝绿部署?

  • 蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的、正在运行的系统,只是系统版本和对外服务情况不同。

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

  • 蓝色系统不对外提供服务,用来做什么呢?

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

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

  • 切换后的一段时间内,依旧是蓝绿两套系统并存,但是用户访问的已经是蓝色系统。这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。
  • 当确信对外提供服务的蓝色系统工作正常,不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。 原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。
  • 蓝绿部署的优势和缺点

  • 优点:
    1、更新过程无需停机,风险较少
    2、回滚方便,只需要更改路由或者切换 DNS 服务器,效率较高

  • 缺点:
    1、成本较高,需要部署两套环境。如果新版本中基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户。
    2、需要部署两套机器,费用开销大
    3、在非隔离的机器(Docker、VM)上操作时,可能会导致蓝绿环境被摧毁风险
    4、负载均衡器/反向代理/路由/DNS 处理不当,将导致流量没有切换过来情况出现

  • 通过 k8s 实现线上业务的蓝绿部署

  • Kubernetes 不支持内置的蓝绿部署。目前最好的方式是创建新的 deployment,然后更新应用程序的 service 以指向新的 deployment 部署的应用
  • 创建绿色部署环境(旧的部署环境)

  • 下面步骤在 k8s 的控制节点操作:
    # kubectl create ns blue-green
    # vim lv.yaml

    创建前端 service
    vim service_lanlv.yaml

  • 创建蓝色环境(新的部署环境)
    vim lan.yaml

  • 在浏览器访问 http://k8s-master 节点 ip:30062 显示如下:

  • 修改 service_lanlv.yaml 配置文件,修改标签,让其匹配到蓝程序(升级之后的程序)

  • 实验完成之后,把资源先删除,以免影响后面实验:
    kubectl delete -f lan.yaml
    kubectl delete -f lv.yaml
    kubectl delete -f service_lanlv.yaml

  • 通过 k8s 实现滚动更新-滚动更新流程和策略

  • 滚动更新简介

  • 滚动更新是一种自动化程度较高的发布方式,用户体验比较平滑,是目前成熟型技术组织所采用的主流发布方式,一次滚动发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义),例如第一批 1 台,第二批 10%,第三批 50%,第四批 100%。每个批次之间留观察间隔,通过手工验证或监控反馈确保没有问题再发下一批次,所以总体上滚动式发布过程是比较缓慢

  • 在 k8s 中实现滚动更新
  • 首先看下 Deployment 资源对象的组成:
    kubectl explain deployment
    kubectl explain deployment.spec

     paused <boolean>   #暂停,当更新的时候创建 pod 先暂停,不是立即更新
     revisionHistoryLimit <integer>    #保留的历史版本数,默认是 10 个
    strategy <Object>      #更新策略,支持的滚动更新策略  Default is RollingUpdate.
     
    #支持两种更新,Recreate 和 RollingUpdate 
    #Recreate 是重建式更新,删除一个更新一个
    #RollingUpdate 滚动更新,定义滚动更新的更新方式的,也就是 pod 能多几个,少几个,控制更新力度的

    maxSurge <string>  #更新的过程当中最多允许超出的指定的目标副本数有几个;它有两种取值方式,第一种直接给定数量,第二种根据百分比,百分比表示原本是 5 个,最多可以超出 20%,那就允许多一个,最多可以超过 40%,那就允许多两个
    maxUnavailable <string> #最多允许几个不可用 ,假设有 5 个副本,最多一个不可用,就表示最少有 4 个可用
  • 自定义滚动更新策略
    maxSurge 和 maxUnavailable 用来控制滚动更新的更新策略
    取值范围
    数值
    1. maxUnavailable: [0, 副本数]
    2. maxSurge: [0, 副本数]
    注意:两者不能同时为 0。
    比例
    1. maxUnavailable: [0%, 100%] 向下取整,比如 10 个副本,5%的话==0.5 个,但计算按照 0个;
    2. maxSurge: [0%, 100%] 向上取整,比如 10 个副本,5%的话==0.5 个,但计算按照 1 个;
    注意:两者不能同时为 0。

    建议配置
    1. maxUnavailable == 0
    2. maxSurge == 1
    这是我们生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:
    1 个新版本 pod ready(结合 readiness)后,才销毁旧版本 pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是“太慢”了。

     

  • 总结:
    maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
    maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。

  • 查看默认的滚动更新策略
    #最多允许多 25%个 pod,25%表示不足一个,可以补一个

  • 查看控制器的滚动历史
    kubectl rollout history deployment mongodb-kubernetes-operator

    回滚操作:
    kubectl rollout undo deployment/mongodb-kubernetes-operator  --to-revision=1

    自定义策略:
    修改更新策略:maxUnavailable=1,maxSurge=1 

    kubectl patch deployments.apps mongodb-kubernetes-operator -p '"spec":"strategy":"rollingUpdate":"maxSurge":1,"maxUnavailable":1'

    显示如下:
    RollingUpdateStrategy: 1 max unavailable, 1 max surge
    上面可以看到 RollingUpdateStrategy: 1 max unavailable, 1 max surge 
    这个 rollingUpdate 更新策略变成了刚才设定的,因为我们设定的 pod 副本数是 3,1 和 1 表示最少不能少于 2 个 pod,最多不能超过 4 个 pod 
    这个就是通过控制 RollingUpdateStrategy 这个字段来设置滚动更新策略 

  • 通过 k8s 完成线上业务的金丝雀发布

  • 金丝雀发布简介

  • 金丝雀发布的由来:17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;当瓦斯含量超过一定限度时,虽然人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为瓦斯检测指标,以便在危险状况下紧急撤离。

  • 金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发 1 台,或者一个小比例,例如 2%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试 (国内常称灰度测试)。

  • 简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。 如果金丝测试通过,则把剩余的 V1 版本全部升级为 V2 版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。

  • 优点:灵活,策略自定义,可以按照流量或具体的内容进行灰度(比如不同账号,不同参数),出现问题不会影响全网用户
    缺点:没有覆盖到所有的用户导致出现问题不好排查

  • 在 k8s 中实现金丝雀发布
    打开一个标签 1 监测更新过程
    kubectl get pods -l app=myapp -n blue-green -w

  • 打开另一个标签 执行如下操作:
    kubectl set image deployment myapp-v1 myapp=janakiramm/myapp:v2 -n blue-green && kubectl rollout pause deployment myapp-v1 -n blue-green

    注:上面的解释说明把 myapp 这个容器的镜像更新到 janakiramm/myapp:v2 版本 ,更新镜像之后,创建一个新的 pod 就立即暂停,这就是我们说的金丝雀发布;
    如果暂停几个小时之后没有问题,那么取消暂停,就会依次执行后面步骤,把所有 pod 都升级

  • 解除暂停:
    回到标签 1 继续观察:

  • 打开标签 2 执行如下:
    kubectl rollout resume deployment myapp-v1 -n blue-green

  • kubectl get rs -n blue-green
    可以看到 replicaset 控制器有 2 个了

  • 回滚:
    如果发现刚才升级的这个版本有问题可以回滚,查看当前有哪几个版本:
    kubectl rollout history deployment myapp-v1 -n blue-green

    上面说明一共有两个版本,回滚的话默认回滚到上一版本,可以指定参数回滚:
    kubectl rollout undo deployment myapp-v1 -n blue-green --to-revision=1
    #回滚到的版本号是 1
    kubectl rollout history deployment myapp-v1 -n blue-green

    上面可以看到第一版没了,被还原成了第三版,第三版的前一版是第二版 

     以看到下面的 rs 已经用第一个了,这个就是还原之后的 rs

  • 自定义 CRD 资源

    通过 crd 部署 mongodb 集群

    部署 mongodb-aperator
    1、项目地址
    https://github.com/mongodb/mongodb-kubernetes-operator.git 找到 0.5.0,看这个版本对应使用

    2、创建名称空间 mongodb,并进入到 mongodb-kubernetes-operator 目录应用 crd 资源,
    创建自定义资源类型
    kubectl create ns mongodb
    cd mongodb-kubernetes-operator-0.5.0
    kubectl apply -f deploy/crds/mongodb.com_mongodbcommunity_crd.yaml

    #查看 mongodb 是否创建成功
    kubectl get crd/mongodbcommunity.mongodb.com


    3、安装 operator
    kubectl apply -f deploy/operator/ -n mongodb

    提示:mongodb-kubernetes-operator 这个项目是将自定义控制器和自定义资源类型分开实现的;其 operator 只负责创建和监听对应资源类型的变化,在资源有变化时,实例化为对应资源对象,并保持对应资源对象状态吻合用户期望状态;上述四个清单中主要是创建了一个 sa 账户,并对对应的 sa 用户授权;


    验证:查看 operator 是否正常运行
    kubectl get pods -n mongodb

    验证:使用自定义资源类型创建一个 mongodb 副本集集群
    kubectl apply -f deploy/crds/mongodb.com_v1_mongodbcommunity_cr.yaml -n mongodb
    kubectl get pods -n mongodb

    提示:这里可以看到对应 pod 处于 pending 状态;
     查看 pod 详细信息

    提示:这里提示没有可以用的 pvc; 4 pod has unbound immediate PersistentVolumeClaims.
    删除 mongodb 名称空间下 pvc
    kubectl get pvc -n mongodb
    kubectl delete pvc --all -n mongodb

    创建 pv 和 pvc
    vim pv-demo.yaml


    在 nfs 服务器 上创建 nfs 共享目录
    mkdir /data/p1,2,3

    创建 pvc 资源
    vim pvc-demo.yaml

     可以看到对应的pod已经正常跑起来了;

    验证:连接mongodbpod,看看对应副本集集群是否工作正常?

以上是关于k8s 应用更新策略:灰度发布和蓝绿发布的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes 实现灰度和蓝绿发布

蓝绿发布灰度发布和滚动发布

一文了解蓝绿发布/灰度发布/滚动发布

一文搞懂蓝绿发布灰度发布和滚动发布

一文搞懂蓝绿发布灰度发布和滚动发布(转)

蓝绿部署滚动发布灰度发布的介绍以及最佳实践