本文由 CNCF + Alibaba 云原生技术公开课 整理而来
Deployment:管理部署发布
Pod
存在的问题:
Kubernetes 集群可以直接管理所有的 Pod
吗?如果这样做,会带来什么样的问题呢?
首先 Kubernetes 集群不可以直接管理所有的 Pod
,也强烈不建议这么做,因为这么做会带来这些问题:
1. 如何保证集群内可用 Pod 的数量? 2. 如何为所有 Pod 更新镜像的版本? 3. 如何在更新过程中保证服务的可用性? 4. 如何在更新过程中发现问题并快速回滚?
正因为存在这些问题,所以 Kubernetes 引入了全新的资源对象——Deployment
,它也是逻辑概念,用来作为 Pod
管理部署发布的控制器。
Deployment
介绍:
Deployment
作为 Pod
管理部署发布的控制器,每个 Deployment
其实是管理的一组相同的应用 Pod
。Deployment
可以具体完成这些事情:
1. Deployment定义了 Pod 期望数量,Controller 始终会持续维持 Pod 数量为期望的数量。当 Pod 出现问题时,Controller也能够恢复 2. 配置 Pod 发布方式,Controller 会按照 Deployment 配置的策略来更新 Pod,而且在更新过程中可以设置不可用的 Pod 数量范围 3. 如果更新过程中发生问题,也可以针对 Deployment “一键回滚”,通过一条命令就可以将 Deployment 对应的所有 Pod 更新为之前的旧版本
Deployment 用法
下面简单介绍 Deployment
的用法。
Deployment
语法:
nginx Deployment
yaml 文件示例:
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
文件解析:
apiVersion: apps/v1 表示 Deployment 当前所属的组是 apps,版本是 v1 kind 表示 Kubernetes 资源类型是 Deployment metadata 表示 Deployment 的元数据,元数据通常包含 name、namespace、labels、annotations 等 spec 表示 Deployment 的期望状态,replicas 表示期望的 Pod 数量;selector 表示 Pod 选择器,选择带相同 label 的 Pod; template 表示 Pod 的模板,模板中也有 Pod 的 metadata 和 spec
- 查看
Deployment
状态:
当创建出一个 Deployment
,可以通过 kubectl get deployment
命令查看 Deployment
的状态。具体可以看到这些字段:
DESIRED 期望的 Pod 数量(replicas) CURRENT 当前实际的 Pod 数量 UP-TO-DATE 到达期望版本的 Pod 数量 AVAILABLE 运行中可用的 Pod 数量 AGE Deployment 创建的时长
- 查看
Pod
状态:
当创建出一个 Deployment
,可以通过 kubectl get pod
命令查看 Pod
的状态。通常可以看出 Pod
的名称分为三部分:
第一部分,是 Pod 所属的 Deployment 的名称,如果是上面示例中创建的 Deployment,则该名称是 nginx-deployment 第二部分,是 template-hash,同一个 Deployment 的 Pod 是一样的,因为 Pod 是同一个 template 中创建出来的 第三部分,是一个随机生成的字符串,每个 Pod 随机生成的字符串都不会相同
Deployment
更新镜像版本:
对一个给定的 Deployment
更新镜像版本,有三种方式。以上面示例为例:
1. kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 2. kubectl edit deployment nginx-deployment #修改镜像版本 3. 直接修改 yaml 文件(image: nginx:1.9.1),kubectl apply -f
Deployment
快速回滚:
如果在发布过程中遇到了问题,也支持快速回滚。以上面示例为例:
#回滚到上一版本 kubectl rollout undo deployment/nginx-deployment #先查看版本列表,然后回滚到指定版本 kubectl rollout history deployment.v1.apps/nginx-deployment kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
Deployment Status
:
Kubernetes 的每一个资源都有它的 spec.Status
,Deployment Status
中描述的三个其实是它的 conversion 状态,也就是 Processing
、Complete
以及 Failed
。
以 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
状态。
架构设计
- 管理模式:
Deployment
只负责管理不同版本的 ReplicaSet
,由 ReplicaSet
来管理具体的 Pod
副本数,每个 ReplicaSet
对应 Deployment template
的一个版本。每一次修改 template
,都会生成一个新的 ReplicaSet
,这个 ReplicaSet
下的 Pod 其实都是相同的版本。
Deployment
创建 ReplicaSet
,而 ReplicaSet
创建 Pod
,它们的 OwnerRef
都对应了其控制器的资源。
Deployment
控制器:
首先,所有的控制器都是通过 Informer 中的事件做一些 Handler
和 Watch
,这里 Deployment
控制器其实关注的是 Deployment
和 ReplicaSet
中的事件,收到事件后会加入到队列中。而 Deployment
控制器从队列中取出来之后,它的逻辑会判断 Check Paused,这个 Paused 其实是 Deployment
是否需要进行新的发布,如果 Paused 设置为 true
,就表示这个 Deployment
只会做一个数量上的维持,不会做新的发布。
如果 Check Paused 为 true
,那么 Deployment
控制器只会做 Sync replicas
,即把 replicas
同步到对应的 ReplicaSet
中,然后再更新 Deployment Status
,这一次的过程就结束了。
如果 Paused 为 false
,它就会做 Rollout
,通过 Create
或 Rolling
的方式来更新,更新的方式也是通过 Create/Update/Delete
ReplicaSet
来做实现的。
ReplicaSet
控制器:
当 Deployment
分配 ReplicaSet
之后,ReplicaSet
控制器本身也是从 Informer 中 Wtach
一些事件,这些事件包含了 ReplicaSet
和 Pod
的事件。从队列中取出之后,ReplicaSet
控制器的逻辑很简单,就只管理 replicas
。如果 replicas
比当前 Pod
数量大,就会扩容;反之则会缩容,删除 Pod
,维持当前 Pod
数量与 replicas
一致。
Deployment
控制器其实做了更复杂的事情,包含了版本管理,只不过是把每一个版本下的 Pod
数量维持工作交给 ReplicaSet
来完成。
Spec
字段解析:
Deployment
中还有这些重要的 Spec
字段:
MinReadySeconds:Deployment 判断 Pod available 的最小时间。如果我们设置 MinReadySeconds 为 30 秒,那 Deployment 就一定会等到 Pod ready 超过 30 秒之后才认为 Pod 是 available 的。 Pod available 的前提条件是 Pod ready,但是 ready 的 Pod 不一定是 available 的,它一定要超过 MinReadySeconds 之后,才会判断为 available; revisionHistoryLimit:保留历史 revision(ReplicaSet)的数量,默认值为 10 个。可以设置为一个或两个,如果回滚可能性比较大的话,可以设置数量超过 10; paused:用来标识 Deployment 只做数量维持、不做新的发布,这个字段在 Debug 场景可能会用到; progressDeadlineSeconds:判断 Deployment Status 为 Failed 的最大时间。当 Deployment 处于扩缩容或者发布状态时,它的 condition 会处于 Processing 的状态。 可以为 Processing 设置一个超时时间。如果超过超时时间还处于 Processing 状态,那么控制器将认为这个 Pod 会进入 Failed 状态。
- 升级策略字段解析:
Deployment
在 RollingUpdate
中主要提供了两个策略,分别是 MaxUnavailable
和 MaxSurge
:
MaxUnavailable:滚动过程中最多有多少个 Pod 不可用 MaxSurge:滚动过程中最多存在多少个 Pod 超过预期 replicas 数量
举个例子,ReplicaSet
为 3 的 Deployment
在发布时可能存在一种情况:新版本的 ReplicaSet
和旧版本的 ReplicaSet
都可能有 2 个 replicas
,加在一起就是 4 个,超过了期望的数量 3 个。这是因为默认的 MaxUnavailable
和 MaxSurge
都是 25%
,默认 Deployment
在发布的过程中,可能有 25% 的 replicas
是不可用的,也可能超过 replicas
数量 25% 是可用的,最高可以达到 125% 的 replicas
数量。
其实用户可以根据实际场景来做设置。当资源足够、且更注重发布过程中的可用性时,可设置 MaxUnavailable
较小、MaxSurge
较大。但如果资源比较紧张,可以设置 MaxSurge
较小,甚至设置为 0,但注意 MaxSurge
和 MaxUnavailable
不能同时为 0。
因为当 MaxSurge
为 0 的时候,必须要删除 Pod
,才能扩容 Pod
;如果不删除 Pod
是不能新扩 Pod
的,因为新扩出来的话,总的 Pod
数量就会超过期望数量。而两者同时为 0 的话,MaxSurge
保证不能新扩 Pod,但 MaxUnavailable
不能保证 ReplicaSet
中有 Pod
是 Available
的,这样就会产生问题。所以说这两个值不能同时为 0。
- 总结:
Deployment
管理多版本的方式,是针对每个版本的 template
创建一个 ReplicaSet
,由 ReplicaSet
维护期望数量的 Pod
副本,而 Deployment
只需要关心不同版本的 ReplicaSet
里要指定多少数量的 Pod。
因此,Deployment
部署发布的根本原理,就是 Deployment
调整不同版本 ReplicaSet
里的期望副本数,以此来达到多版本 Pod
的升级和回滚。