POD驱逐-配置资源不足时的处理方式 | Kubernetes

标签: | 发表时间:2021-06-14 10:47 | 作者:
出处:https://kubernetes.io

配置资源不足时的处理方式

本页介绍如何使用 kubelet配置资源不足时的处理方式。

当可用计算资源较少时, kubelet需要保证节点稳定性。 这在处理如内存和硬盘之类的不可压缩资源时尤为重要。 如果任意一种资源耗尽,节点将会变得不稳定。

驱逐信号

kubelet支持按照以下表格中描述的信号触发驱逐决定。 每个信号的值在 description 列描述,基于 kubelet摘要 API。

驱逐信号 描述
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
pid.available pid.available:= node.stats.rlimit.maxpid- node.stats.rlimit.curproc

上面的每个信号都支持字面值或百分比的值。基于百分比的值的计算与每个信号对应的总容量相关。

memory.available的值从 cgroupfs 获取,而不是通过类似 free -m的工具。 这很重要,因为 free -m不能在容器中工作,并且如果用户使用了 节点可分配资源特性,资源不足的判定将同时在本地 cgroup 层次结构的终端用户 Pod 部分和根节点做出。 这个 脚本复现了与 kubelet计算 memory.available相同的步骤。 kubeletinactive_file(意即活动 LRU 列表上基于文件后端的内存字节数)从计算中排除, 因为它假设内存在出现压力时将被回收。

kubelet只支持两种文件系统分区。

  1. nodefs文件系统,kubelet 将其用于卷和守护程序日志等。
  2. imagefs文件系统,容器运行时用于保存镜像和容器可写层。

imagefs可选。 kubelet使用 cAdvisor 自动发现这些文件系统。 kubelet不关心其它文件系统。当前不支持配置任何其它类型。 例如,在专用 filesytem中存储卷和日志是 不可以的。

在将来的发布中, kubelet将废除当前存在的 垃圾回收机制,这种机制目前支持将驱逐操作作为对磁盘压力的响应。

驱逐阈值

kubelet支持指定驱逐阈值,用于触发 kubelet回收资源。

每个阈值形式如下:

[eviction-signal][operator][quantity]

  • 合法的 eviction-signal标志如上所示。
  • operator是所需的关系运算符,例如 <
  • quantity是驱逐阈值值标志,例如 1Gi。合法的标志必须匹配 Kubernetes 使用的数量表示。 驱逐阈值也可以使用 %标记表示百分比。

举例说明,如果一个节点有 10Gi内存,希望在可用内存下降到 1Gi以下时引起驱逐操作, 则驱逐阈值可以使用下面任意一种方式指定(但不是两者同时)。

  • memory.available<10%
  • memory.available<1Gi

软驱逐阈值

软驱逐阈值使用一对由驱逐阈值和管理员必须指定的宽限期组成的配置对。在超过宽限期前, kubelet不会采取任何动作回收和驱逐信号关联的资源。如果没有提供宽限期, kubelet启动时将报错。

此外,如果达到了软驱逐阈值,操作员可以指定从节点驱逐 pod 时,在宽限期内允许结束的 pod 的最大数量。 如果指定了 pod.Spec.TerminationGracePeriodSeconds值, kubelet将使用它和宽限期二者中较小的一个。 如果没有指定, kubelet将立即终止 pod,而不会优雅结束它们。

软驱逐阈值的配置支持下列标记:

  • eviction-soft描述了驱逐阈值的集合(例如 memory.available<1.5Gi),如果在宽限期之外满足条件将触发 pod 驱逐。
  • eviction-soft-grace-period描述了驱逐宽限期的集合(例如 memory.available=1m30s),对应于在驱逐 pod 前软驱逐阈值应该被控制的时长。
  • eviction-max-pod-grace-period描述了当满足软驱逐阈值并终止 pod 时允许的最大宽限期值(秒数)。

硬驱逐阈值

硬驱逐阈值没有宽限期,一旦察觉, kubelet将立即采取行动回收关联的短缺资源。 如果满足硬驱逐阈值, kubelet将立即结束 Pod 而不是体面地终止它们。

硬驱逐阈值的配置支持下列标记:

  • eviction-hard描述了驱逐阈值的集合(例如 memory.available<1Gi),如果满足条件将触发 Pod 驱逐。

kubelet有如下所示的默认硬驱逐阈值:

  • memory.available<100Mi
  • nodefs.available<10%
  • imagefs.available<15%

在Linux节点上,默认值还包括 nodefs.inodesFree<5%

驱逐监控时间间隔

kubelet根据其配置的整理时间间隔计算驱逐阈值。

  • housekeeping-interval是容器管理时间间隔。

节点状态

kubelet会将一个或多个驱逐信号映射到对应的节点状态。

如果满足硬驱逐阈值,或者满足独立于其关联宽限期的软驱逐阈值时, kubelet将报告节点处于压力下的状态。

下列节点状态根据相应的驱逐信号定义。

节点状态 驱逐信号 描述
MemoryPressure memory.available 节点上可用内存量达到逐出阈值
DiskPressure nodefs.available, nodefs.inodesFree, imagefs.available, 或 imagefs.inodesFree 节点或者节点的根文件系统或镜像文件系统上可用磁盘空间和 i 节点个数达到逐出阈值
PIDPressure pid.available 在(Linux)节点上的可用进程标识符已降至驱逐阈值以下

kubelet将以 --node-status-update-frequency指定的频率连续报告节点状态更新,其默认值为 10s

节点状态振荡

如果节点在软驱逐阈值的上下振荡,但没有超过关联的宽限期时,将引起对应节点的状态持续在 true 和 false 间跳变,并导致不好的调度结果。

为了防止这种振荡,可以定义下面的标志,用于控制 kubelet从压力状态中退出之前必须等待的时间。

  • eviction-pressure-transition-periodkubelet从压力状态中退出之前必须等待的时长。

kubelet将确保在设定的时间段内没有发现和指定压力条件相对应的驱逐阈值被满足时,才会将状态变回 false

回收节点层级资源

如果满足驱逐阈值并超过了宽限期, kubelet将启动回收压力资源的过程,直到它发现低于设定阈值的信号为止。

kubelet将尝试在驱逐终端用户 pod 前回收节点层级资源。 发现磁盘压力时,如果节点针对容器运行时配置有独占的 imagefskubelet回收节点层级资源的方式将会不同。

使用 imagefs

如果 nodefs文件系统满足驱逐阈值, kubelet通过驱逐 pod 及其容器来释放磁盘空间。

如果 imagefs文件系统满足驱逐阈值, kubelet通过删除所有未使用的镜像来释放磁盘空间。

未使用 imagefs

如果 nodefs满足驱逐阈值, kubelet将以下面的顺序释放磁盘空间:

  1. 删除停止运行的 pod/container
  2. 删除全部没有使用的镜像

驱逐最终用户的 pod

如果 kubelet在节点上无法回收足够的资源, kubelet将开始驱逐 pod。

kubelet首先根据他们对短缺资源的使用是否超过请求来排除 pod 的驱逐行为, 然后通过 优先级, 然后通过相对于 pod 的调度请求消耗急需的计算资源。

kubelet按以下顺序对要驱逐的 pod 排名:

  • BestEffortBurstable,其对短缺资源的使用超过了其请求,此类 pod 按优先级排序,然后使用高于请求。
  • Guaranteedpod 和 Burstablepod,其使用率低于请求,最后被驱逐。 GuaranteedPod 只有为所有的容器指定了要求和限制并且它们相等时才能得到保证。 由于另一个 Pod 的资源消耗,这些 Pod 保证永远不会被驱逐。 如果系统守护进程(例如 kubeletdocker、和 journald)消耗的资源多于通过 system-reservedkube-reserved分配保留的资源,并且该节点只有 GuaranteedBurstablePod 使用少于剩余的请求,然后节点必须选择驱逐这样的 Pod 以保持节点的稳定性并限制意外消耗对其他 pod 的影响。 在这种情况下,它将首先驱逐优先级最低的 pod。

必要时, kubelet会在遇到 DiskPressure时逐个驱逐 Pod 来回收磁盘空间。 如果 kubelet响应 inode短缺,它会首先驱逐服务质量最低的 Pod 来回收 inodes。 如果 kubelet响应缺少可用磁盘,它会将 Pod 排在服务质量范围内,该服务会消耗大量的磁盘并首先结束这些磁盘。

使用 imagefs

如果是 nodefs触发驱逐, kubelet将按 nodefs用量 - 本地卷 + pod 的所有容器日志的总和对其排序。

如果是 imagefs触发驱逐, kubelet将按 pod 所有可写层的用量对其进行排序。

未使用 imagefs

如果是 nodefs触发驱逐, kubelet会根据磁盘的总使用情况对 pod 进行排序 - 本地卷 + 所有容器的日志及其可写层。

最小驱逐回收

在某些场景,驱逐 pod 会导致回收少量资源。这将导致 kubelet反复碰到驱逐阈值。除此之外,对如 disk这类资源的驱逐时比较耗时的。

为了减少这类问题, kubelet可以为每个资源配置一个 minimum-reclaim。 当 kubelet发现资源压力时, kubelet将尝试至少回收驱逐阈值之下 minimum-reclaim数量的资源。

例如使用下面的配置:

      --eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"`

如果 memory.available驱逐阈值被触发, kubelet将保证 memory.available至少为 500Mi。 对于 nodefs.availablekubelet将保证 nodefs.available至少为 1.5Gi。 对于 imagefs.availablekubelet将保证 imagefs.available至少为 102Gi, 直到不再有相关资源报告压力为止。

所有资源的默认 eviction-minimum-reclaim值为 0

调度器

当资源处于压力之下时,节点将报告状态。调度器将那种状态视为一种信号,阻止更多 pod 调度到这个节点上。

节点状态 调度器行为
MemoryPressure 新的 BestEffortPod 不会被调度到该节点
DiskPressure 没有新的 Pod 会被调度到该节点

节点 OOM 行为

如果节点在 kubelet回收内存之前经历了系统 OOM(内存不足)事件,它将基于 oom-killer做出响应。

kubelet基于 pod 的 service 质量为每个容器设置一个 oom_score_adj值。

Service 质量 oom_score_adj
Guaranteed -998
BestEffort 1000
Burstable min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

如果 kubelet在节点经历系统 OOM 之前无法回收内存, oom_killer将基于它在节点上 使用的内存百分比算出一个 oom_score,并加上 oom_score_adj得到容器的有效 oom_score,然后结束得分最高的容器。

预期的行为应该是拥有最低服务质量并消耗和调度请求相关内存量最多的容器第一个被结束,以回收内存。

和 pod 驱逐不同,如果一个 Pod 的容器是被 OOM 结束的,基于其 RestartPolicy, 它可能会被 kubelet重新启动。

最佳实践

以下部分描述了资源外处理的最佳实践。

可调度资源和驱逐策略

考虑以下场景:

  • 节点内存容量: 10Gi
  • 操作员希望为系统守护进程保留 10% 内存容量(内核、 kubelet等)。
  • 操作员希望在内存用量达到 95% 时驱逐 pod,以减少对系统的冲击并防止系统 OOM 的发生。

为了促成这个场景, kubelet将像下面这样启动:

      --eviction-hard=memory.available<500Mi
--system-reserved=memory=1.5Gi

这个配置的暗示是理解系统保留应该包含被驱逐阈值覆盖的内存数量。

要达到这个容量,要么某些 pod 使用了超过它们请求的资源,要么系统使用的内存超过 1.5Gi - 500Mi = 1Gi

这个配置将保证在 pod 使用量都不超过它们配置的请求值时,如果可能立即引起内存压力并触发驱逐时,调度器不会将 pod 放到这个节点上。

DaemonSet

我们永远都不希望 kubelet驱逐一个从 DaemonSet派生的 Pod,因为这个 Pod 将立即被重建并调度回相同的节点。

目前, kubelet没有办法区分一个 Pod 是由 DaemonSet还是其他对象创建。 如果/当这个信息可用时, kubelet可能会预先将这些 pod 从提供给驱逐策略的候选集合中过滤掉。

总之,强烈推荐 DaemonSet不要创建 BestEffort的 Pod,防止其被识别为驱逐的候选 Pod。 相反,理想情况下 DaemonSet应该启动 Guaranteed的 pod。

现有的回收磁盘特性标签已被弃用

kubelet已经按需求清空了磁盘空间以保证节点稳定性。

当磁盘驱逐成熟时,下面的 kubelet标志将被标记为废弃的,以简化支持驱逐的配置。

现有标签 新标签
--image-gc-high-threshold --eviction-hardor eviction-soft
--image-gc-low-threshold --eviction-minimum-reclaim
--maximum-dead-containers deprecated
--maximum-dead-containers-per-container deprecated
--minimum-container-ttl-duration deprecated
--low-diskspace-threshold-mb --eviction-hardor eviction-soft
--outofdisk-transition-frequency --eviction-pressure-transition-period

已知问题

以下部分描述了与资源外处理有关的已知问题。

kubelet 可能无法立即发现内存压力

kubelet当前通过以固定的时间间隔轮询 cAdvisor来收集内存使用数据。如果内存使用在那个时间窗口内迅速增长, kubelet可能不能足够快的发现 MemoryPressureOOMKiller将不会被调用。我们准备在将来的发行版本中通过集成 memcg通知 API 来减小这种延迟。当超过阈值时,内核将立即告诉我们。

如果您想处理可察觉的超量使用而不要求极端精准,可以设置驱逐阈值为大约 75% 容量作为这个问题的变通手段。这将增强这个特性的能力,防止系统 OOM,并提升负载卸载能力,以再次平衡集群状态。

kubelet 可能会驱逐超过需求数量的 pod

由于状态采集的时间差,驱逐操作可能驱逐比所需的更多的 pod。将来可通过添加从根容器获取所需状态的能力 https://github.com/google/cadvisor/issues/1247来减缓这种状况。


相关 [pod 驱逐 资源] 推荐:

POD驱逐-配置资源不足时的处理方式 | Kubernetes

- -
kubelet配置资源不足时的处理方式. kubelet需要保证节点稳定性. 这在处理如内存和硬盘之类的不可压缩资源时尤为重要. 如果任意一种资源耗尽,节点将会变得不稳定. kubelet支持按照以下表格中描述的信号触发驱逐决定. 每个信号的值在 description 列描述,基于. kubelet摘要 API.

k8s资源需求和限制, 以及pod驱逐策略 - ainimore - 博客园

- -
requests:需求,最低保障, 保证被调度的节点上至少有的资源配额 limits:限制,硬限制, 容器可以分配到的最大资源配额. 如果Pod中所有Container的所有Resource的limit和request都相等且不为0,则这个Pod的QoS Class就是Guaranteed. 注意,如果一个容器只指明了limit,而未指明request,则表明request的值等于limit的值.

Kubernetes群集的零停机更新-使用drain驱逐POD去维护NODE

- -
原文标题:Zero Downtime Server Updates For Your Kubernetes Cluster. 发布时间:Jan 26, 2019. 原文链接:https://blog.gruntwork.io/zero-downtime-server-updates-for-your-kubernetes-cluster-902009df5b33.

深入掌握K8S Pod - Yabea - 博客园

- -
K8S configmap介绍. Pod是k8s中最小的调度单元,包含了一个“根容器”和其它用户业务容器. 如果你使用过k8s的话,当然会了解pod的基本使用,但是为了更好的应用,你需要深入了解pod的配置、调度、升级和扩缩容等. pod包含一个或多个相对紧密耦合的容器,处于同一个pod中的容器共享同样的存储空间、IP地址和Port端口.

Kubernetes:玩转 Pod 滚动更新

- - IT瘾-dev
今天推荐一篇关于Kubernetes上服务滚动更新相关的配置选项的文章,文章列出了最常用的几个配置项,解释了他们是怎么影响调度器对服务进行滚动更新的,同时还带出了 Kubernetes项目中 Pod这个逻辑单元的 Ready状态是怎么确定的,并不是容器运行起来后 Pod就进入 Ready状态的.

k8s外网如何访问业务应用之Service 池化pod

- - IT瘾-geek
一、废话:先讲述一个k8s重要概念,我觉得这个概念是整个k8s集群实现微服务的最核心的概念. Service定义了Pod的逻辑集合和访问该集合的策略,是真实服务的抽象. Service提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解后台Pod是如何运行. 只需要将一组跑同一服务的pod池化成一个service,k8s集群会自动给这个service分配整个集群唯一ip和端口号(这个端口号自己在yaml文件中定义),一个service定义了访问pod的方式,就像单个固定的IP地址和与其相对应的DNS名之间的关系.

解决Kubernetes Pod故障的5个简单的技巧

- - DockOne.io
——轻松地解决Kubernetes应用程序的故障并理解其机制. 在很多情况下,你可能会发现Kubernetes中的应用程序没有正确地部署,或者没有正常地工作. 今天这篇文章就提供了如何去快速解决这类故障以及一些技巧. 在阅读了这篇文章之后,你还将深入了解Kubernetes的内部机制,另外,我还将与大家分享一些关于自己操作K8S的一些非常有用的技巧.

监控 Pod 时,我们在监控什么

- - DockOne.io
应用 Kubernetes 化已经开始推进了一段时间,监控系统也提供了 Kubernetes Pod 相关的监控指标和警报规则. 由于 Kubernetes 和传统的物理机/虚拟机是完全不同的运行环境,因此监控系统提供的监控指标也存在一定的区别. 虽然我们已经尽量统一不同平台的差异,但是日常工作中仍会收到用户对 Kubernetes 监控指标的反馈.

在 k8s 中对指定 Pod 进行抓包

- -
Distributed Tracing时,遇到了一些问题,需要深入到底层去进行网络抓包分析报文. 但是应用时运行在 k8s 集群中的,与传统的在一台机器上跑一个进程直接通过 tcpdump 抓包方式略有不同. 最初对容器的理解不深刻认为一定要进入到这个容器抓包,而进入容器内并没有 tcpdump 等基础工具,相当于自己还是把容器当作虚拟机在看待.

k8s 部署 skywalking 并将 pod 应用接入链路追踪

- - SegmentFault 最新的文章
前面写了两篇文章介绍使用 docker 部署 spring boot 和 tomcat 项目,并将其接入skywalking,这篇文章主要介绍使用 k8s 部署 skywalking 并将 pod 应用接入链路追踪. 二、使用 helm 部署 skywalking. 在 k8s 中使用 helm 的前提是需要先安装 helm 客户端,关于 helm 的安装可以查看官方文档.