bigywater.tech
Kubernetes · 109

Pod Overhead 与 RuntimeClass:额外开销怎么计入

RuntimeClass 除了选运行时,还有什么用?Pod Overhead 是怎么被算进调度和配额的?它会不会影响容器的 cgroup 限制?handler 没装时 Pod 什么表现?这篇用 runc 的两个 RuntimeClass 把这些环节逐个量出来。

350m
容器请求 100m 的 Pod 加上 250m overhead 后在节点 requests 里实际占用的 CPU
184 MiB
容器 limit 64Mi + overhead 120Mi 后 Pod 级 cgroup 的 memory.max
450m
ResourceQuota 里算上 overhead 后两个 Pod 的 requests.cpu 用量,超过 500m 上限的 Pod 被拒

overhead 被写进 Pod 并计入节点

实测 · 本机执行输出
  RuntimeClass runc-heavy:handler=runc;overhead.podFixed={cpu: 250m, memory: 120Mi}
  Pod plain(没写 runtimeClassName):spec.overhead=None;Pod heavy(runtimeClassName: runc-heavy):spec.overhead={'cpu': '250m', 'memory': '120Mi'}(RuntimeClass 准入控制器写进去的,容器 requests 都是 100m / 64Mi)
  节点 worker 的 Allocated resources(requests):加 plain 前 150m / 114Mi → 加 plain 后 250m / 178Mi → 再加 heavy 后 600m / 362Mi
  plain 增加 cpu 100m、heavy 增加 cpu 350m(= 100m + 250m overhead)

RuntimeClass runc-heavy:handler=runc,overhead.podFixed={cpu: 250m, memory: 120Mi}。Pod plain 不写 runtimeClassName,spec.overhead 是空;Pod heavy 写了 runtimeClassName: runc-heavy,spec.overhead={cpu: 250m, memory: 120Mi}——RuntimeClass 准入控制器写进去的,两个 Pod 的容器 requests 都是 100m / 64Mi。节点 worker 的 Allocated resources(requests):150m / 114Mi → 加 plain 后 250m / 178Mi → 再加 heavy 后 600m / 362Mi:plain 增加 100m,heavy 增加 350m(100m + 250m overhead)。

overhead 进入 Pod 的 cgroup

实测 · 本机执行输出
  plain(qosClass=Guaranteed):Pod 级 memory.max=64 MiB cpu.max=10000 100000;容器级 memory.max=64 MiB cpu.max=10000 100000
  heavy(qosClass=Guaranteed):Pod 级 memory.max=184 MiB cpu.max=35000 100000;容器级 memory.max=64 MiB cpu.max=10000 100000
  Pod 级限制 = 容器 limits 之和 + overhead;容器自己的限制不变——overhead 是给沙箱/运行时组件留的空间

plain(Guaranteed)的 Pod 级 memory.max=64 MiB、cpu.max=10000 100000,容器级相同;heavy 的 Pod 级 memory.max=184 MiB(64 + 120)、cpu.max=35000 100000(100m + 250m),而容器级 memory.max 仍是 64 MiB、cpu.max 10000 100000。Pod 级限制 = 容器 limits 之和 + overhead;应用的 OOM 边界仍是它自己的 limits,overhead 是给沙箱和运行时组件留的空间。

配额与调度

实测 · 本机执行输出
  命名空间已有 plain + heavy,ResourceQuota requests.cpu 上限 500m,已用 450m(plain 100m + heavy 100m + overhead 250m)
  再创建一个 heavy 类的 Pod(容器 100m + overhead 250m = 350m,合计会到 800m):退出码 1;['Error from server (Forbidden): error when creating "STDIN": pods "third" is forbidden: exceeded quota: q, requested: requests.cpu=350m, used: requests.cpu=450m, limited: requests.cpu=500m']
  再创建一个普通 Pod(100m,合计 550m 也超了):退出码 1;['Error from server (Forbidden): error when creating "STDIN": pods "small" is forbidden: exceeded quota: q, requested: requests.cpu=100m, used: requests.cpu=450m, limited: requests.cpu=500m']
  overhead 是 100 个 CPU 的 RuntimeClass runc-huge:Pod huge 的 phase=Pending;[('PodScheduled', 'Unschedulable', '0/3 nodes are available: 1 node(s) had untolerated taint(s), 2 Insufficient cpu. preemption: 0/3 nodes are available: 3 Preemption is not helpful for ')]

命名空间已有 plain + heavy,ResourceQuota requests.cpu 上限 500m,已用 450m(plain 100m + heavy 100m + overhead 250m)。再创建一个 heavy 类的 Pod(容器 100m + overhead 250m = 350m)被拒:exceeded quota: q, requested: requests.cpu=350m, used: requests.cpu=450m, limited: requests.cpu=500m;一个普通的 100m Pod 也被拒(450 + 100 > 500)。overhead 是 100 个 CPU 的 RuntimeClass runc-huge:Pod huge 一直 Pending,PodScheduled=False,0/3 nodes are available: … 2 Insufficient cpu。

RuntimeClass 不对

实测 · 本机执行输出
  runtimeClassName: nope(没有这个 RuntimeClass 对象):退出码 1;['Error from server (Forbidden): error when creating "STDIN": pods "missing-rc" is forbidden: pod rejected: RuntimeClass "nope" not found']
  RuntimeClass 存在但 handler: gvisor-not-installed 节点上没配:phase=Pending;None;容器状态 ['waiting']
  事件:['8s Warning FailedCreatePodSandBox pod/nohandler Failed to create pod sandbox: rpc error: code = Unknown desc = unable to get OCI runtime for sandbox "56b72be1f8aa9a3932c60360ac3625379dda49ab164fda83d946d2007eddb085": no runtime for "gvisor-not-installed" is co']

runtimeClassName 写了不存在的 RuntimeClass:创建被拒,pod rejected: RuntimeClass "nope" not found。RuntimeClass 存在但 handler: gvisor-not-installed 在节点 containerd 里没配置:Pod 能创建,停在 Pending,容器 waiting,事件 FailedCreatePodSandBox: … no runtime for "gvisor-not-installed" is configured。

分步演示

RuntimeClass 与 Overhead
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,containerd 默认只有 runc 一个 handler),所有 Pod 固定在 worker;overhead 值是人为设定的(250m / 120Mi),不是真实运行时的数值;节点 requests 来自 kubectl describe node 的 Allocated resources;cgroup 数据读自节点;每种情形各一次
    • 没有验证:真实的沙箱运行时(Kata、gVisor、Firecracker)和它们的 overhead;RuntimeClass.scheduling(nodeSelector、tolerations);Pod Overhead 对 kubelet 驱逐、HPA 计算的影响;overhead 对 BestEffort / Burstable Pod 的 cgroup 设置;RuntimeClass 的 handler 命名规则(DNS label)
    京ICP备2026067502号-1京公网安备11010502063487号