4. 节点资源模型:CPU、内存、临时存储、扩展资源(GPU、FPGA)的调度语义

在 Kubernetes 集群中,每个节点都是一个资源池。调度器(kube-scheduler)的核心职责是根据 Pod 的 资源请求(Requests) 与 限制(Limits),在满足节点剩余容量的前提下完成绑定。理解不同资源类型的调度语义,是进行容量规划与节点扩容的前提。

4.1 资源类型与调度语义矩阵

Kubernetes 将节点资源分为四大类,每一类在调度器中的处理逻辑存在显著差异:

资源类型 单位 是否可压缩 调度依据 超卖风险 典型场景
CPU cores(核) / millicores(m) 是 Requests(可压缩) 低(限流不杀死) 通用计算、Web 服务
内存 bytes(Mi / Gi) 否 Requests(不可压缩) 高(OOM Kill) 缓存、数据库、有状态服务
临时存储 bytes(Mi / Gi) 否 Requests(不可压缩) 中(Eviction) 日志、镜像层、emptyDir
扩展资源 整数(如 1, 2, 4) 否 Requests(显式声明) 低(独占设备) GPU、FPGA、RDMA
关键原则:调度器只检查 Requests,不检查 Limits。Limits 仅在运行时由 kubelet 执行 QoS 强制。这意味着容量规划必须基于 所有 Pod 的 Requests 总和,而非实际使用量。

4.2 CPU 调度语义:可压缩资源的弹性边界

CPU 是唯一被 Kubernetes 定义为 可压缩资源(Compressible) 的类型。当节点 CPU 使用率超过 100% 时,kubelet 会通过 CFS 配额对 Pod 进行限流(Throttling),但不会杀死容器。

  • 调度语义:调度器使用 requests.cpu 计算节点已分配量。例如,一个 Pod 声明 requests: cpu: 500m,调度器认为该 Pod 会占用节点 0.5 核。
  • 超卖策略:允许节点上所有 Pod 的 Requests 总和超过节点总 CPU 核数(即超卖)。但超卖比例过高会导致 CPU Throttling 加剧,影响延迟敏感型应用。
  • 容量规划建议:对于在线业务,建议节点 CPU 分配率(Allocation Ratio)控制在 60%–80%;对于离线批处理任务,可放宽至 100%–150%。
# 示例:Pod CPU 声明
resources:
  requests:
    cpu: "500m"        # 调度保证 0.5 核
  limits:
    cpu: "1000m"       # 运行时最多使用 1 核,超限则限流

4.3 内存调度语义:不可压缩资源的严格边界

内存是 不可压缩资源(Incompressible)。一旦节点内存耗尽,kubelet 会触发 OOM Killer 选择并杀死容器。调度器必须确保节点上所有 Pod 的 requests.memory 总和不超过节点可分配内存。

  • 调度语义:严格按 requests.memory 进行准入检查。如果节点剩余内存小于 Pod 的请求值,调度器直接跳过该节点。
  • OOM 风险:即使调度成功,如果 Pod 实际使用内存超过 limits.memory,容器会被 OOM Kill。如果 Pod 未设置 limits,但节点整体内存不足,QoS 等级最低的 Pod 会先被杀死。
  • 容量规划建议:内存分配率建议控制在 70%–85%,预留 15%–30% 作为系统开销和突发缓冲。
常见陷阱:很多团队只设置 CPU Requests 而忽略内存 Requests,导致调度器低估内存压力。当节点内存实际使用率飙升时,OOM 事件会集中爆发。务必为每个生产级 Pod 同时设置 CPU 和内存的 Requests。

4.4 临时存储调度语义:被忽视的容量瓶颈

临时存储(Ephemeral Storage)包括容器日志、可写层、emptyDir 卷以及镜像层。Kubernetes 1.19+ 开始支持 ephemeral-storage 的显式声明。

  • 调度语义:与内存类似,属于不可压缩资源。调度器检查 requests.ephemeral-storage,确保节点剩余临时存储满足 Pod 需求。
  • 驱逐机制:当节点临时存储使用率超过 eviction-hard 阈值(默认 85%),kubelet 开始驱逐 Pod。如果 Pod 未设置存储请求,则按 Best-Effort 等级优先驱逐。
  • 容量规划建议:为每个 Pod 设置合理的 requests.ephemeral-storage,避免日志爆满导致节点驱逐风暴。建议节点预留 20% 临时存储作为系统保护。
# 示例:Pod 临时存储声明
resources:
  requests:
    ephemeral-storage: "1Gi"
  limits:
    ephemeral-storage: "2Gi"

4.5 扩展资源调度语义:GPU、FPGA 的独占模式

扩展资源(Extended Resources)如 GPU、FPGA、RDMA 等,通常以 整数计数 形式上报,且为 不可压缩、不可超卖 的独占资源。

  • 调度语义:调度器使用 requests 进行精确匹配。例如,Pod 声明 nvidia.com/gpu: 1,调度器会寻找剩余 GPU 数量 ≥ 1 的节点。
  • 设备插件机制:GPU/FPGA 等资源由 Device Plugin 负责发现、上报和分配。调度器不感知设备内部拓扑(如 GPU 显存大小、NVLink 连接),仅做整数计数。
  • 容量规划挑战:由于 GPU 等资源价格昂贵且不可超卖,节点扩容时必须精确匹配工作负载的 GPU 型号、显存大小和互联拓扑。建议使用 Node Feature Discovery(NFD) 结合节点标签进行精细化调度。
扩展资源调度流程:
  1. Device Plugin 向 kubelet 注册并上报资源数量(如 nvidia.com/gpu=4)。
  2. kubelet 将资源数量更新到 Node 对象的 status.capacity 和 status.allocatable。
  3. 调度器读取 Node 的 allocatable,减去已分配 Pod 的 Requests,得到剩余量。
  4. Pod 声明扩展资源 Requests,调度器执行整数匹配。
  5. 调度成功后,kubelet 调用 Device Plugin 的 Allocate 接口完成设备绑定。
节点资源模型与调度决策流程 节点资源池(Node Allocatable) CPU 可压缩 · 超卖允许 调度依据:Requests 内存 不可压缩 · OOM 风险 调度依据:Requests 临时存储 不可压缩 · 驱逐风险 调度依据:Requests 扩展资源 不可压缩 · 独占设备 调度依据:整数 Requests kube-scheduler 调度决策 检查 Node Allocatable - Σ(Pod Requests) ≥ 0 调度成功 → 绑定 Pod 调度失败 → 等待/排队 容量规划核心公式:节点可分配资源 ≥ 所有 Pod 的 Requests 总和 + 系统预留 + 驱逐阈值

4.6 资源模型与节点扩容的映射关系

节点扩容决策必须基于上述资源模型的调度语义。以下是不同资源瓶颈下的扩容策略对比:

瓶颈资源 扩容触发条件 扩容策略 注意事项
CPU 节点 CPU 分配率 > 80%,且 Throttling 持续上升 增加同规格节点,或使用更大核数实例 CPU 超卖可短期缓解,但需监控限流比例
内存 节点内存分配率 > 85%,或出现 OOM Kill 增加内存密集型节点,或垂直扩容(更大内存实例) 内存不可超卖,必须预留安全缓冲
临时存储 节点临时存储使用率 > 80%,或 Pod 被驱逐 增加节点,或调整 Pod 日志轮转策略 优先优化日志和 emptyDir 使用量,再考虑扩容
GPU/FPGA GPU 分配率 = 100%,且存在 Pending Pod 增加同 GPU 型号节点,或使用多 GPU 实例 必须匹配 GPU 驱动和 CUDA 版本,避免碎片化
容量规划最佳实践:
  • 使用 Cluster Autoscaler 结合 Pod Disruption Budget(PDB) 实现自动扩容。
  • 为每个节点池设置 资源分配率告警(CPU 80%、内存 85%、临时存储 80%)。
  • GPU 节点建议使用 节点亲和性(Node Affinity) 和 拓扑管理策略(Topology Manager) 保证设备对齐。
  • 定期使用 kubectl describe node 检查 Allocated resources 和 Allocatable 的差值,识别资源碎片。