Kubernetes如何高效管理节点的资源

30次阅读

共计 4501 个字符,预计需要花费 12 分钟才能阅读完成。

kubelet 是 Kubernetes 中的主要节点组件,它执行许多关键任务。Kubelet 主要职责在:

  • 向 kube-apiserver 注册节点
  • watch kube-apiserver 中已经调度完成的 Pod,并在 Pod 被调度完成之后告诉容器运行时(例如 Docker)启动容器
  • 监视运行中的容器并将其状态报告给 kube-apiserver
  • 执行活动性探针并在容器失败后重新启动容器
  • 运行由 kubelet 直接管理的静态 Pod
  • 与 Core Metrics Pipeline 和容器运行时进行交互以收集容器和节点 metrcis

我们在本文中要讨论的另一个重要的 kubelet 任务是,当节点资源耗尽时,“agent”具有将 Pods 逐出的功能。当计算资源(例如磁盘,RAM 或 CPU)不足时,kubelet 在维护节点稳定性方面起着至关重要的作用。对于 Kubernetes 管理员来说,了解配置资源超过配额的最佳做法很有用,以使节点资源更灵活,同时保留系统的整体容错性和关键系统进程的稳定性。

Kubelet 如何确定资源不足?

如前所述,kubelet 可以从节点上驱逐工作负载,以释放资源来处理其他 Pod 和 / 或系统任务,例如容器运行时或 kubelet 本身。但是,kubelet 如何确定资源不足?

Kubelet 根据收回信号和收回阈值确定何时回收资源。驱逐信号是系统资源(如内存或存储器)的当前容量。反过来,驱逐阈值是 kubelet 应该维护的此资源的最小值。

换句话说,每个驱逐信号都与某个驱逐阈值相关联,该阈值告诉 kubelet 何时开始回收资源。目前,支持以下驱逐信号:

  • memory.available — 描述集群内存状态的信号。内存的默认逐出阈值为 100Mi。换句话说,当内存下降到 100 Mi 时,kubelet 开始驱逐 Pod。
  • nodefs.available — nodefs 是 kubelet 用于卷,守护程序日志等的文件系统。默认情况下,如果 nodefs.available <10%,则 kubelet 开始回收节点资源。
  • nodefs.inodesFree — 描述 nodefs 索引节点内存状态的信号。默认情况下,如果 nodefs.inodesFree <5%,则 kubelet 将开始驱逐工作负载。
  • imagefs.available — imagefs 文件系统是容器运行时使用的可选文件系统,用于存储容器镜像和容器可写层。默认情况下,如果 imagefs.available <15%,则 kubelet 开始驱逐工作负载。
  • imagefs.inodesFree — imagefs 索引节点内存的状态。它没有默认驱逐阈值。

上述驱逐阈值是非常合理的默认值。但是,用户可以通过在 kubelet 二进制文件上设置适当的标志来配置其自定义逐出阈值。这些用户定义的阈值可以更改默认的 kubelet 驱逐行为。

目前,Kubernetes 支持硬驱和软驱逐阈值。

如果达到硬驱逐阈值,则 kubelet 将立即开始回收资源,而没有任何宽限期。相反,软驱逐阈值包括用户定义的宽限期,该宽限期应在 kubelet 开始回收任何资源之前到期。

您可以使用 kubelet 二进制文件上的 --eviction-hard 标志定义硬驱逐阈值。例如,kubelet-eviction-hard = memory.available <1Gi将告诉 kubelet 在节点的 memory.available 低于 1Gi 时开始回收资源。

如果要在驱逐之前允许宽限期,则可以将 -eviction-soft标志与 --eviction-soft-grace-period 标志结合使用。例如,kubelet —- eviction-soft=memory.available<2Gikubelet —- eviction-soft-grace-period=1m30s 将使驱逐阈值保持 90 秒,然后触发驱逐阈值。

用户还可以通过以秒为单位设置 --eviction-max-pod-grace-period 来指定允许的最大宽限期。

Kubelet 如何回收资源?

Kubelet 以用户 Pod 的利益为代价来回收资源。它首先尝试回收未使用的容器镜像或 dead 的 Pod。

如果节点具有专用的 imagefs 文件系统以及 nodefs 文件系统,则 kubelet 会以不同的方式回收节点资源。在这种情况下,如果 nodefs 达到驱逐阈值,则 kubelet 会删除所有已失效的 Pod 及其容器。相应地,如果 imagefs 达到驱逐阈值,则 kubelet 会删除所有未使用的容器镜像。

如果没有使用imagefs,则 kubelet 首先删除所有无效的 Pod 及其容器,然后删除所有未使用的镜像。有关此过程的更多信息,请参见 Kubernetes 文档。

如果回收容器镜像,失效的 Pod 和其他资源没有导致资源匮乏,则 kubelet 将删除用户 Pod 作为最后的选择。kubelet 根据 Pod 的 QoS 等级,Pod 优先级和下面讨论的许多其他参数,决定退出哪个用户 Pod。在描述此过程之前,让我们回顾一下 Kubernetes 中的基本 QoS 类。

Pod 的 Qos 共分为 Guaranteed,Burstable 或 Best-Effort。

  • Guaranteed : 在 Pod 的所有容器中都为 CPU 和 RAM 设置资源限制和请求,并且它们的值相等。
  • Burstable Pod 中一个或多个容器的资源(例如,CPU,RAM)设置了请求和限制的容器,它们不相等。
  • Best-Effort Pod 中的容器未设置资源限制。

此 QoS 模型由 kubelet 在其 Pod 排序方案中隐式使用。通常,kubelet 使用以下规则对驱逐候选人进行排名:

  • Pod 是否超出其资源请求。在 Kubernetes 中,Pod 是根据其请求而不是限制进行调度的。因此,保证所有容器和 Pod 都具有它们所请求的 RAM / CPU 数量。但是,如果没有设置限制,并且 Pod 超出了其资源请求,则在保证 Pod 或某些系统任务需要受限资源的情况下,可以终止或限制该 Pod。在某些情况下,甚至那些消耗少于要求量的 Pod 也会被杀死。例如,当系统任务内存严重不足并且没有较低优先级的 Pod 被杀死时。
  • 按 Pod 优先级排列。如果没有 Pod 超出其请求,则 kubelet 会检查 Pod Priority。它将尝试先驱逐优先级较低的 Pod。注意:在 Kubernetes 1.14 中,Pod 的优先级和抢占式迁移到了 GA。从 1.11 开始默认启用它们。您可以在本文中了解有关 Pod Priority 的更多信息。

根据这些规则,kubelet 会按以下顺序驱逐用户 Pod:

  • 驱逐的第一个候选对象是 Best-Effort 和 / 或 Burstable 的 Pod,其受限资源的使用超出了请求。如果有多个此类 Pod,则 kubelet 会按优先级对它们进行排序,然后将资源消耗按指定的请求进行排序。
  • 最后驱逐了资源使用量低于请求的 Guaranteed 和 Burstable Pods 的 Pod。但是,如果某些系统任务(如 kubelet 或 Docker)需要更大的资源,并且节点上没有 Best-EffortPod,则 kubelet 可以驱逐消耗量低于其请求量的 Guaranteed Pod。在这种情况下,它将首先以最低优先级驱逐 Guaranteed 和 Burstable Pods。

最低驱逐收回

如果 kubelet 回收的资源量很小,则系统可以反复达到驱逐阈值。这不是理想的行为,因为它可能导致不良的调度决策和 Pods 频繁驱逐。为了避免这种情况,用户可以使用 kubelet 二进制文件上的 -eviction-minimum-reclaim 标志设置每个资源的最小回收级别。

例如,查看下面的 kubelet 配置:

--eviction-hard=memory.available<1Gi,nodefs.available<2Gi,imagefs.available<200Gi
--eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=1Gi,imagefs.available=2Gi

—- eviction-minimum-reclaim设置可确保回收后可用的 nodefs 最小存储量为 3Gi,可用的 imagefs 最小存储量为 202 Gi。因此,以上配置可确保系统具有足够的可用资源,以避免非常频繁地达到收回阈值。

资源匮乏的处理配置不当可能遇到的另一个潜在问题是节点条件的波动。当 kubelet 收到逐出信号时,后者会映射到相应的节点条件。例如,当达到 memory.available 逐出阈值时,kubelet 将 MemoryPressure 节点条件分配给该节点。此条件与相应的污点关联,该污点可防止在具有 MemoryPressure 节点条件的节点上调度新 Pod。

但是,如果您使用具有较长宽限期的软驱逐阈值,则节点条件可能会在宽限期内在 true 和 false 之间振荡。这可能会导致驱逐不确定性,并因此导致不良的调度决策。为避免这种情况,您可以在 kubelet 上使用 -- eviction-pressure-transition-period 标志,该标志定义 kubelet 在满足驱逐条件之前必须等待多长时间。

一个简单的资源短缺处理方案

现在,我们将说明如何为 K8s 集群配置资源不足的处理。让我们想象一个简单的场景,其中仅考虑节点 RAM。假设我们节点的内存容量为 10 Gi RAM。我们希望为内核,kubelet,Docker 等系统守护进程保留总内存的 10%。我们还希望驱逐 Pods,使其占用 95%的内存。

使用默认逐出阈值启动 kubelet,并且没有系统保留。我们需要在 kubelet 上显式设置几个标志,以启用所需的行为。

为了实现我们的目标,我们需要在 kubelet 上设置以下标志:

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

如您所见,系统保留设置为 1.5Gi,尽管直观上应将其设置为 10%= 1Gi。但是,“系统保留”应包括驱逐阈值(1Gi + .5Gi)覆盖的内存量。

根据配置 K8s 集群的方式,可以不同地设置 kubelet 标志。例如,如果计划使用 Kops 配置 K8s 集群,请运行 kops edit cluster $NAME 以使用集群配置打开编辑器。如果是 VI 编辑器,则按“I”进入插入模式以编辑文件。上述资源不足处理策略的 kubelet 标志应如下所示:

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

结论

在本文中,我们讨论了一些有用的 Kubernetes 管理实践,用于在 Kubernetes 中自定义 kubelet 超出资源的管理。该平台允许管理员设置自定义逐出阈值和逐出宽限期,以决定哪些条件被视为对节点稳定性有害。但是,有了这种自由,就要承担很多责任。Kubernetes 附带了合理的资源短缺管理默认设置。因此,在将驱逐阈值设置得太高或将驱逐宽限期设置得太长时,您应保持谨慎。

PS: 本文属于翻译,原文

正文完
 0