原文:https://sysdig.com/blog/kubernetes-pod-evicted/
作者:JAVIER MARTÍNEZ
Kubernetes Pods 被驱逐是什么意思?它们被终止了,通常是由于没有足够的资源,但是为什么会发生这种情况呢?
驱逐是一个过程,分配给一个节点的 Pod 被要求终止。Kubernetes 中最常见的情况之一是抢占,为了在资源有限的节点上安排一个新的 Pod,通常需要终止另外一个 Pod。
另外,Kubernetes 会不断检查资源使用情况,当节点压力过大的时候,会触发节点压力驱逐。
每天,数以千计的 Pod 被驱逐出他们的家园。搁浅和迷茫,他们不得不放弃以前的生活方式。他们中的一些人甚至会无家可归。当前的社会,对 CPU 和内存的要求会越来越高。
本篇文章将从以下几个方面来展开介绍:
- Pod 被驱逐的原因:抢占和节点压力
- 抢占式驱逐
- Pod 优先级类
- 节点压力驱逐
- 服务质量类
- 其他类型的驱逐
- Prometheus 中的 Kubernetes Pod 驱逐监控
Pods 被驱逐的原因:抢占和节点压力
Kubernetes 中发生 Pod 驱逐的原因有几个,最重要的原因是:
- 抢占
- 节点压力驱逐
抢占驱逐
抢占的过程如下:如果一个新的 Pod 需要被调度,但没有任何合适的节点有足够的资源,那么 kube-scheduler 将检查是否通过驱逐(终止)一些优先级较低的 Pod,用来保障新的 Pod 可以调度。
让我们先了解一下 Kubernetes 调度是如何工作的。
Pod 调度
Kubernetes 调度是将 Pod 分配给节点的过程。
默认情况下,有一个负责调度的 Kubernetes 实体,称为 kube-scheduler,它将在控制平面上运行。Pod 将在 Pending 状态下开始,直到找到一个匹配的节点。
将一个 Pod 分配给一个节点的过程遵循这个顺序。
- 预选
- 打分
预选
在预选过程中,kube-scheduler 将选择当前 Pod 可能被放置的所有节点。这里将考虑到污点和容忍度等特征。一旦完成,它将有一个适合该 Pod 的节点列表。
打分
在打分过程中,kube-scheduler 将从上一步得到的列表中,给每个节点分配一个分数。这样一来,候选节点就会从最合适到最不合适排序。如果两个节点有相同的分数,kube-scheduler 会将它们随机排序。
但是,如果没有合适的节点让 Pod 运行,会发生什么?在这种情况下,Kubernetes 将启动抢占程序,试图驱逐低优先级的 Pod,以便分配新的 Pod。
Pod Priority Class
怎样才能防止某个特定的 Pod 在抢占过程中被驱逐?有时候,一个特定的 Pod 对你来说是至关重要的,不应该被终止。
这就是为什么 Kubernetes 具有 Priority Class。
Priority Class 是一个 Kubernetes 对象,允许我们将数字优先级值映射到特定的 Pod。那些数值较高的被归类为更重要,不太可能被驱逐。
你可以通过以下方式查询当前的 Priority Class。
kubectl get priorityclasses
kubectl get pc
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 2d
system-node-critical 2000001000 false 2d
测试 Priority Class
这里有三个 Pod:blueberry, raspberry 和 strawberry。
NAME READY STATUS RESTARTS AGE
blueberry 1/1 Running 0 4h41m
raspberry 1/1 Running 0 58m
strawberry 1/1 Running 0 5h22m
还有两个 Priority Class:trueberry 和 falseberry。其中 trueberry 拥有比较高的优先级。
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: trueberry
value: 1000000
globalDefault: false
description: "This fruit is a true berry"
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: falseberry
value: 5000
globalDefault: false
description: "This fruit is a false berry"
- blueberry 将使用 trueberry
- raspberry 和 strawberry 将使用 ffalseberry
这意味着在发生抢占的情况下,raspberry 和 strawberry 更有可能被驱逐,以便为更高优先级的 Pod 腾出空间。
然后通过在 Pod 定义中加入优先级类别,将其分配给 Pod。
priorityClassName: trueberry
现在让我们试着再增加三种水果:所有的新水果将包含更高的优先级类,称为 trueberry。
由于这三个新的水果对内存或 CPU 的要求是节点无法满足的,kubelet 会驱逐所有比新水果优先级低的 Pod。Blueberry 保持运行,因为它有更高的优先级。
NAME READY STATUS RESTARTS AGE
banana 0/1 ContainerCreating 0 2s
blueberry 1/1 Running 0 4h42m
raspberry 0/1 Terminating 0 59m
strawberry 0/1 Terminating 0 5h23m
tomato 0/1 ContainerCreating 0 2s
watermelon 0/1 ContainerCreating 0 2s
最终结果如下:
NAME READY STATUS RESTARTS AGE
banana 1/1 Running 0 3s
blueberry 1/1 Running 0 4h43m
tomato 1/1 Running 0 3s
watermelon 1/1 Running 0 3s
节点压力驱逐
除了抢占之外,Kubernetes 还不断检查节点资源,如磁盘压力、CPU 或内存不足(OOM)。
如果节点的资源(如 CPU 或内存)消耗达到一定的阈值,Kubelet 将开始驱逐 Pod,以释放资源。服务质量(QoS)将被纳入考虑范围,以确定驱逐顺序。
服务质量 QoS
在 Kubernetes 中,Pod 被赋予三种 QoS 类别之一,这将定义它们在缺乏资源的情况下被驱逐的可能性。这三种 QoS 分别是:
- Guaranteed
- Burstable
- BestEffort
这些 QoS 类别是如何分配给 Pod 的?这是基于对 CPU 和内存的限制和请求。
- limits:一个容器可以使用的资源的最大数量。
- requests:容器运行所需的最小资源量。
Guaranteed
如果一个 Pod 被分配了一个 Guaranteed 的 QoS 等级,它们的特征如下:
- Pod 中的所有容器都为 CPU 和内存设置了限制和请求。
- 在 Pod 中的所有容器都有相同的 CPU 限制和 CPU 请求的值。
- Pod 中的所有容器都有相同的内存限制和内存请求值。
一个有保证的 Pod 在正常情况下不会被驱逐以分配给节点中的另一个 Pod。
Burstable
如果一个 Pod 的 QoS 等级为 Burstable,那么它将被分配到一个 QoS 等级。
- 它没有担保的 QoS 等级。
- 为 Pod 中的一个容器设置了限制或请求。
一个 Burstable Pod 可以被驱逐,但比下一个类别的可能性小。
BestEffort
一个 Pod 将被分配一个 BestEffort 的 QoS 类别,它们将:
- 没有为 Pod 中的任何容器设置限制和请求。
BestEffort Pod 在节点中发生节点压力过程的情况下具有最高的驱逐机会。
重要的是:在限制和请求中可能有其他可用的资源,如短暂的存储,但它们不用于 QoS 类的计算。
如前所述,QoS 类将被纳入节点压力驱逐的考虑范围。以下是内部发生的过程。
kubelet 按照以下顺序排列要被驱逐的 Pod。
- 使用量超过请求的 BestEffort Pods 或 Burstable Pods
- 使用量低于请求的 Burstable Pods 或 Guaranteed Pods
Kubernetes 将尝试在第二组之前驱逐第一组的 Pod。
从上述内容中得到的一些启示。
- 如果在你的容器中添加了非常低的请求,他们的 Pod 可能会被分配到组 1,这意味着它更有可能被驱逐。
- 你无法知道哪个特定的 Pod 会被驱逐,只是 Kubernetes 会尝试在第 2 组之前驱逐第 1 组的 Pod。
- 有保证的 Pod 通常不会被驱逐:Kubelet 不会为了安排其他 Pod 而驱逐它们。但是,如果一些系统服务需要更多的资源,kubelet 将在必要时终止有保证的 Pod,并且总是以最低的优先级。
其他类型的驱逐
本文主要介绍抢占和节点压力驱逐,但 Pod 也可以通过其他方式被驱逐。例子包括。
API 发起的驱逐
你可以通过使用 Kubernetes Eviction API【1】请求对你的一个节点中的 Pod 进行按需驱逐。
基于污点的驱逐
通过 Kubernetes 污点和容忍度,可以指导你的 Pod 应该如何分配给 Node。但是,如果你将 NoExecute 污点应用于现有的 Node,所有不容忍它的 Pod 将被立即驱逐。
节点排水
有些时候,节点变得无法使用,或者你不想再在上面工作。命令 kubectl cordon 可以防止新的 Pod 被安排在它上面,但也有可能一次性完全清空所有当前 Pod。如果你运行 kubectl drain nodename,该节点中的所有 Pod 将被驱逐,尊重其优雅的终止期。
Kubernetes Pod 驱逐监控
在你的云解决方案中,你可以使用 Prometheus 来轻松监控 Pod 驱逐的做法。
kube_pod_status_reason{reason="Evicted"} > 0
这将显示你的集群中所有被驱逐的 Pod。你也可以将其与 kube_pod_status_phase{phase=“Failed”} 配对,以提醒那些在 Pod 发生故障后被驱逐的人。
如果你想深入了解,请查看以下关于 Prometheus 中监控资源的文章。
- 如何合理调整 Kubernetes 的资源限制【1】
- Kubernetes 容量规划:如何合理安排你的集群的请求【2】
总结
正如你所看到的,驱逐只是 Kubernetes 的另一个功能,它允许你控制有限的资源:在这种情况下,Pod 将使用的节点。
在抢占期间,Kubernetes 将试图通过驱逐优先级较低的 Pod 来释放资源,以安排一个新的 Pod。通过优先级类,你可以控制哪些 Pod 更有可能在抢占后继续运行,因为它们被驱逐的可能性较小。
在执行过程中,Kubernetes 将检查节点压力,并在需要时驱逐 Pod。通过 QoS 类,你可以控制哪些 Pod 在节点压力的情况下更有可能被驱逐。
内存和 CPU 是节点中的重要资源,你需要配置你的 Pod、容器和节点来使用它们的正确数量。如果你对这些资源进行相应的管理,不仅可以节省成本,而且还可以确保重要的进程无论如何都能继续运行。
文档
【1】https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#create-eviction-pod-v1-core
【1】https://sysdig.com/blog/kubernetes-resource-limits/
【2】https://sysdig.com/blog/kubernetes-capacity-planning/