Pod 开销

特性状态: Kubernetes v1.24 [稳定]

当你在节点上运行 Pod 时,Pod 本身会占用一定量的系统资源。这些资源除了运行 Pod 内容器所需的资源外,还需要额外开销。在 Kubernetes 中,“Pod 开销”(Pod Overhead)是一种用于在容器请求和限制之外计算 Pod 基础设施所消耗资源的方法。

在 Kubernetes 中,Pod 的开销是在准入(Admission)阶段,根据与 Pod 的 RuntimeClass 相关联的开销进行设置的。

在调度 Pod 时,Pod 的开销会被计入容器资源请求的总和之中。同样,kubelet 在调整 Pod cgroup 大小以及执行 Pod 驱逐排名时,也会包含 Pod 开销。

配置 Pod 开销

你需要确保使用了定义了 overhead 字段的 RuntimeClass

使用示例

要使用 Pod 开销,你需要一个定义了 overhead 字段的 RuntimeClass。例如,你可以将以下 RuntimeClass 定义与虚拟化容器运行时(在本例中,Kata Containers 结合 Firecracker 虚拟机监控程序)一起使用,该运行时为每个 Pod 的虚拟机和客户机操作系统使用约 120MiB 的内存:

# You need to change this example to match the actual runtime name, and per-Pod
# resource overhead, that the container runtime is adding in your cluster.
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata-fc
handler: kata-fc
overhead:
  podFixed:
    memory: "120Mi"
    cpu: "250m"

创建并指定了 kata-fc RuntimeClass 处理程序的工作负载,将在资源配额计算、节点调度以及 Pod cgroup 大小调整时计入内存和 CPU 开销。

考虑运行给定的示例工作负载 test-pod

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  runtimeClassName: kata-fc
  containers:
  - name: busybox-ctr
    image: busybox:1.28
    stdin: true
    tty: true
    resources:
      limits:
        cpu: 500m
        memory: 100Mi
  - name: nginx-ctr
    image: nginx
    resources:
      limits:
        cpu: 1500m
        memory: 100Mi

说明

如果 Pod 定义中仅指定了 limits,kubelet 将从这些限制中推导出 requests,并将其设置为与定义的 limits 相同。

在准入时,RuntimeClass 准入控制器会更新工作负载的 PodSpec,以包含 RuntimeClass 中描述的 overhead。如果 PodSpec 中已定义了此字段,则 Pod 将被拒绝。在给定的示例中,由于仅指定了 RuntimeClass 名称,准入控制器会变更(mutate)该 Pod 以包含 overhead

RuntimeClass 准入控制器进行修改后,你可以检查更新后的 Pod 开销值:

kubectl get pod test-pod -o jsonpath='{.spec.overhead}'

输出如下:

map[cpu:250m memory:120Mi]

如果定义了 ResourceQuota,则容器请求的总和以及 overhead 字段都将被计入。

当 kube-scheduler 决定哪个节点应该运行一个新的 Pod 时,调度器会考虑该 Pod 的 overhead 以及该 Pod 的容器请求总和。在此示例中,调度器会将请求和开销相加,然后寻找一个拥有 2.25 CPU 和 320 MiB 可用内存的节点。

一旦 Pod 被调度到节点上,该节点上的 kubelet 会为 Pod 创建一个新的 cgroup。底层的容器运行时将在该 cgroup 内创建容器。

如果资源为每个容器定义了限制(Guaranteed QoS 或已定义限制的 Burstable QoS),kubelet 将为与该资源关联的 pod cgroup 设置上限(CPU 为 cpu.cfs_quota_us,内存为 memory.limit_in_bytes)。此上限基于容器限制总和加上 PodSpec 中定义的 overhead

对于 CPU,如果 Pod 是 Guaranteed 或 Burstable QoS,kubelet 将根据容器请求总和加上 PodSpec 中定义的 overhead 来设置 cpu.shares

查看我们的示例,验证工作负载的容器请求:

kubectl get pod test-pod -o jsonpath='{.spec.containers[*].resources.limits}'

总容器请求为 2000m CPU 和 200MiB 内存。

map[cpu: 500m memory:100Mi] map[cpu:1500m memory:100Mi]

根据节点观察到的数据进行核对:

kubectl describe node | grep test-pod -B2

输出显示请求为 2250m CPU 和 320MiB 内存。这些请求包括了 Pod 开销。

  Namespace    Name       CPU Requests  CPU Limits   Memory Requests  Memory Limits  AGE
  ---------    ----       ------------  ----------   ---------------  -------------  ---
  default      test-pod   2250m (56%)   2250m (56%)  320Mi (1%)       320Mi (1%)     36m

验证 Pod cgroup 限制

检查工作负载运行节点上的 Pod 内存 cgroup。在以下示例中,节点上使用了 crictl,它为 CRI 兼容的容器运行时提供 CLI。这是一个展示 Pod 开销行为的高级示例,用户通常不需要直接在节点上检查 cgroup。

首先,在特定节点上确定 Pod 标识符:

# Run this on the node where the Pod is scheduled
POD_ID="$(sudo crictl pods --name test-pod -q)"

由此,你可以确定 Pod 的 cgroup 路径:

# Run this on the node where the Pod is scheduled
sudo crictl inspectp -o=json $POD_ID | grep cgroupsPath

所得的 cgroup 路径包括了 Pod 的 pause 容器。Pod 级别的 cgroup 在上一级目录中。

  "cgroupsPath": "/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/7ccf55aee35dd16aca4189c952d83487297f3cd760f1bbf09620e206e7d0c27a"

在这种特定情况下,pod cgroup 路径为 kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2。验证 Pod 级别的内存 cgroup 设置:

# Run this on the node where the Pod is scheduled.
# Also, change the name of the cgroup to match the cgroup allocated for your pod.
 cat /sys/fs/cgroup/memory/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/memory.limit_in_bytes

正如预期的那样,这是 320 MiB。

335544320

可观测性

kube-state-metrics 中提供了一些 kube_pod_overhead_* 指标,用于帮助确定何时使用了 Pod 开销,并帮助观察在定义了开销的情况下运行的工作负载的稳定性。

接下来


最后修改于 2024年4月10日 下午5:56 (PST):解释 Pod 开销概念中的 RuntimeClass 名称 (#45454) (c25ceaa535)