介绍
概念功能说明
- kubelet主动监测和防止Kubernetes集群的资源使用情况,在资源短缺时,如何判断资源短缺根据系统设置的eviction保留策略,当节点资源使用触发到该阈值,开始执行驱逐(主动的结束一个或者多个Pod以回收资源,Pod的状态变为Failed),如果被驱逐的Pod被deployment控制器接管,那么将会被调度到其它的节点
"evictionHard": { "imagefs.available": "15%", "memory.available": "100Mi", "nodefs.available": "10%", "nodefs.inodesFree": "5%" },
驱逐处理
驱逐信号
具体信号,参考下表
驱逐信号 | 解释 | |
memory.available | memory.available := node.status.capacity[memory] - node.stats.memory.workingSet | 代表节点可用的内存 |
nodefs.available | nodefs.available := node.stats.fs.available | 可用的文件系统,一般指/,官方说明是指kubelet所使用的卷及日志所在文件系统 |
nodefs.inodesFree | nodefs.inodesFree := node.stats.fs.inodesFree | 同上,inode的使用 |
imagefs.available | imagefs.available := node.stats.runtime.imagefs.available | Container runtimes所在的逻辑卷,用于存储镜像及可写入的镜像层 |
imagefs.inodesFree | imagefs.inodesFree := node.stats.runtime.imagefs.inodesFree | 同上,inode的使用 |
pid.available | pid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc |
驱逐信号的值,可以用具体数字及百分比代表
memory.available 的值从 cgroupfs 获取,而不是通过类似 free -m 的工具。因为 free -m 不能在容器中工作,并且如果用户使用了 节点可分配资源 特性,资源不足的判定将同时在本地 cgroup 层次结构的终端用户 Pod 部分和根节点做出。 这个脚本 复现了与 kubelet 计算 memory.available 相同的步骤。 kubelet 将 inactive_file(意即活动 LRU 列表上基于文件后端的内存字节数)从计算中排除, 因为它假设内存在出现压力时将被回收
官方文档总是那么的认真,一句话,就是节点的available内存,还给出一个具体计算方式
-
- 计算方式
#!/bin/bash #!/usr/bin/env bash # This script reproduces what the kubelet does # to calculate memory.available relative to root cgroup. # current memory usage memory_capacity_in_kb=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}') memory_capacity_in_bytes=$((memory_capacity_in_kb * 1024)) memory_usage_in_bytes=$(cat /sys/fs/cgroup/memory/memory.usage_in_bytes) memory_total_inactive_file=$(cat /sys/fs/cgroup/memory/memory.stat | grep total_inactive_file | awk '{print $2}') memory_working_set=${memory_usage_in_bytes} if [ "$memory_working_set" -lt "$memory_total_inactive_file" ]; then memory_working_set=0 else memory_working_set=$((memory_usage_in_bytes - memory_total_inactive_file)) fi memory_available_in_bytes=$((memory_capacity_in_bytes - memory_working_set)) memory_available_in_kb=$((memory_available_in_bytes / 1024)) memory_available_in_mb=$((memory_available_in_kb / 1024)) echo "memory.capacity_in_bytes $memory_capacity_in_bytes" echo "memory.usage_in_bytes $memory_usage_in_bytes" echo "memory.total_inactive_file $memory_total_inactive_file" echo "memory.working_set $memory_working_set" echo "memory.available_in_bytes $memory_available_in_bytes" echo "memory.available_in_kb $memory_available_in_kb" echo "memory.available_in_mb $memory_available_in_mb"
- 计算方式
文件系统驱逐信号
目前kubelet只支持二种文件系统,如下
- nodefs (节点kubelet所在文件系统使用率)
- imagefs(docker的Root Dir,docker info查看)
驱逐阈值
表示语法
[eviction-signal][operator][quantity]
- 合法的 eviction-signal 标志如上所示。
- operator 是所需的关系运算符,例如 <
- quantity 是驱逐阈值值标志,例如 1Gi。合法的标志必须匹配 Kubernetes 使用的数量表示。 驱逐阈值也可以使用 % 标记表示百分比
驱逐方式
- 硬驱逐:硬驱逐阈值没有宽限期,触发阈值,kubelet将立即采取行动回收关联的资源(被触发的资源)。 如果满足硬驱逐阈值,kubelet将立即结束 (kill的方式)Pod 而不是优雅的(stop的方式)它们
- 软驱逐:当触发阈值时需要等待指定的宽限期组合使用(阈值&宽限期),在超出宽限期前,kubelet不会采取任何动作回收和驱逐信号关联的资源。如果没有提供宽限期,kubelet启动时将报错;此外,如果达到了软驱逐阈值,可以指定从节点驱逐 pod 时,在宽限期内允许结束的 pod 的最大数量。 如果指定了 pod.Spec.TerminationGracePeriodSeconds值, kubelet取二者(TerminationGracePeriodSeconds & eviction-soft-grace-period)的最小值执行。 如果没有指定,kubelet将立即终止 pod,而不会优雅结束它们
-
- eviction-soft 描述了驱逐阈值的集合(例如 memory.available<1.5Gi),如果在宽限期之外满足条件将触发 pod 驱逐。
- eviction-soft-grace-period 描述了驱逐宽限期的集合(例如 memory.available=1m30s),对应于在驱逐 pod 前软驱逐阈值应该被控制的时长。
- eviction-max-pod-grace-period 描述了当满足软驱逐阈值并终止 pod 时允许的最大宽限期值(秒数)
驱逐时间检查间隔
驱逐节点状态
MemoryPressure | memory.available | 节点上可用内存量达到逐出阈值 |
DiskPressure |
nodefs.available, nodefs.inodesFree, imagefs.available, 或 imagefs.inodesFree
|
节点或者节点的根文件系统或镜像文件系统上可用磁盘空间和 inode个数达到逐出阈值 |
PIDPressure | pid.available | 在(Linux)节点上的可用进程标识符已降至驱逐阈值以下 |
驱逐时节点资源波动
kubelet在配置了软驱逐时,如果触发了阈值并在上下波动,时true时flase,针对此种情况会使用以下参数规避
eviction-pressure-transition-period (默认时间5m0s)是 kubelet从压力状态中退出之前必须等待的时长
回收节点资源
当时达到eviction阈值时,kubelet在驱逐Pod释放系统资源,比如硬盘资源缺乏时,如下规则
imagefs
- 如果 nodefs文件系统满足驱逐阈值,kubelet通过删除dead pod & Contaienr以释放磁盘空间
- 如果 imagefs文件系统满足驱逐阈值,kubelet通过删除所有未使用的镜像来释放磁盘空间
no imagefs
- 删除所有Dead Pod & Container
- 删除所有未使用镜像
驱逐Pod
如果kubele在节点上无法回收足够的资源,则需要驱逐Pod,具体顺序如下
- 首先对BestEffort或者Burstable此类Qos级别Pod的紧缺资源进行判断,判断的条件是实际使用大于请求分配,然后进行排序,高则驱逐
-
Guaranteed pod 和 Burstable pod实际使用低于请求分配,最后被驱逐,高则先被驱逐
- 如果在节点遇到系统守护进程如(kubelet docker journald)实际使用的资源消耗大于systemReserved & kubeReserved预留的资源,则按优先级驱逐此类Pod以保持节点的稳定性
- 具体个人总结为(BestEffort > Burstable > Guaranteed )同级情况比较资源的消耗量,高则先被驱逐
- imagesfs
- 如果是 nodefs触发驱逐,kubelet是按基于nodefs用量进行排序,判断条件(本地卷 + Pod所有容器日志的总和)
- 如果 imagefs 触发了驱逐,Kubelet 按Pod中所有容器的写入层进行排序,从高至低,高则驱逐
- no imagefs
- 如果是nodefs触发了驱逐阈值,kubelet基于Pod的所有容器的(Local volumes + 日志用量 + 可写入层)的和进行排序
最小回收值
有时会遇到在触发驱逐阈值后,驱逐Pod会回收少量的资源会反反复复进行驱逐这样会引起平台的稳定性,对此可以设置最小回收值解决此类现象,如下
--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"
节点OOM
如果kubelet在回收内存前先执行了节点OOM,那么下表是依据Pod的Qos而定义的oom_score_adj的值
sshd/dmevented / systemd-udevd
|
-1000 |
kubelet/docker/journalctl
|
-999 |
Guaranteed
|
-998 |
BestEffort
|
1000 |
Burstable
|
min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
|
如果节点OS在内存紧缺时,并且在节点OOM之前无法进行内存回收,那么oom_killer会计算所有container基于内存使用的百分比得出oom_score,再与oom_score_adj,最终算出容器真正的oom_score,然后kill得分最高的容器,具体公式如下
init oom_score(基于容器对内存使用的百分比计算) + oom_score_adj = oom_score_adj,计算的结果等于Pod的Qos等级最低及请求内存最高的容器首先被第一个结束
与Pod驱逐不同的是,如果一个Pod被OOM,会被所属的资源管理器所接管,如deployment接管,kubelet执行对应Deployment中指定的restartPolicy策略
驱逐建议
参考场景:
节点内存容量:10Gi
系统守护进程保留 5% 内存量(kernel sshd udevf)系统守护进程而预留
kubeRserved预留 5% 内存量(kubelet docekr proxy)Kubernetes组件而预留
在内存用量达到 90% 时驱逐 pod,以减少对系统的冲击并防止系统 OOM 的发生
- 具体配置,如下
"evictionHard": { "imagefs.available": "15%", "memory.available": "10%", "nodefs.available": "10%", "nodefs.inodesFree": "5%" }, "evictionPressureTransitionPeriod": "4m0s", "evictionMinimumReclaim": { "imagefs.available": "2Gi", "memory.available": "300Mi", "nodefs.available": "500Mi" }, ... "systemReserved": { "cpu": "500m", "memory": "500Mi" }, "kubeReserved": { "cpu": "500m", "memory": "500Mi" }
以上配置总结如下
systemReserved+kubeReserved ≥ eviction > node OOM(/proc/sys/vm/min_free_kbytes)
如果systemReserved + kubeReserved < eviction 的值代表OOM的概率增加,因为Pod的Allocatable的值接近Capacity的值
如果systemReserved + kubeReserved > eviction 的值代表OOM的概率减少,因为Pod的Allocatable的值小于Capacity的值
最终目的是优先执行eviction,防止应用丢失数据
DaemonSet
在配置DaemonSet时资源副本控制器,Qos的等级务必为Guaranteed(requests & limits的值相同),因为如果Qos设置过低的话,会被优先驱逐,由于DaemonSet的特性是每个节点的守护Pod,如果kill或者驱逐则调度器会在相同的节点重新调度
https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/#active-file-memory-is-not-considered-as-available-memory