K8S 的节点上的资源会被 pod 和系统进程所使用,若是默认什么都不配置,那么节点上的所有资源都是能够分配给pod使用的,系统进程自己没有保障,这样作很危险:node
节点资源主要分为两类:git
oom 分数:github
因此,OOM 的优先级以下:docker
BestEffort Pod > Burstable Pod > 其它进程 > Guaranteed Pod > kubelet/docker 等 > sshd 等进程
所以须要对节点的内存等资源进行配置,以保证节点核心进程运行正常。bash
节点资源的配置通常分为 2 种:服务器
allocatable的值即对应 describe node 时看到的allocatable容量,pod 调度的上限ssh
计算公式:节点上可配置值 = 总量 - 预留值 - 驱逐阈值 Allocatable = Capacity - Reserved(kube+system) - Eviction Threshold
以上配置均在kubelet 中添加,涉及的参数有:google
--enforce-node-allocatable=pods,kube-reserved,system-reserved --kube-reserved-cgroup=/system.slice/kubelet.service --system-reserved-cgroup=/system.slice --kube-reserved=cpu=200m,memory=250Mi --system-reserved=cpu=200m,memory=250Mi --eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10% --eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15% --eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m --eviction-max-pod-grace-period=30 --eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
配置的含义以下:spa
(1)--enforce-node-allocatable3d
含义:指定kubelet为哪些进程作硬限制,可选的值有: * pods * kube-reserved * system-reserve 这个参数开启并指定pods后kubelet会为全部pod的总cgroup作资源限制(经过cgroup中的kubepods.limit_in_bytes),限制为公式计算出的allocatable的大小。 假如想为系统进程和k8s进程也作cgroup级别的硬限制,还能够在限制列表中再加system-reserved和kube-reserved,同时还要分别加上--kube-reserved-cgroup和--system-reserved-cgroup以指定分别限制在哪一个cgroup里。
配置:--enforce-node-allocatable=pods,kube-reserved,system-reserved
(2)设置k8s组件的cgroup
含义:这个参数用来指定k8s系统组件所使用的cgroup。 注意,这里指定的cgroup及其子系统须要预先建立好,kubelet并不会为你自动建立好。
配置:--kube-reserved-cgroup=/system.slice/kubelet.service
(3)设置系统守护进程的cgroup
含义:这个参数用来指定系统守护进程所使用的cgroup。 注意,这里指定的cgroup及其子系统须要预先建立好,kubelet并不会为你自动建立好。
配置:--system-reserved-cgroup=/system.slice
(4)配置 k8s组件预留资源的大小,CPU、Mem
指定为k8s系统组件(kubelet、kube-proxy、dockerd等)预留的资源量, 如:--kube-reserved=cpu=1,memory=2Gi,ephemeral-storage=1Gi。 这里的kube-reserved只为非pod形式启动的kube组件预留资源,假如组件要是以static pod(kubeadm)形式启动的,那并不在这个kube-reserved管理并限制的cgroup中,而是在kubepod这个cgroup中。 (ephemeral storage须要kubelet开启feature-gates,预留的是临时存储空间(log,EmptyDir),生产环境建议先不使用) ephemeral-storage是kubernetes1.8开始引入的一个资源限制的对象,kubernetes 1.10版本中kubelet默认已经打开的了,到目前1.11仍是beta阶段,主要是用于对本地临时存储使用空间大小的限制,如对pod的empty dir、/var/lib/kubelet、日志、容器可读写层的使用大小的限制。
(5)配置 系统守护进程预留资源的大小(预留的值须要根据机器上容器的密度作一个合理的值)
含义:为系统守护进程(sshd, udev等)预留的资源量, 如:--system-reserved=cpu=500m,memory=1Gi,ephemeral-storage=1Gi。 注意,除了考虑为系统进程预留的量以外,还应该为kernel和用户登陆会话预留一些内存。
配置:--system-reserved=cpu=200m,memory=250Mi
(6)配置 驱逐pod的硬阈值
含义:设置进行pod驱逐的阈值,这个参数只支持内存和磁盘。 经过--eviction-hard标志预留一些内存后,当节点上的可用内存降至保留值如下时, kubelet 将会对pod进行驱逐。
配置:--eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10%
(7)配置 驱逐pod的软阈值
--eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15%
(8)定义达到软阈值以后,持续时间超过多久才进行驱逐
--eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m
(9)驱逐pod前最大等待时间=min(pod.Spec.TerminationGracePeriodSeconds, eviction-max-pod-grace-period),单位为秒
--eviction-max-pod-grace-period=30
(10)至少回收的资源量
--eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
以上配置均为百分比,举例:
以2核4GB内存40GB磁盘空间的配置为例,Allocatable是1.6 CPU,3.3Gi 内存,25Gi磁盘。当pod的总内存消耗大于3.3Gi或者磁盘消耗大于25Gi时,会根据相应策略驱逐pod。
kubelet 利用metric的值做为决策依据来触发驱逐行为,下面内容来自于 Kubelet summary API。
一旦超出阈值,就会触发 kubelet 进行资源回收的动做(区别于软驱逐,有宽限期),指标以下:
例如若是一个 Node 有 10Gi 内存,咱们但愿在可用内存不足 1Gi 时进行驱逐,就能够选取下面的一种方式来定义驱逐阈值:
能够配置百分比或者实际值,可是操做符只能使用小于号,即<
软阈值须要和一个宽限期参数协同工做。当系统资源消耗达到软阈值时,这一情况的持续时间超过了宽限期以前,Kubelet 不会触发任何动做。若是没有定义宽限期,Kubelet 会拒绝启动。
另外还能够定义一个 Pod 结束的宽限期。若是定义了这一宽限期,那么 Kubelet 会使用 pod.Spec.TerminationGracePeriodSeconds 和最大宽限期这两个值之间较小的那个(进行宽限),若是没有指定的话,kubelet 会不留宽限当即杀死 Pod。
软阈值的定义包括如下几个参数:
Housekeeping interval 参数定义一个时间间隔,Kubelet 每隔这一段就会对驱逐阈值进行评估。
若是触发了硬阈值,或者符合软阈值的时间持续了与其对应的宽限期,Kubelet 就会认为当前节点压力太大,下面的节点状态定义描述了这种对应关系。
Kubelet 会持续报告节点状态的更新过程,这一频率由参数 —node-status-update-frequency 指定,缺省状况下取值为 10s。
若是一个节点的情况在软阈值的上下波动,可是又不会超过他的宽限期,将会致使该节点的状态持续的在是否之间徘徊,最终会影响下降调度的决策过程。
要防止这种情况,下面的标志能够用来通知 Kubelet,在脱离pressure以前,必须等待。
eviction-pressure-transition-period
定义了在脱离pressure状态以前要等待的时间
Kubelet 在把pressure状态设置为 False 以前,会确认在周期以内,该节点没有达到阈值
若是达到了驱逐阈值,而且超出了宽限期,那么 Kubelet 会开始回收超出限量的资源,直到回到阈值之内。
Kubelet 在驱逐用户 Pod 以前,会尝试回收节点级别的资源。若是服务器为容器定义了独立的 imagefs,他的回收过程会有所不一样。
有 Imagefs
若是 nodefs 文件系统到达了驱逐阈值,kubelet 会按照下面的顺序来清理空间:
若是 imagefs 文件系统到达了驱逐阈值,kubelet 会按照下面的顺序来清理空间:
没有 Imagefs
若是 nodefs 文件系统到达了驱逐阈值,kubelet 会按照下面的顺序来清理空间。
Kubelet 会按照下面的标准对 Pod 的驱逐行为进行评判:
接下来,Pod 按照下面的顺序进行驱逐(QOS):
参考 POD的QOS:服务质量等级
Guaranteed Pod 不会由于其余 Pod 的资源被驱逐。若是系统进程(例如 kubelet、docker、journald 等)消耗了超出 system-reserved 或者 kube-reserved 的资源,并且这一节点上只运行了 Guaranteed Pod,那么为了保证节点的稳定性并下降异常请求对其余 Guaranteed Pod 的影响,必须选择一个 Guaranteed Pod 进行驱逐。
本地磁盘是一个 BestEffort 资源。若有必要,kubelet 会在 DiskPressure 的状况下,kubelet 会按照 QoS 进行评估。若是 Kubelet 断定缺少 inode 资源,就会经过驱逐最低 QoS 的 Pod 的方式来回收 inodes。若是 kubelet 断定缺少磁盘空间,就会经过在相同 QoS 的 Pods 中,选择消耗最多磁盘空间的 Pod 进行驱逐。
有 Imagefs
没有 Imagefs
例以下面的配置:
--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi --eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"
缺省状况下,全部资源的 eviction-minimum-reclaim 为 0。
在节点资源紧缺的状况下,调度器将再也不继续向此节点部署新的 Pod
若是节点在 Kubelet 可以回收内存以前,遭遇到了系统的 OOM (内存不足),节点就依赖 oom_killer 进行响应了。
kubelet 根据 Pod 的 QoS 为每一个容器设置了一个 oom_score_adj 值。
若是 kubelet 没法在系统 OOM 以前回收足够的内存,oom_killer 就会根据根据内存使用比率来计算 oom_score,得出结果和 oom_score_adj 相加,最后得分最高的 Pod 会被首先驱逐。
跟 Pod 驱逐不一样,若是一个 Pod 的容器被 OOM 杀掉,他是可能被 kubelet 根据 RestartPolicy 重启的。
由于 DaemonSet 中的 Pod 会当即重建到同一个节点,因此 Kubelet 不该驱逐 DaemonSet 中的 Pod。
可是目前 Kubelet 没法分辨一个 Pod 是否由 DaemonSet 建立。若是Kubelet 可以识别这一点,那么就能够先从驱逐候选列表中过滤掉 DaemonSet 的 Pod。
通常来讲,强烈建议 DaemonSet 不要建立 BestEffort Pod,而是使用 Guaranteed Pod,来避免进入驱逐候选列表。
Kubelet 目前从 cAdvisor 定时获取内存使用情况统计。若是内存使用在这个时间段内发生了快速增加,Kubelet 就没法观察到 MemoryPressure,可能会触发 OOMKiller。咱们正在尝试将这一过程集成到 memcg 通知 API 中,来下降这一延迟,而不是让内核首先发现这一状况。
若是用户不是但愿得到终极使用率,而是做为一个过量使用的衡量方式,对付这一个问题的较为可靠的方式就是设置驱逐阈值为 75% 容量。这样就提升了避开 OOM 的能力,提升了驱逐的标准,有助于集群状态的平衡。
这也是由于状态搜集的时间差致使的。将来会加入功能,让根容器的统计频率和其余容器分别开来(https://github.com/google/cad...)。
目前不可能知道一个容器消耗了多少 inode。若是 Kubelet 觉察到了 inode 耗尽,他会利用 QoS 对 Pod 进行驱逐评估。在 cadvisor 中有一个 issue,来跟踪容器的 inode 消耗,这样咱们就能利用 inode 进行评估了。例如若是咱们知道一个容器建立了大量的 0 字节文件,就会优先驱逐这一 Pod
一、资源预留须要设置,pod 的 limit 也要设置。
二、cpu是可压缩资源,内存、磁盘资源是不可压缩资源。内存必定要预留,CPU能够根据实际状况来调整
三、预留多少合适:根据集群规模设置阶梯,以下(GKE建议):
Allocatable = Capacity - Reserved - Eviction Threshold
对于内存资源:
对于 CPU 资源:
对于磁盘资源(不是正式特性,仅供参考):
效果:查看节点的可分配资源:
kubectl describe node [NODE_NAME] | grep Allocatable -B 4 -A 3
--eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10% --eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15% --eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m --eviction-max-pod-grace-period=30 --eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
原文连接:http://www.xuyasong.com/?p=1725