Pod
1. 概述⚓
1.1 控制器⚓
用户应该始终使用控制器来创建 Pod,控制器((例如 Deployment、StatefulSet、DaemonSet 等)可以提供如下特性:
- 水平扩展(运行 Pod 的多个副本)
- rollout(版本更新)
- self-healing(故障恢复)
1.2 Pod Template⚓
Pod Template 是关于 Pod 的定义,但是被包含在其他的 Kubernetes 对象中(例如 Deployment、StatefulSet、DaemonSet 等控制器)。
2. 容器的检查⚓
Probe 是指 kubelet 周期性地检查容器的状况。有三种类型的 Probe:
- ExecAction: 在容器内执行一个指定的命令。如果该命令的退出状态码为 0,则成功
- TCPSocketAction: 探测容器的指定 TCP 端口,如果该端口处于 open 状态,则成功
- HTTPGetAction: 探测容器指定端口/路径上的 HTTP Get 请求,如果 HTTP 响应状态码在 200 到 400(不包含400)之间,则成功
Probe 有三种可能的结果:
- Success: 容器通过检测
- Failure: 容器未通过检测
- Unknown: 检测执行失败,此时 kubelet 不做任何处理
Kubelet 可以在两种情况下对运行中的容器执行 Probe:
- 就绪检查 readinessProbe: 确定容器是否已经就绪并接收服务请求。如果就绪检查失败,kubernetes 将该 Pod 的 IP 地址从所有匹配的 Service 的资源池中移除掉。
- 健康检查 livenessProbe: 确定容器是否正在运行。如果健康检查失败,kubelete 将结束该容器,并根据 restart policy(重启策略)确定是否重启该容器。
更详细的说明参考:
- https://kuboard.cn/learning/k8s-intermediate/workload/pod-lifecycle.html#%E5%AE%B9%E5%99%A8%E7%9A%84%E6%A3%80%E6%9F%A5
- https://kuboard.cn/learning/k8s-intermediate/workload/pod-health.html#%E4%B8%80%E3%80%81%E9%9C%80%E6%B1%82%E6%9D%A5%E6%BA%90
3. 重启策略⚓
定义 Pod 或工作负载时,可以指定 restartPolicy,可选的值有:
- Always (默认值)
- OnFailure
- Never
restartPolicy 将作用于 Pod 中的所有容器。
Note
控制器 Deployment/StatefulSet/DaemonSet 中,只支持 Always 这一个选项,不支持 OnFailure 和 Never 选项。
4. 初始化容器⚓
Pod 可以包含多个工作容器和多个初始化容器,初始化容器在工作容器启动之前执行。
工作容器和初始化容器的区别:
- 初始化容器总是运行并自动结束
- kubelet 按顺序执行 Pod 中的初始化容器,前一个初始化容器成功结束后,下一个初始化容器才开始运行。所有的初始化容器成功执行后,才开始启动工作容器
- 如果 Pod 的任意一个初始化容器执行失败,kubernetes 将反复重启该 Pod,直到初始化容器全部成功(除非 Pod 的 restartPolicy 被设定为 Never),因此初始化容器中的代码必须是 幂等 的。
- 初始化容器的 Resource request / limits 处理不同,请参考 Resources
- 初始化容器不支持 就绪检查 readiness probe,因为初始化容器必须在 Pod ready 之前运行并结束
- 初始化容器的端口是不能够通过 kubernetes Service 访问的
- Pod 在初始化过程中处于 Pending 状态
- 改变工作容器的镜像,将只重启该工作容器,而不重启 Pod
4.1 Resources⚓
在确定初始化容器的执行顺序以后,以下 resource 使用规则将适用:
- 所有初始化容器中最高的 resource request/limit 是最终生效的 request/limit
- 对于 Pod 来说,最终生效的 resource request/limit 是如下几个当中较高的一个:
- 所有工作容器某一个 resource request/limit 的和
- 最终生效的初始化容器的 request/limit 的和
- Kubelet 依据最终生效的 request/limit 执行调度,这意味着,在执行初始化容器时,就已经为 Pod 申请了其资源需求
5. 容器的毁坏⚓
5.1 自愿的和非自愿的毁坏⚓
除非有人(人或者控制器)销毁Pod,或者出现不可避免的硬件/软件故障,Pod不会凭空消失。此类不可避免的情况,我们称之为非自愿的毁坏(involuntary disruption)。例如:
- 节点所在物理机的硬件故障
- 集群管理员误删了虚拟机
- 云供应商或管理程序故障导致虚拟机被删
- Linux 内核故障
- 集群所在的网络发生分片,导致节点不可用
- 节点资源耗尽,导致 Pod 被驱逐
还有一类毁坏,我们称之为自愿的毁坏(voluntary disruptions)。主要包括由应用管理员或集群管理员主动执行的操作。应用管理员可能执行的操作有:
- 删除 Deployment 或其他用于管理 Pod 的控制器
- 修改 Deployment 中 Pod 模板的定义,导致 Pod 重启
- 直接删除一个 Pod
集群管理员可能执行的操作有:
-
排空节点 以便维修或升级
-
排空节点,以将集群缩容
-
从节点上删除某个 Pod,以使得其他的 Pod 能够调度到该节点上
5.2 Disruption Budget如何工作⚓
应用程序管理员可以为每一个应用程序创建 PodDisruptionBudget
对象(PDB)。PDB限制了多副本应用程序在自愿的毁坏情况发生时,最多有多少个副本可以同时停止。
集群管理员以及托管供应商在进行系统维护时,应该使用兼容 PodDisruptionBudget 的工具(例如 kubectl drain
,此类工具调用 Eviction API )而不是直接删除 Pod 或者 Deployment。
- PDB 通过 Pod 的
.metadata.ownerReferences
查找到其对应的控制器(Deployment、StatefulSet) - PDB 通过 控制器(Deployment、StatefulSet)的
.spec.replicas
字段来确定期望的副本数 - PDB 通过控制器(Deployment、StatefulSet)的 label selector 来确定哪些 Pod 属于同一个应用程序
- PDB 不能阻止 非自愿的毁坏 发生,但是当这类毁坏发生时,将被计入到当前毁坏数里
- 通过
kubectl drain
驱逐 Pod 时,Pod 将被优雅地终止(gracefully terminated,参考 terminationGracePeriodSeconds) - 在滚动更新过程中被删除的 Pod 也将计入到 PDB 的当前毁坏数,但是控制器(例如 Deployment、StatefulSet)在执行滚动更新时,并不受 PDB 的约束。滚动更新过程中,同时可以删除的 Pod 数量在控制器对象(Deployment、StatefulSet等)的定义中规定。
5.3 配置PodDisruptionBudget⚓
通常如下几种 Kubernetes 控制器创建的应用程序可以使用 PDB:
- Deployment
- ReplicationController
- ReplicaSet
- StatefulSet
值与其他的控制器或直接创建的 Pod 参考下面的章节:《任意控制器和选择器》
5.4 思考应用程序如何应对毁坏⚓
- 无状态的前端:
- 关注点:不能让服务能力(serving capacity)降低超过 10%
- 解决方案:在 PDB 中配置 minAvailable 90%
- 单实例有状态应用:
- 关注点:未经同意不能关闭此应用程序
- 解决方案1: 不使用 PDB,并且容忍偶尔的停机
- 解决方案2: 在 PDB 中设置 maxUnavailable=0。与集群管理员达成一致(不是通过Kubernetes,而是邮件、电话或面对面),请集群管理员在终止应用之前与你沟通。当集群管理员联系你时,准备好停机时间,删除 PDB 以表示已准备好应对毁坏。并做后续处理
- 多实例有状态应用,例如 consul、zookeeper、etcd:
- 关注点:不能将实例数降低到某个数值,否则写入会失败
- 解决方案1: 在 PDB 中设置 maxUnavailable 为 1 (如果副本数会发生变化,可以使用此设置)
- 解决方案2: 在 PDB 中设置 minAvailable 为最低数量(例如,当总副本数为 5 时,设置为3)(可以同时容忍更多的毁坏数)
- 可以重新开始的批处理任务:
- 关注点:当发生自愿毁坏时,Job仍然需要完成其执行任务
- 解决方案: 不创建 PDB。Job 控制器将会创建一个 Pod 用于替换被毁坏的 Pod
5.5 定义PodDisruptionBudget⚓
PodDisruptionBudget
包含三个字段:
- 标签选择器
.spec.selector
用于指定 PDB 适用的 Pod。此字段为必填 .spec.minAvailable
:当完成驱逐时,最少仍然要保留多少个 Pod 可用。该字段可以是一个整数,也可以是一个百分比.spec.maxUnavailable
: 当完成驱逐时,最多可以有多少个 Pod 被终止。该字段可以是一个整数,也可以是一个百分比
minAvailable
或 maxUnavailable
可以指定为整数或者百分比。使用百分比进行计算时 Kubernetes 将向上舍入。
在一个 PodDisruptionBudget
中,只能指定 maxUnavailable
和 minAvailable
中的一个。 maxUnavailable
只能应用到那些有控制器的 Pod 上。
推荐使用 maxUnavailable
这种形式的定义,因为当控制器的 spec.replicas
发生变化时,应用受到的影响更小一些。例如,将其副本数伸缩到 10,如果使用 minAvailable=2
这种形式,则可能会有 8 个 Pod 被毁坏。而如果使用 maxUnavailable=1
这种形式,应用程序将可以保存 9 个可用实例。
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: nginx-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
test: nginx
获取更多关于 pdb 的信息:
kubectl get pdb nginx-pdb -o yaml
5.6 任意控制器和选择器⚓
PDB 可以用于保护其他类型控制器(例如,“operator”)创建的 Pod,或者直接创建的 Pod(bare pod),但是有如下限定:
- 只能使用
.spec.minAvailable
,不能使用.spec.maxUnavailable
.spec.minAvailable
字段中只能使用整型数字,不能使用百分比
Warning
PDB 的标签选择器之间不能重叠。