Pod 开销
Kubernetes v1.24 [稳定]
当你在节点上运行 Pod 时,Pod 本身会占用一定量的系统资源。这些资源是运行 Pod 内容器所需的资源之外的附加资源。在 Kubernetes 中,Pod 开销(Pod Overhead) 是一种计算 Pod 基础设施在容器请求和限制之上所消耗资源的方式。
在 Kubernetes 中,Pod 的开销(overhead)在准入时,根据 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 handler 的工作负载,其内存和 CPU 开销将被计入资源配额计算、节点调度以及 Pod cgroup 大小确定中。
考虑运行给定的示例工作负载 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 名称,准入控制器会修改 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 或定义了 limits 的 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 的内存 cgroups。在以下示例中,节点上使用了 crictl
,它提供了 CRI 兼容容器运行时的 CLI。这是一个高级示例,用于展示 Pod 开销行为,不期望用户需要直接在节点上检查 cgroups。
首先,在特定节点上,确定 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 开销,并帮助观察运行指定开销的工作负载的稳定性。
接下来
- 详细了解 RuntimeClass
- 阅读 PodOverhead 设计 增强提案以获取更多背景信息