从零开始入门 K8s | 应用编排与管理

1、需求来源

背景问题


首先来看一下背景问题。以下图所示:若是咱们直接管理集群中全部的 Pod,应用 A、B、C 的 Pod,实际上是散乱地分布在集群中。


c1



如今有如下的问题:node

  • 首先,如何保证集群内可用 Pod 的数量?也就是说咱们应用 A 四个 Pod 若是出现了一些宿主机故障,或者一些网络问题,如何能保证它可用的数量?
  • 如何为全部 Pod 更新镜像版本?咱们是否要某一个 Pod 去重建新版本的 Pod?
  • 而后在更新过程当中,如何保证服务的可用性?
  • 以及更新过程当中,若是发现了问题,如何快速回滚到上一个版本?

 

Deployment:管理部署发布的控制器


这里就引入了咱们今天的主题:Deployment 管理部署发布的控制器。nginx

c2

能够看到咱们经过 Deployment 将应用 A、B、C 分别规划到不一样的 Deployment 中,每一个 Deployment 实际上是管理的一组相同的应用 Pod,这组 Pod 咱们认为它是相同的一个副本,那么 Deployment 能帮咱们作什么事情呢?api

  1. 首先,Deployment 定义了一种 Pod 指望数量,好比说应用 A,咱们指望 Pod 数量是四个,那么这样的话,controller 就会持续维持 Pod 数量为指望的数量。当咱们与 Pod 出现了网络问题或者宿主机问题的话,controller 能帮咱们恢复,也就是新扩出来对应的 Pod,来保证可用的 Pod 数量与指望数量一致;
  2. 配置 Pod 发布方式,也就是说 controller 会按照用户给定的策略来更新 Pod,并且更新过程当中,也能够设定不可用 Pod 数量在多少范围内;
  3. 若是更新过程当中发生问题的话,即所谓“一键”回滚,也就是说你经过一条命令或者一行修改可以将 Deployment 下面全部 Pod 更新为某一个旧版本 。

 

2、用例解读

 

Deployment 语法


下面咱们用一个简单的用例来解读一下如何操做 Deployment。网络

c3

上图能够看到一个最简单的 Deployment 的 yaml 文件。

“apiVersion:apps/v1”,也就是说 Deployment 当前所属的组是 apps,版本是 v1。“metadata”是咱们看到的 Deployment 元信息,也就是往期回顾中的 Labels、Selector、Pod.image,这些都是在往期中提到的知识点。

Deployment 做为一个 K8s 资源,它有本身的 metadata 元信息,这里咱们定义的 Deployment.name 是 nginx.Deployment。Deployment.spec 中首先要有一个核心的字段,即 replicas,这里定义指望的 Pod 数量为三个;selector 实际上是 Pod 选择器,那么全部扩容出来的 Pod,它的 Labels 必须匹配 selector 层上的 image.labels,也就是 app.nginx。

就如上面的 Pod 模板 template 中所述,这个 template 它其实包含了两部份内容:架构

  • 一部分是咱们指望 Pod 的 metadata,其中包含了 labels,即跟 selector.matchLabels 相匹配的一个 Labels;
  • 第二部分是 template 包含的一个 Pod.spec。这里 Pod.spec 实际上是 Deployment 最终建立出来 Pod 的时候,它所用的 Pod.spec,这里定义了一个 container.nginx,它的镜像版本是 nginx:1.7.9。

下面是遇到的新知识点:app

  • 第一个是 replicas,就是 Deployment 中指望的或者终态数量;
  • 第二个是 template,也就是 Pod 相关的一个模板。

 

查看 Deployment 状态

当咱们建立出一个 Deployment 的时候,能够经过 kubectl get deployment,看到 Deployment 整体的一个状态。以下图所示:

c4dom

上图中能够看到:阿里云

  • DESIRED:指望的 Pod 数量是 3 个;
  • CURRENT:当前实际 Pod 数量是 3 个;
  • UP-TO-DATE:实际上是到达最新的指望版本的 Pod 数量;
  • AVAILABLE:这个实际上是运行过程当中可用的 Pod 数量。后面会提到,这里 AVAILABLE 并不简单是可用的,也就是 Ready 状态的,它其实包含了一些可用超过必定时间长度的 Pod;
  • AGE:deployment 建立的时长,如上图 Deployment 就是已经建立了 80 分钟。

 

查看 Pod

最后咱们能够查看一下 Pod。以下图所示:spa

c5

上图中有三个 Pod,Pod 名字格式咱们不难看到。

最前面一段:nginx-deployment,实际上是 Pod 所属 Deployment.name;中间一段:template-hash,这里三个 Pod 是同样的,由于这三个 Pod 其实都是同一个 template 中建立出来的。

最后一段,是一个 random 的字符串,咱们经过 get.pod 能够看到,Pod 的 ownerReferences 即 Pod 所属的 controller 资源,并非 Deployment,而是一个 ReplicaSet。这个 ReplicaSet 的 name,实际上是 nginx-deployment 加上 pod.template-hash,后面会提到。全部的 Pod 都是 ReplicaSet 建立出来的,而 ReplicaSet 它对应的某一个具体的 Deployment.template 版本。架构设计

 

更新镜像


接下来咱们能够看一下,如何对一个给定的 Deployment 更新它全部Pod的镜像版本呢?这里咱们能够执行一个 kubectl 命令:

kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1

  • 首先 kubectl 后面有一个 set image 固定写法,这里指的是设定镜像;
  • 其次是一个 deployment.v1.apps,这里也是一个固定写法,写的是咱们要操做的资源类型,deployment 是资源名、v1 是资源版本、apps 是资源组,这里也能够简写为 deployment 或者 deployment.apps,好比说写为 deployment 的时候,默认将使用 apps 组 v1 版本。
  • 第三部分是要更新的 deployment 的 name,也就是咱们的 nginx-deployment;再日后的 nginx 其实指的是 template,也就是 Pod 中的 container.name;这里咱们能够注意到:一个 Pod 中,其实可能存在多个 container,而咱们指定想要更新的镜像的 container.name,就是 nginx。
  • 最后,指定咱们这个容器指望更新的镜像版本,这里指的是 nginx: 1.9.1。以下图所示:当执行完这条命令以后,能够看到 deployment 中的 template.spec 已经更新为 nginx: 1.9.1。


c6

 

快速回滚


若是咱们在发布过程当中遇到了问题,也支持快速回滚。经过 kubectl 执行的话,实际上是“kubectl rollout undo”这个命令,能够回滚到 Deployment 上一版本;经过“rollout undo”加上“to-revision”来指定能够回滚到某一个具体的版本。

c7

 

DeploymeStatus


最后咱们来看一下 DeploymeStatus。每个资源都有它的 spec.Status。这里能够看一下,deploymentStatus 中描述的三个实际上是它的 conversion 状态,也就是 Processing、Complete 以及 Failed。


c8



以 Processing 为例:Processing 指的是 Deployment 正在处于扩容和发布中。好比说 Processing 状态的 deployment,它全部的 replicas 及 Pod 副本所有达到最新版本,并且是 available,这样的话,就能够进入 complete 状态。而 complete 状态若是发生了一些扩缩容的话,也会进入 processing 这个处理工做状态。

若是在处理过程当中遇到一些问题:好比说拉镜像失败了,或者说 readiness probe 检查失败了,就会进入 failed 状态;若是在运行过程当中即 complete 状态,中间运行时发生了一些 pod readiness probe 检查失败,这个时候 deployment 也会进入 failed 状态。进入 failed 状态以后,除非全部点 replicas 均变成 available,并且是 updated 最新版本,deployment 才会从新进入 complete 状态。

 

3、操做演示

 

Deployment 建立及状态

下面咱们来进行操做演示:这里链接一个阿里云服务集群。咱们能够看到当前集群已经有几个可用的 node。


c9

首先建立对应的 deployment。能够看到 deployment 中的 desired、current、up-to-date 以及 available 已经都达到了可用的指望状态。

c10

 

Deployment 的结构

这里看到 spec 中的 replicas 是三个,selector 以及 template labels中定义的标签都是 app:nginx,spec 中的 image 是咱们指望的 nginx: 1.7.9;status 中的 available.replicas,readReplicas 以及 updatedReplicas 都是 3 个。

c11

 

Pod 状态


咱们能够再选择一个 Pod 看一下状态:

能够看到:Pod 中 ownerReferences 的功能是 ReplicaSet;pod.spec.container 里的镜像是 1.7.9。这个 Pod 已是 Running 状态,并且它的 conditions.status 是“true”,表示它的服务已经可用了。

c12

 

更新升级


当前只有最新版本的 replicaset,那么如今尝试对 deployment 作一次升级。


c13


“kubectl set image”这个操做命令,后面接 “deployment”,加 deployment.name,最后指定容器名,以及咱们指望升级的镜像版本。

c14


接下来咱们看下 deployment 中的 template 中的 image 已经更新为 1.9.1。

c15


这个时候咱们再 get pod 看一下状态。

c16


三个 pod 已经升级为新版本,pod 名字中的 pod-template-hash 也已更新。

c17


能够看到:旧版本 replicaset 的 spec 数量以及 pod 数量是都是 0,新版本的 pod 数量是 3 个。

假设又作了一次更新,这个时候 get.pod 其实能够看到:当前的 pod 实际上是有两个旧版本的处于 running,另外一个旧版本是在删除中;而两个新版本的 pod,一个已经进入 running,一个还在 creating 中。

这时咱们可用的 pod 数量即非删除状态的 pod 数量,实际上是 4 个,已经超过了 replica 原先在 deployment 设置的数量 3 个。这个缘由是咱们在 deployment 中有 maxavailable 和 maxsugar 两个操做,这两个配置能够限制咱们在发布过程当中的一些策略。在后面架构设计中会讲到这个问题。

c18

 

历史版本保留 revisionHistoryLimit


上图看到,咱们当前最新版本的 replicaset 是 3 个 pod,另外还有两个历史版本的 replicaset,那么会不会存在一种状况:随着 deployment 持续的更新,这个旧版本的 replicaset 会越积越多。其实 deployment 提供了一个机制来避免这个问题:在 deployment spec 中,有一个 revisionHistoryLimit,它的默认值为 10,它其实保证了保留历史版本的 replicaset 的数量,咱们尝试把它改成 1。

c19


c20


由上面第二张图,能够看到两个 replicaset,也就是说,除了当前版本的 replicaset 以外,旧版本的 replicaset 其实只保留了一个。

 

回滚


最后再尝试作一下回滚。首先再来看一下 replicaset,这时发现旧版本的 replicaset 数量从 0 个增到 2 个,而新版本的 replicaset 数量从 3 个削减为 1 个,表示它已经开始在作回滚的操做。而后再观察一下, 旧版本的数量已是 3 个,即已经回滚成功,而新版本的 pod 数量变为 0 个。

c21


咱们最后再 get pod 看一下:


c22


这时,3 个 pod.template-hash 已经更新为旧版本的 hash,但其实这 3 个 pod 都是从新建立出来的,而并不是咱们在前一版本中建立的 3 个 pod。换句话说,也就是咱们回滚的时候,实际上是建立了 3 个旧版本的 pod,而并不是把先前的 3 个 pod 找回来。

 

4、架构设计

 

管理模式

c23


咱们来看一下架构设计。首先简单看一下管理模式:Deployment 只负责管理不一样版本的 ReplicaSet,由 ReplicaSet 来管理具体的 Pod 副本数,每一个 ReplicaSet 对应 Deployment template 的一个版本。在上文的例子中能够看到,每一次修改 template,都会生成一个新的 ReplicaSet,这个 ReplicaSet 底下的 Pod 其实都是相同的版本。

如上图所示:Deployment 建立 ReplicaSet,而 ReplicaSet 建立 Pod。他们的 OwnerRef 其实都对应了其控制器的资源。

 

Deployment 控制器


咱们先简单看一下控制器实现原理。

首先,咱们全部的控制器都是经过 Informer 中的 Event 作一些 Handler 和 Watch。这个地方 Deployment 控制器,实际上是关注 Deployment 和 ReplicaSet 中的 event,收到事件后会加入到队列中。而 Deployment controller 从队列中取出来以后,它的逻辑会判断 Check Paused,这个 Paused 实际上是 Deployment 是否须要新的发布,若是 Paused 设置为 true 的话,就表示这个 Deployment 只会作一个数量上的维持,不会作新的发布。

c24


如上图,能够看到若是 Check paused 为 Yes 也就是 true 的话,那么只会作 Sync replicas。也就是说把 replicas sync 同步到对应的 ReplicaSet 中,最后再 Update Deployment status,那么 controller 这一次的 ReplicaSet 就结束了。

那么若是 paused 为 false 的话,它就会作 Rollout,也就是经过 Create 或者是 Rolling 的方式来作更新,更新的方式其实也是经过 Create/Update/Delete 这种 ReplicaSet 来作实现的。

 

ReplicaSet 控制器


c25


当 Deployment 分配 ReplicaSet 以后,ReplicaSet 控制器自己也是从 Informer 中 watch 一些事件,这些事件包含了 ReplicaSet 和 Pod 的事件。从队列中取出以后,ReplicaSet controller 的逻辑很简单,就只管理副本数。也就是说若是 controller 发现 replicas 比 Pod 数量大的话,就会扩容,而若是发现实际数量超过时望数量的话,就会删除 Pod。

上面 Deployment 控制器的图中能够看到,Deployment 控制器其实作了更复杂的事情,包含了版本管理,而它把每个版本下的数量维持工做交给 ReplicaSet 来作。

 

扩/缩容模拟


下面来看一些操做模拟,好比说扩容模拟。这里有一个 Deployment,它的副本数是 2,对应的 ReplicaSet 有 Pod1 和 Pod2。这时若是咱们修改 Deployment replicas, controller 就会把 replicas 同步到当前版本的 ReplicaSet 中,这个 ReplicaSet 发现当前有 2 个 Pod,不知足当前指望 3 个,就会建立一个新的 Pod3。


c26

 

发布模拟


咱们再模拟一下发布,发布的状况会稍微复杂一点。这里能够看到 Deployment 当前初始的 template,好比说 template1 这个版本。template1 这个 ReplicaSet 对应的版本下有三个 Pod:Pod1,Pod2,Pod3。

这时修改 template 中一个容器的 image, Deployment controller 就会新建一个对应 template2 的 ReplicaSet。建立出来以后 ReplicaSet 会逐渐修改两个 ReplicaSet 的数量,好比它会逐渐增长 ReplicaSet2 中 replicas 的指望数量,而逐渐减小 ReplicaSet1 中的 Pod 数量。

那么最终达到的效果是:新版本的 Pod 为 Pod四、Pod5 和 Pod6,旧版本的 Pod 已经被删除了,这里就完成了一次发布。

c27

 

回滚模拟


来看一下回滚模拟,根据上面的发布模拟能够知道 Pod四、Pod五、Pod6 已经发布完成。这时发现当前的业务版本是有问题的,若是作回滚的话,不论是经过 rollout 命令仍是经过回滚修改 template,它其实都是把 template 回滚为旧版本的 template1。

这个时候 Deployment 会从新修改 ReplicaSet1 中 Pod 的指望数量,把指望数量修改成 3 个,且会逐渐减小新版本也就是 ReplicaSet2 中的 replica 数量,最终的效果就是把 Pod 从旧版本从新建立出来。

c28


发布模拟的图中能够看到,其实初始版本中 Pod一、Pod二、Pod3 是旧版本,而回滚以后实际上是 Pod七、Pod八、Pod9。就是说它的回滚并非把以前的 Pod 从新找出来,而是说从新建立出符合旧版本 template 的 Pod。

 

spec 字段解析


最后再来简单看一些 Deployment 中的字段解析。首先看一下 Deployment 中其余的 spec 字段:

  • MinReadySeconds:Deployment 会根据 Pod ready 来看 Pod 是否可用,可是若是咱们设置了 MinReadySeconds 以后,好比设置为 30 秒,那 Deployment 就必定会等到 Pod ready 超过 30 秒以后才认为 Pod 是 available 的。Pod available 的前提条件是 Pod ready,可是 ready 的 Pod 不必定是 available 的,它必定要超过 MinReadySeconds 以后,才会判断为 available;
  • revisionHistoryLimit:保留历史 revision,即保留历史 ReplicaSet 的数量,默认值为 10 个。这里能够设置为一个或两个,若是回滚可能性比较大的话,能够设置数量超过 10;
  • paused:paused 是标识,Deployment 只作数量维持,不作新的发布,这里在 Debug 场景可能会用到;
  • progressDeadlineSeconds:前面提到当 Deployment 处于扩容或者发布状态时,它的 condition 会处于一个 processing 的状态,processing 能够设置一个超时时间。若是超过超时时间还处于 processing,那么 controller 将认为这个 Pod 会进入 failed 的状态。


c29

 

升级策略字段解析


最后来看一下升级策略字段解析。

Deployment 在 RollingUpdate 中主要提供了两个策略,一个是 MaxUnavailable,另外一个是 MaxSurge。这两个字段解析的意思,能够看下图中详细的 comment,或者简单解释一下:

  • MaxUnavailable:滚动过程当中最多有多少个 Pod 不可用;
  • MaxSurge:滚动过程当中最多存在多少个 Pod 超过预期 replicas 数量。


上文提到,ReplicaSet 为 3 的 Deployment 在发布的时候可能存在一种状况:新版本的 ReplicaSet 和旧版本的 ReplicaSet 均可能有两个 replicas,加在一块儿就是 4 个,超过了咱们指望的数量三个。这是由于咱们默认的 MaxUnavailable 和 MaxSurge 都是 25%,默认 Deployment 在发布的过程当中,可能有 25% 的 replica 是不可用的,也可能超过 replica 数量 25% 是可用的,最高能够达到 125% 的 replica 数量。

这里其实能够根据用户实际场景来作设置。好比当用户的资源足够,且更注重发布过程当中的可用性,可设置 MaxUnavailable 较小、MaxSurge 较大。但若是用户的资源比较紧张,能够设置 MaxSurge 较小,甚至设置为 0,这里要注意的是 MaxSurge 和 MaxUnavailable 不能同时为 0。

理由不难理解,当 MaxSurge 为 0 的时候,必需要删除 Pod,才能扩容 Pod;若是不删除 Pod 是不能新扩 Pod 的,由于新扩出来的话,总共的 Pod 数量就会超过时望数量。而二者同时为 0 的话,MaxSurge 保证不能新扩 Pod,而 MaxUnavailable 不能保证 ReplicaSet 中有 Pod 是 available 的,这样就会产生问题。因此说这两个值不能同时为 0。用户能够根据本身的实际场景来设置对应的、合适的值。


c30

 

本文总结


这里为你们简单总结一下本文的主要内容:

  • Deployment 是 Kubernetes 中常见的一种 Workload,支持部署管理多版本的 Pod;
  • Deployment 管理多版本的方式,是针对每一个版本的 template 建立一个 ReplicaSet,由 ReplicaSet 维护必定数量的 Pod 副本,而 Deployment 只须要关心不一样版本的 ReplicaSet 里要指定多少数量的 Pod;
  • 所以,Deployment 发布部署的根本原理,就是 Deployment 调整不一样版本 ReplicaSet 里的终态副本数,以此来达到多版本 Pod 的升级和回滚。

 

阅读原文

本文为云栖社区原创内容,未经容许不得转载。 

相关文章
相关标签/搜索