【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新

前言

大家好,我是秋意零。

在上一篇中,我们介绍了控制器的基本设计思想:控制器模式。通过这个 “控制器模式” 我们来看看 Deployment 是如何依靠它来实现的。

最近搞了一个扣扣群,旨在技术交流、博客互助,希望各位大佬多多支持!

获取方式:

  • 1.在我主页推广区域,如图:

在这里插入图片描述

  • 2.文章底部推广区域,如图:

在这里插入图片描述

简介

  • 个人主页: 秋意零
  • 个人介绍:在校期间参与众多云计算相关比赛,如: “省赛”、“国赛”,并斩获多项奖项荣誉证书
  • 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,暑假开始实习
  • 账号:各个平台, 秋意零 账号创作者、 云社区 创建者
  • 欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万

在这里插入图片描述

系列文章目录


【云原生|探索 Kubernetes-1】容器的本质是进程
【云原生|探索 Kubernetes-2】容器 Linux Cgroups 限制
【云原生|探索 Kubernetes 系列 3】深入理解容器进程的文件系统
【云原生|探索 Kubernetes 系列 4】现代云原生时代的引擎
【云原生|探索 Kubernetes 系列 5】简化 Kubernetes 的部署,深入解析其工作流程



更多点击专栏查看:深入探索 Kubernetes

文章目录

  • 前言
  • 系列文章目录
  • 一、介绍水平扩展、水平收缩、滚动更新
  • 二、水平扩展/收缩的实现
  • 三、滚动更新
  • 四、回滚
    • 回滚到上一个版本
    • 回滚到更早之前版本
    • 删除多余的 RplicaSet
  • 总结

正文开始

  • 快速上船,马上开始掌舵了(Kubernetes),距离开船还有 3s,2s,1s…

在这里插入图片描述

一、介绍水平扩展、水平收缩、滚动更新

Deployment 实现了非常重要的功能:Pod 的水平扩展、水平收缩、滚动更新。

举个栗子

想象一个场景,现在我们有一个 Deployment 控制器上面部署的是一个 Web 服务,期望 Pod 的个数为:3。对外发布后,起初用户量比较少,我们的 Web 服务还能扛住,但是某一天(618、双11)为了宣传搞活动,导致用户量访问量突然暴涨,这个时候我们 3 个 Pod 部署的 Web 服务就扛不住了

  • 这个时候,我们怎么办呢?当活动结束访问量不大的时候怎么办?手动一个一个添加、删除 Pod 服务吗?这种显然是不现实的。因为,手动操作即费时间,又费人力资源,最重要的是损失了大量流量导致错过商机。

  • 这种情况下就需要使用水平扩展、水平收缩(弹性机制)了。而我们控制器就包含这些功能,看看是怎么实现的吧。

    • 水平扩展:我们可以设置一个资源阈值,当 CPU 或者 Mem 利用率达到 80% 或 90% 时就利用 Deployment 扩展我们 Pod 服务;
    • 水平收缩:当 CPU 或者 Mem 利用率降低到 20% 或 40% 时就利用 Deployment 收缩我们 Pod 服务。
  • 如果 Web 程序需要更新版本这时候怎么办?

    • 滚动更新:滚动更新,在 Kubernetes 中就是替换掉 YAML 文件中的镜像版本,替换之后,控制器会重新创建一组新版本的服务,一个新版 Pod 服务创建成功之后,会删除一个旧版本的 Pod 服务,这样依次循环直到替换完毕;如果新版不稳定也可以马上回到之前旧版本,这个操作称为:“回滚”。这样的好处是对于用户是透明的,无感知的;对于管理人员来说是便捷高效的。

注意:目前这篇还不会提到监控资源的利用率自动来扩展和收缩 Pod(感兴趣可以先去了解 HorizontalPodAutoscaler(HPA)),这里介绍的是手动执行命令来扩展和收缩 Pod

二、水平扩展/收缩的实现

知道了这三个功能水平扩展、水平收缩、滚动更新,那么我们就来看看它们是由谁实现的,是 Deployment ?

其实答案在上一篇中结尾部分,我们介绍了 Deployment 管理的 Pod ,这个 Pod 的 ownerReference(所有者)是 ReplicaSet;ReplicaSet 的 ownerReference(所有者)是 Deployment。

答案:所以,水平扩展、水平收缩、滚动更新三个功能主要依靠 ReplicaSet 来实现。不过还是需要 Deployment 管理辅助。

明白了这个原理之后,我们接着来看看 Deployment,如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3  # 指定副本数量
  selector:
    matchLabels:
      app: nginx  # 选择标签为`app: nginx`的Pod进行管理
  template:
    metadata:
      labels:
        app: nginx  # Pod的标签,与 matchLabels 字段下的标签绑定
    spec:
      containers:
        - name: nginx-web
          image: nginx  # 指定应用程序的镜像
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80  # 应用程序监听的端口号

上述 Deployment 的 YAML 文件,可以用下图表示:

  • 通过这张图,我们可以看到,一个定义了 replicas: 3 的 Deployment 与 ReplicaSet 和 Pod 的关系结构,是 “层层控制” 的。
  • ReplicaSet 负责通过 “控制器模式”,保证 Pod 的个数永远是 YAML 文件中所期望的个数(replicas: 3),所以 Deployment 只允许容器的 restartPolicy=Always ,这样才能保证,容器始终是 Running 状态的前提下,ReplicaSet 调整 Pod 的个数才有意义。

【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新_第1张图片
Deployment 同样通过 “控制器模式”,来操作 ReplicaSet 的个数和属性,从而实现 “水平扩展 / 收缩” 和 “滚动更新” 这两个编排动作。

“水平扩展 / 收缩” 的实现,Deployment 只需要修改它所控制的 ReplicaSet 的 Pod 副本个数就可以了,也就是 replicas: 3 字段。我们将上面 Deployment 的 YAML 文件创建,如下:

1.创建 Deployment:

[root@master01 yaml]# kubectl apply -f deploy-web.yaml
deployment.apps/nginx-deployment created
[root@master01 yaml]#
[root@master01 yaml]# kubectl get -f deploy-web.yaml
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           6s

2.扩展 Pod 的副本数为:6

[root@master01 yaml]# kubectl scale deployment nginx-deployment --replicas=6
deployment.apps/nginx-deployment scaled
[root@master01 yaml]#
[root@master01 yaml]# kubectl get -f deploy-web.yaml
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   6/6     6            6           119s
[root@master01 yaml]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-54fdb8fb59-948nn   1/1     Running   0          2s
nginx-deployment-54fdb8fb59-bgqhd   1/1     Running   0          3m13s
nginx-deployment-54fdb8fb59-hl9pv   1/1     Running   0          2s
nginx-deployment-54fdb8fb59-ptwz2   1/1     Running   0          3m13s
nginx-deployment-54fdb8fb59-s9rkp   1/1     Running   0          2s
nginx-deployment-54fdb8fb59-wf4mh   1/1     Running   0          2s

3.收缩 Pod 的副本数为:2

[root@master01 yaml]# kubectl scale deployment nginx-deployment --replicas=2
deployment.apps/nginx-deployment scaled
[root@master01 yaml]#
[root@master01 yaml]# kubectl get -f deploy-web.yaml
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           2m46s
[root@master01 yaml]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-54fdb8fb59-bgqhd   1/1     Running   0          2m59s
nginx-deployment-54fdb8fb59-ptwz2   1/1     Running   0          2m59s
[root@master01 yaml]#

三、滚动更新

首先查看 Deployment 所控制的 ReplicaSet

这个 ReplicaSet 的名字,是由 Deployment 的名字和一个随机字符串共同组成。这个随机字符串叫作 pod-template-hash,在我们这个例子里就是:54fdb8fb59。ReplicaSet 会把这个随机字符串加在它所控制的所有 Pod 的标签里,从而保证这些 Pod 不会与集群里的其他 Pod 混淆。

[root@master01 yaml]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   2         2         2       65s

现在,修改了 Deployment 的 Pod 模板,“滚动更新” 就会被自动触发。

我们可以使用 kubectl edit 指令编辑 Etcd 里的 API 对象。 kubectl edit 指令,会帮你直接打开 nginx-deployment 的 API 对象。然后,你就可以修改这里的 Pod 模板部分了。

  • kubectl edit 并不神秘,它不过是把 API 对象的内容下载到了本地文件,让你修改完成后再提交上去。

1.修改 deployment 模板。

这里将原本镜像是: nginx:latest 的版本,修改为:nginx:alpine

kubectl edit deploy/nginx-deployment

【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新_第2张图片

2.通过查看 Deployment 的 Events,看到这个“滚动更新”的流程:

  • 第二条 Events:Deployment 首先创建了一个新的 ReplicaSet (nginx-deployment-86d5bf894b),初始 Pod 副本数为:0。
  • 第三条 Events:缩放 ReplicaSet 控制器 nginx-deployment-54fdb8fb59 从 3 缩小到 2。
  • 第四条 Events:缩放 ReplicaSet 控制器 nginx-deployment-86d5bf894b 从1 放大到 2。
  • 第五条 Events:缩放 ReplicaSet 控制器 nginx-deployment-54fdb8fb59 从 2 缩小到 1。
  • 第六条 Events:缩放 ReplicaSet 控制器 nginx-deployment-86d5bf894b 从 2 放大到 3。
  • 第七条 Events:缩放 ReplicaSet 控制器 nginx-deployment-54fdb8fb59 从1 缩小到 0。

像这样,交替逐一升级的过程,就是 “滚动更新”。这个过程保证了用户的体验,因为在升级的过程中,只有当新版本的运行成功之后旧版本才会删除,所以这个过程始终都会有服务提供给用户。

[root@master01 ~]# kubectl describe deploy/nginx-deployment
...
...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  55m   deployment-controller  Scaled up replica set nginx-deployment-54fdb8fb59 to 3
  Normal  ScalingReplicaSet  32m   deployment-controller  Scaled up replica set nginx-deployment-86d5bf894b to 1
  Normal  ScalingReplicaSet  31m   deployment-controller  Scaled down replica set nginx-deployment-54fdb8fb59 to 2 from 3
  Normal  ScalingReplicaSet  31m   deployment-controller  Scaled up replica set nginx-deployment-86d5bf894b to 2 from 1
  Normal  ScalingReplicaSet  31m   deployment-controller  Scaled down replica set nginx-deployment-54fdb8fb59 to 1 from 2
  Normal  ScalingReplicaSet  31m   deployment-controller  Scaled up replica set nginx-deployment-86d5bf894b to 3 from 2
  Normal  ScalingReplicaSet  31m   deployment-controller  Scaled down replica set nginx-deployment-54fdb8fb59 to 0 from 1

3.再次查看 ReplicaSet:

  • 这里,可以看到有两个 ReplicaSet,一个新创建的,一个旧的。旧的 ReplicaSet 还存在的意义就是为了保证,切换为之前的版本,“回滚” 的操作。
[root@master01 yaml]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   0         0         0       25m
nginx-deployment-86d5bf894b   3         3         3       2m13s

综上所述,再来看看此时 Deployment、ReplicaSet 和 Pod 的关系图(黄色代表旧 Pod,绿色代表新 Pod,目前状态是 新 Pod 只更新了一个):

  • 通过图我们了解到,Deployment 可以控制 ReplicaSet 的数量,以及每个 ReplicaSet 的属性;
  • 而一个应用的版本,对应的是一个 ReplicaSet。

【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新_第3张图片

四、回滚

首先,我们使用 kubectl set image 的指令,直接修改 nginx-deployment 所使用的镜像。这个命令的好处就是,你可以不用像 kubectl edit 那样需要打开编辑器。

这次,我们把镜像改为一个不存在的镜像,如改为 nginx:1.111,这个 Deployment 就会出现一个升级失败的版本(nginx-deployment-746bd689d9)。

1.修改 Deployment 的 image 版本:

[root@master01 ~]# kubectl get deploy -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES         SELECTOR
nginx-deployment   3/3     3            3           126m   nginx-web    nginx:alpine   app=nginx
[root@master01 ~]#
[root@master01 ~]# kubectl set image deploy/nginx-deployment nginx-web=nginx:1.111
deployment.apps/nginx-deployment image updated

2.查看 RplicaSet 情况:

  • nginx-deployment-746bd689d9 控制器,可以看到 READY 状态的个数为:0
[root@master01 ~]# kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     1            3           127m
[root@master01 ~]#
[root@master01 ~]# kubectl get rs   #746bd689d9
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   0         0         0       127m
nginx-deployment-746bd689d9   1         1         0       20s
nginx-deployment-86d5bf894b   3         3         3       104m

查看 Pod,可以看到不正常状态的 Pod。这是因为 “滚动更新” 被触发后,报错会立刻停止。

[root@master01 ~]# kubectl get pod
NAME                                READY   STATUS             RESTARTS   AGE
nginx-deployment-746bd689d9-qcsxf   0/1     ImagePullBackOff   0          34m
nginx-deployment-86d5bf894b-fzcd7   1/1     Running            0          138m
nginx-deployment-86d5bf894b-hc28d   1/1     Running            0          138m
nginx-deployment-86d5bf894b-vfkxg   1/1     Running            0          138m

回滚到上一个版本

执行一条 kubectl rollout undo 命令,就能把整个 Deployment 回滚到上一个版本:

kubectl rollout undo deployment/nginx-deployment

查看 RplicaSet

[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   0         0         0       170m
nginx-deployment-746bd689d9   0         0         0       43m
nginx-deployment-86d5bf894b   3         3         3       147m

回滚到更早之前版本

如果我想回滚到更早之前的版本,要怎么办呢?

1.首先,使用 kubectl rollout history 命令,查看每次 Deployment 变更对应的版本。

  • 我们的的操作从最开始依次顺序的记录在了这里,那次失败的更新操作,则对应的是版本 3,因为在这之前执行了回滚的命令。
[root@master01 ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         kubectl create --filename=deploy-web.yaml --record=true
3         kubectl create --filename=deploy-web.yaml --record=true
4         kubectl create --filename=deploy-web.yaml --record=true

2.查看对应版本细节。

通过 --revision=3 参数加上对应的步骤版本,就可以查看细节,如:

[root@master01 ~]# kubectl rollout history deployment/nginx-deployment --revision=3
deployment.apps/nginx-deployment with revision #3
Pod Template:
  Labels:       app=nginx
        pod-template-hash=746bd689d9
  Annotations:  kubernetes.io/change-cause: kubectl create --filename=deploy-web.yaml --record=true
  Containers:
   nginx-web:
    Image:      nginx:1.111
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>

3.回滚到指定版本。

通过 kubectl rollout undo 命令,加上 --to-revision=2 要回滚到的指定版本的版本号,就可以回到指定版本了。


[root@master01 ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=1
deployment.apps/nginx-deployment rolled back
[root@master01 ~]#

回到指定版本后,可以看到 RplicaSet 控制器也就发生了变化,一个 RplicaSet 对应一个版本

[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   3         3         3       3h5m
nginx-deployment-746bd689d9   0         0         0       57m
nginx-deployment-86d5bf894b   0         0         0       162m

删除多余的 RplicaSet

不过,Deployment 进行的每一次更新操作,都会生成一个新的 ReplicaSet 对象,是不是有些多余,甚至浪费资源呢?

  • 我们在确定了,不需要某个版本之后就可以将其删除。
[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   3         3         3       3h12m
nginx-deployment-746bd689d9   0         0         0       65m
nginx-deployment-86d5bf894b   0         0         0       169m

[root@master01 ~]# kubectl delete rs/nginx-deployment-746bd689d9
replicaset.apps "nginx-deployment-746bd689d9" deleted

[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   3         3         3       3h12m
nginx-deployment-86d5bf894b   0         0         0       169m

除了删除之外

  • Kubernetes 项目还提供了一个指令,使得我们对 Deployment 的多次更新操作,最后 只生成一个 ReplicaSet。
  • 具体的做法是,在更新 Deployment 前,你要先执行一条 kubectl rollout pause 指令。

步骤如下:

  • 1.让 Deployment 进入了 “暂停” 状态。
[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   3         3         3       3h12m
nginx-deployment-86d5bf894b   0         0         0       169m

[root@master01 ~]# kubectl rollout pause deployment/nginx-deployment
deployment.apps/nginx-deployment paused
  • 2.修改 Image 镜像版本。
[root@master01 ~]# kubectl set image deploy/nginx-deployment nginx-web=nginx:alpine
deployment.apps/nginx-deployment image updated
[root@master01 ~]#
[root@master01 ~]#  kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   3         3         3       3h46m
nginx-deployment-86d5bf894b   0         0         0       3h22m
  • 3.“恢复” Deployment
[root@master01 ~]#  kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed

[root@master01 ~]#  kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-54fdb8fb59   0         0         0       3h46m
nginx-deployment-86d5bf894b   3         3         3       3h23m

如果,你将 spec.revisionHistoryLimit 字段设置为:0;那么,你就不能做回滚操作了。

总结

今天讲解了,Deploymen 最基本的编排控制器的实现原理和使用方法。

分别说明了,水平扩展/收缩、滚动更新、回滚的机制实现。

最后:技术交流、博客互助,点击下方或主页推广加入哦!!

【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新_第4张图片

你可能感兴趣的:(#,深入探索,Kubernetes,kubernetes,云原生,容器,云计算,Deployment,RplicaSet,Pod)