一、服务质量等级 QoS
Guaranteed
pod内所有容器的cpu和内存都配置了request和limit的限额,并且都各自相等
Burstable
至少一个容器配置了,且不满足Guaranteed要求
BestEffort
Pod 里的容器必须没有任何内存或者 CPU的限额配置
二、驱逐 与 OOM_Killer(内存相关)
因为 kubelet 默认每 10
秒抓取一次 cAdvisor 的监控数据,所以有可能在 kubelet 驱逐 Pod 回收内存之前发生内存使用量激增的情况,这时就有可能触发内核 OOM killer。这时删除容器的权利就由kubelet 转交到内核 OOM killer 手里,但 kubelet 仍然会起到一定的决定作用,它会根据 Pod 的 QoS 来设置其 oom_score_adj
值:
oom_socre_adj
分数越高被kill的优先级越高
QoS | oom_score_adj |
---|---|
BestEffort | 1000 |
Burstable(2~999) | min(max(2, 1000 - (1000 * 内存使用数) / 总内存数), 999) |
Guaranteed | -998 |
pod-infra-container | -998 |
kubelet, docker daemon, systemd service | -999 |
三、资源不足 vs 处理操作 vs 调度
kubelet
首先根据他们对短缺资源的使用是否超过请求来排除 pod 的驱逐行为,然后通过 优先级,然后通过相对于 pod 的调度请求消耗急需的计算资源。
kubelet
按以下顺序对要驱逐的 pod 排名:
BestEffort
或Burstable
,其对短缺资源的使用超过了其请求,此类 pod 按优先级排序,然后使用高于请求。Guaranteed
pod 和Burstable
pod,其使用率低于请求,最后被驱逐。
1. DiskPressure
kubelet 默认的关于节点存储的驱逐触发条件:
- nodefs.available<10%(容器 volume 使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)
- imagefs.available<15%(容器镜像使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)
当 imagefs
使用量达到阈值时,kubelet 会尝试删除不使用的镜像来清理磁盘空间。
当 nodefs
使用量达到阈值时,kubelet 就会拒绝在该节点上运行新 Pod,并向 API Server 注册一个 DiskPressure condition。然后 kubelet 会尝试删除死亡的 Pod 和容器来回收磁盘空间,如果此时 nodefs
使用量仍然没有低于阈值,kubelet 就会开始驱逐 Pod。从 Kubernetes 1.9 开始,kubelet 驱逐 Pod 的过程中不会参考 Pod 的 QoS,只是根据 Pod 的 nodefs 使用量来进行排名,并选取使用量最多的 Pod 进行驱逐。所以即使 QoS 等级为 Guaranteed
的 Pod 在这个阶段也有可能被驱逐(例如 nodefs 使用量最大)。如果驱逐的是 Daemonset
,kubelet 会阻止该 Pod 重启,直到 nodefs 使用量超过阈值。
2. MemoryPressure
kubelet 默认的关于节点内存资源的驱逐触发条件:
- memory.available<100Mi
当内存使用量超过阈值时,kubelet 就会向 API Server 注册一个 MemoryPressure condition,此时 kubelet 不会接受新的 QoS 为 Best Effort
的 Pod 在该节点上运行,并按照以下顺序来驱逐 Pod:
- Pod 的内存使用量是否超过了
request
指定的值 - 根据 priority 排序,优先级低的 Pod 最先被驱逐
- 比较它们的内存使用量与
request
指定的值之差。
节点状况 | 调度行为 |
---|---|
MemoryPressure | 不再分配新的 BestEffort Pod 到这个节点(因为来新的BestEffort可能马上又被驱逐) |
DiskPressure | 不再向这一节点分配 Pod |
四、驱逐方式与驱逐信号
驱逐方式
硬驱逐
直接触发驱逐
软驱逐
根据配置给到一个容忍时间,时间内恢复则不驱逐pod
驱逐信号
驱逐信号 | 描述 |
---|---|
memory.available | memory.available:= node.status.capacity[memory]- node.stats.memory.workingSet |
nodefs.available | nodefs.available:= node.stats.fs.available |
nodefs.inodesFree | nodefs.inodesFree:= node.stats.fs.inodesFree |
imagefs.available | imagefs.available:= node.stats.runtime.imagefs.available |
imagefs.inodesFree | imagefs.inodesFree:= node.stats.runtime.imagefs.inodesFree |
上述每个值支持字面值或百分比。
举例说明,如果一个节点有 10Gi
内存,希望在可用内存下降到 1Gi
以下时引起驱逐操作,则驱逐阈值可以使用下面任意一种方式指定(但不是两者同时)。
memory.available<10%
memory.available<1Gi
五、分配方案
防止触发OOM-Killer(OOM-Killer是linux内核防护能力,不是最佳实践)
比如
kubelet
启动命令作如下修整:1
2
3
4# 指定内存低于500M时开始驱逐防止触发OOM
--eviction-hard=memory.available<500Mi
# 为系统守护进程(内核、kubelet等)保留一定的内存容量(这里的1.5G包含上面的500M,所以这里预留给系统守护进程的为1G)
--system-reserved=memory=1.5Gi因为
DaemonSet
的Pod不应被驱逐,应确保DaemonSet
的Pod声明为Guaranteed的QoS理论上用户定义的Pod的QoS等级都应该大于BestEffort,同时应估算最大使用内存和磁盘,给出明确的
request
和limit
的定义