跳过正文
  1. Posts/

K8s如何实现滚动升级

·333 字·2 分钟·
Kubehan
作者
Kubehan
云原生知识栈:深度解析容器技术、Kubernetes、Istio、DevOps 实践、Prometheus 监控、Envoy 代理、Golang 开发及云原生架构与微服务趋势的专业博客

K8s如何实现滚动升级
#

k8s滚动更新机制:
#

k8s创建副本应用程序的最佳方法就是部署(Deployment),部署自动创建副本集(ReplicaSet),副本集可以精确地控制每次替换的Pod数量,从而可以很好的实现滚动更新。具体来说,k8s每次使用一个新的副本控制器(replication controller)来替换已存在的副本控制器,从而始终使用一个新的Pod模板来替换旧的pod模板。
大致步骤如下:

  1. 创建一个新的replication controller。
  2. 增加或减少pod副本数量,直到满足当前批次期望的数量。
  3. 删除旧的replicationplication controller。
    #### 实战演示:
使用kubectl更新一个已部署的应用程序,并模拟回滚。为了方便分析,将应用程序的pod副本数量设置为10。  
扩容副本数量

<pre><code class="language-bash">kubectl -n k8s-apps scale deployment helloworldapi  --replicas=10</code></pre>

模拟一下nginx服务
查看部署列表

kubectl get deployments -n k8s-apps

查看在运行的pod

kubectl get pods -n k8s-apps

通过pod描述,查看应用程序的当前映像版本,这里应该是能看到创建的10个副本

[root@OPPO-test ~]# kubectl describe pods helloworldapi-68d7f6dd8-6tqgl -n k8s-apps | grep image
Normal  Pulled     55s   kubelet, k8s-2  Container image "nginx:1.16.0" already present on machine

得知该镜像使用的是1.16.0版本的nginx镜像。现在需要将其升级到1.17.0

[root@OPPO-test ~]# kubectl -n k8s-apps set image deployment/helloworldapi nginx=nginx:1.17.0 --record 
deployment.apps/helloworldapi image updated

验证升级成功:
检查rollout状态

[root@OPPO-test ~]# kubectl -n k8s-apps  rollout status deployments/helloworldapi 
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 9 out of 10 new replicas have been updated...
Waiting for deployment "helloworldapi" rollout to finish: 2 old replicas are pending termination...

正在挨个升级
检查镜像版本
和上面一样的命令

kubectl describe pods  -n k8s-apps | grep image

回滚发布

[root@OPPO-test ~]# kubectl -n k8s-apps rollout undo deployments/helloworldapi
deployment.apps/helloworldapi rolled back

查看版次

kubectl -n k8s-ecoysystem-apps rollout history deployment/helloworldapi

回滚到指定版次

kubectl -n k8s-ecoysystem-apps rollout undo deployment/helloworldapi  --to-revision=<版次>

原理
k8s精确地控制着整个发布过程,分批次有序地进行着滚动更新,直到把所有旧的副本全部更新到新版本。实际上,k8s是通过两个参数来精确地控制着每次滚动的pod数量:

maxSurge 滚动更新过程中运行操作期望副本数的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。
maxUnavailable 滚动更新过程中不可用的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。

kubectl -n k8s-apps get deployment helloworldapi -o yaml

查看yaml里面的参数

spec:
  progressDeadlineSeconds: 600
  replicas: 10
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: helloworldapi
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
[root@OPPO-test ~]# kubectl get deployments.apps -n k8s-apps 
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
helloworldapi   10/10   10           10          18m

DESIRED 最终期望处于READY状态的副本数
CURRENT 当前的副本总数
UP-TO-DATE 当前完成更新的副本数
AVAILABLE 当前可用的副本数
在你执行更新的时候就会出现这样的界面,展示正在进行的更新

[root@OPPO-test ~]# kubectl get deployments.apps -n k8s-apps 
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
helloworldapi   8/10    5            8           19m

当前可用的副本数 = 总共副本数量 - 总共副本数量 25% = ,所以AVAILABLE为8。
当前的副本总数 = 10 + 10
25% = 13
此时你会发现有13个pod,等待升级完成后就会恢复10个,

理想状态下的滚动过程:

创建了一个新的副本集,并为其分配3个新版本的pod,使副本总数达到13,一切正常。
通知旧副本集,销毁2个旧版本的pod,使可用副本总数保持到8,一起正常。
当两个副本销毁成功后,通知新副本集,再新增2个新版本的pod,使副本总数达到13,一切正常。
只要销毁成功,新副本集就会创造新的pod,一直循环,直到旧的副本集pod数量为0。
滚动升级一个服务,实际就是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧RS中的副本数减小到0的复合操作;

无论理想还是不理想,k8s最终都会使应用程序全部更新到期望状态,都会始终保持最大的副本总数和可用副本总数的不变性!!!