K8s 中的资源限制与 Pod 驱逐策略

好的,各位观众,各位Geek,欢迎来到今天的K8s资源限制与Pod驱逐策略脱口秀!我是你们的老朋友,今天就让我们一起扒一扒K8s集群里那些“吃得多干得少”的Pod,以及如何优雅地把它们请出家门。

先别急着打瞌睡,我知道一听到“资源限制”、“驱逐策略”这些词,大家可能觉得枯燥。但相信我,这比你想象的有趣多了!你想想,你的K8s集群就像一个大House,里面住着各种各样的Pod,有的勤勤恳恳,有的好吃懒做。作为房东,你肯定希望资源分配公平合理,对不对?

今天我们就来聊聊,如何当好这个“房东”,让你的K8s House井然有序,高效运转。

一、资源限制:给Pod戴上“紧箍咒”

首先,我们要给Pod们戴上“紧箍咒”,也就是资源限制。这就像给孩子们零花钱一样,你得告诉他们,这个月能花多少,不能超支。

在K8s里,我们主要限制两种资源:CPU和内存。

  • CPU: 可以理解为Pod的“算力”,决定了Pod处理任务的速度。
  • 内存: 可以理解为Pod的“记忆力”,决定了Pod能存储多少数据。

K8s通过resources字段来设置Pod的资源限制,这个字段下面有两个子字段:

  • requests: 资源请求,Pod启动时向K8s声明自己需要的资源量。这就像你跟房东说:“我需要一间卧室,一个厨房。”
  • limits: 资源限制,Pod能使用的最大资源量。这就像房东说:“卧室和厨房你可以用,但不能把客厅也占了!”

让我们看一个例子:

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: main
    image: busybox:latest
    command: ["/bin/sh", "-c", "while true; do sleep 1; done"]
    resources:
      requests:
        cpu: "100m"  # 100 millicores,相当于0.1个CPU核心
        memory: "128Mi" # 128 MB
      limits:
        cpu: "500m"  # 500 millicores,相当于0.5个CPU核心
        memory: "256Mi" # 256 MB

这个Pod的含义是:

  • 启动时,它会告诉K8s:“我需要0.1个CPU核心和128MB内存。”
  • 但它最多可以使用0.5个CPU核心和256MB内存。

为什么要设置requests和limits?

  • Requests: 确保Pod能够获得足够的资源来启动和运行。K8s调度器会根据Pod的requests来选择合适的节点。如果节点上的可用资源不足以满足Pod的requests,Pod将无法被调度。
  • Limits: 防止Pod过度占用资源,影响其他Pod的运行。如果Pod尝试使用的资源超过了limits,K8s会采取相应的措施,例如限制CPU使用率或杀死Pod。

资源单位:

  • CPU: 可以用整数表示CPU核心数,也可以用带有"m"后缀的字符串表示millicores(千分之一个CPU核心)。例如,1表示1个CPU核心,100m表示0.1个CPU核心。
  • 内存: 可以用整数表示字节数,也可以用带有单位的字符串表示。例如,128974848128Mi都表示128MB。常见的单位有:
    • E, P, T, G, M, K (例如:5E, 4P, 3T, 2G, 1M, 5K)
    • Ei, Pi, Ti, Gi, Mi, Ki (例如:5Ei, 4Pi, 3Ti, 2Gi, 1Mi, 5Ki)

资源QoS等级:

K8s根据Pod的资源请求和限制,将Pod分为三种QoS等级:

  • Guaranteed: 最高优先级。Pod的所有容器都设置了相同的requests和limits,并且CPU和内存都有设置。这类Pod通常用于关键应用,例如数据库。
  • Burstable: 中等优先级。Pod的至少一个容器设置了requests,但requests不等于limits,或者只有CPU或内存设置了requests和limits。这类Pod通常用于不太重要的应用,例如Web服务器。
  • BestEffort: 最低优先级。Pod的所有容器都没有设置requests和limits。这类Pod通常用于对资源需求不高的应用,例如后台任务。

表格总结:

QoS等级 CPU Requests CPU Limits Memory Requests Memory Limits 优先级 适用场景
Guaranteed 等于 等于 等于 等于 核心服务
Burstable 已设置 可选 已设置 可选 普通应用
BestEffort 未设置 未设置 未设置 未设置 资源需求不高的任务

二、Pod驱逐策略:清理门户,腾笼换鸟

现在我们已经给Pod们戴上了“紧箍咒”,但总有一些Pod不听话,要么过度占用资源,要么节点本身资源不足。这时候,我们就需要祭出我们的“杀手锏”——Pod驱逐策略。

Pod驱逐是指K8s主动终止Pod的运行,并将Pod重新调度到其他节点上。这就像房东把不听话的租客赶走,然后找新的租客一样。

为什么要驱逐Pod?

  • 节点资源不足: 当节点上的CPU、内存、磁盘空间等资源不足时,K8s会驱逐一些Pod,以释放资源,保证节点的稳定运行。
  • 节点维护: 当需要对节点进行维护时,例如升级内核、更换硬件等,K8s会驱逐节点上的所有Pod,以便安全地进行维护操作。
  • 节点故障: 当节点发生故障时,例如硬件故障、网络故障等,K8s会自动驱逐节点上的所有Pod,并将它们重新调度到其他健康的节点上。

Pod驱逐的触发条件:

K8s通过kubelet组件来监控节点的资源使用情况,当节点的资源使用超过一定的阈值时,就会触发Pod驱逐。这些阈值是可以配置的,常见的阈值有:

  • memory.available: 可用内存低于某个值。
  • nodefs.available: 节点文件系统可用空间低于某个值。
  • nodefs.inodesFree: 节点文件系统可用inode数量低于某个值。
  • imagefs.available: 镜像文件系统可用空间低于某个值。
  • imagefs.inodesFree: 镜像文件系统可用inode数量低于某个值。
  • pid.available: 可用PID数量低于某个值。
  • disk pressure: 磁盘压力过高。
  • memory pressure: 内存压力过高。

Pod驱逐的优先级:

当需要驱逐Pod时,K8s会按照一定的优先级来选择要驱逐的Pod。优先级从低到高依次为:

  1. BestEffort Pods: 首先驱逐QoS等级为BestEffort的Pod。这类Pod没有设置资源请求和限制,因此被认为是最不重要的。
  2. Burstable Pods: 其次驱逐QoS等级为Burstable的Pod。这类Pod设置了资源请求,但没有达到Guaranteed级别,因此被认为优先级低于Guaranteed Pod。
  3. Guaranteed Pods: 最后驱逐QoS等级为Guaranteed的Pod。这类Pod设置了资源请求和限制,并且CPU和内存都有设置,因此被认为是最重要的。

在同一QoS等级的Pod中,K8s会优先驱逐资源使用率最高的Pod。

如何控制Pod驱逐?

虽然K8s会自动进行Pod驱逐,但我们也可以通过一些手段来控制Pod驱逐的行为。

  • PodDisruptionBudget (PDB): PDB允许你指定在自愿中断(例如节点维护)期间,一个Deployment、StatefulSet或ReplicationController中至少需要保持运行的Pod数量。这可以防止关键应用在维护期间完全停止服务。
  • Taints and Tolerations: Taints用于标记节点,Tolerations用于标记Pod。只有具有与节点Taint匹配的Toleration的Pod才能被调度到该节点上。通过使用Taints和Tolerations,你可以控制哪些Pod可以运行在哪些节点上,从而影响Pod驱逐的行为。
  • 优先级类 (PriorityClass): 优先级类允许你为Pod分配优先级,优先级高的Pod在资源竞争时更有可能被保留,而优先级低的Pod更容易被驱逐。

PDB示例:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-pdb
spec:
  minAvailable: 2 # 至少保持2个Pod可用
  selector:
    matchLabels:
      app: my-app

这个PDB的含义是:

  • 它保护所有带有app: my-app标签的Pod。
  • 在自愿中断期间,至少需要保持2个这样的Pod可用。

Taints and Tolerations示例:

# 为节点添加Taint
kubectl taint nodes node1 key=value:NoSchedule

# 为Pod添加Toleration
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: main
    image: busybox:latest
    command: ["/bin/sh", "-c", "while true; do sleep 1; done"]
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

这个例子中,我们为节点node1添加了一个Taint,表示只有具有相应Toleration的Pod才能被调度到该节点上。然后,我们为Podmy-pod添加了一个Toleration,使其能够被调度到node1上。

优先级类示例:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for high-priority pods only."

---
apiVersion: v1
kind: Pod
metadata:
  name: my-high-priority-pod
spec:
  containers:
  - name: main
    image: busybox:latest
    command: ["/bin/sh", "-c", "while true; do sleep 1; done"]
  priorityClassName: high-priority

这个例子中,我们定义了一个名为high-priority的优先级类,并将其值设置为1000000。然后,我们将Podmy-high-priority-podpriorityClassName设置为high-priority,使其具有高优先级。

三、总结:K8s资源管理,任重道远

好了,今天的K8s资源限制与Pod驱逐策略脱口秀就到这里了。希望通过今天的讲解,大家对K8s的资源管理有了更深入的理解。

总而言之,K8s资源管理是一个复杂但重要的课题。我们需要根据应用的特点和集群的资源状况,合理地设置资源限制,并灵活地运用Pod驱逐策略,才能保证K8s集群的稳定运行和高效利用。

记住,K8s集群就像一个生态系统,我们需要像爱护环境一样,爱护我们的K8s集群,才能让它健康成长,为我们提供源源不断的动力。

最后,送给大家一句忠告:

资源限制要合理,Pod驱逐要优雅,K8s集群才能长长久久!

感谢大家的收听,我们下期再见! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注