3. 资源规格(ResourceSpec):CPU、内存、GPU等资源的请求(Request)与限制(Limit)模型

资源规格是容器运行时控制面中描述“容器需要多少计算资源”的核心数据结构。在 Kubernetes 与 CRI 集成中,Request(请求) 和 Limit(限制) 构成了资源调度的双维度模型。理解这一模型,是掌握资源隔离、服务质量(QoS)分级和节点压力驱逐的基础。

3.1 双维度模型:Request 与 Limit 的语义

Kubernetes 将资源描述拆分为两个独立但关联的字段:

维度 语义 调度影响 运行时影响
Request 容器启动时保证获得的最小资源量 调度器以此值计算节点剩余容量,决定 Pod 能否调度 CRI 运行时(如 containerd)通过 cgroup 的 cpu.shares 和 memory.limit_in_bytes 保证下限
Limit 容器运行时允许使用的资源上限 调度器不直接使用 Limit 做准入判断 CRI 运行时通过 cgroup 的 cpu.cfs_quota_us 和 memory.limit_in_bytes 实施硬限制
关键原则:Request ≤ Limit。当 Request 未设置时,默认等于 Limit;当 Limit 未设置时,表示无上限(可突发使用节点空闲资源)。

3.2 CPU 资源模型:可压缩资源

CPU 属于可压缩资源(Compressible Resource)。当容器超出 Limit 时,会被限流(throttle),但不会被杀死。CRI 运行时通过 Linux CFS(Completely Fair Scheduler)实现 CPU 资源的请求与限制。

  • Request(CPU shares): 设置 cpu.shares,相对权重。例如 Request=2 的容器比 Request=1 的容器获得 2 倍 CPU 时间。
  • Limit(CPU quota): 设置 cpu.cfs_period_us 和 cpu.cfs_quota_us。例如 Limit=2(2000m),表示每 100ms 周期内最多使用 200ms CPU 时间。
  • 单位: 1 个 CPU 核心 = 1000m(millicores)。
# 示例:Pod 中容器资源规格定义
resources:
  requests:
    cpu: "500m"        # 保证 0.5 核
    memory: "256Mi"    # 保证 256 MiB
  limits:
    cpu: "1000m"       # 上限 1 核
    memory: "512Mi"    # 上限 512 MiB

3.3 内存资源模型:不可压缩资源

内存属于不可压缩资源(Incompressible Resource)。当容器超出内存 Limit 时,内核 OOM Killer 会介入,直接终止容器进程。CRI 运行时通过 cgroup 的 memory.limit_in_bytes 和 memory.soft_limit_in_bytes 实施控制。

参数 cgroup 映射 行为
Request memory.soft_limit_in_bytes(部分运行时) 调度保证,但内核不强制回收;节点内存压力时优先回收超出 Request 的部分
Limit memory.limit_in_bytes 硬限制,超过即触发 OOM Kill
注意:内存的 Request 与 Limit 差异过大时,可能导致节点内存过量使用(overcommit)。当节点内存不足时,超出 Request 的容器会被优先驱逐或杀死。

3.4 GPU 等扩展资源模型:不可压缩 + 显式声明

GPU、FPGA、NVMe 等扩展资源(Extended Resources)遵循不同的模型:

  • 不可压缩: 超出 Limit 无法被限流,只能失败或重试。
  • 显式声明: 必须通过 resources.requests 和 resources.limits 显式指定,且 Request 必须等于 Limit(不允许 overcommit)。
  • 设备插件机制: 通过 Kubernetes 设备插件(Device Plugin)上报资源,CRI 运行时通过 UpdateContainerResources 接口传递设备分配信息。
# GPU 资源声明示例
resources:
  requests:
    nvidia.com/gpu: 1
  limits:
    nvidia.com/gpu: 1    # Request == Limit,强制相等

3.5 资源模型在 CRI 集成中的传递路径

下图展示了从 Pod Spec 到 CRI 运行时 cgroup 配置的完整资源传递链路:

资源模型在 CRI 集成中的传递路径 Pod Spec (Request / Limit) Kubelet (资源计算 + 准入) CRI gRPC (CreateContainer / UpdateContainerResources) 容器运行时 (containerd / CRI-O) cgroup v1/v2 (cpu.shares / memory.limit_in_bytes) 资源规格传递说明 1. Kubelet 将 Request/Limit 转换为 CRI 的 LinuxContainerResources 2. 运行时写入 cgroup 文件系统 3. 内核根据 cgroup 参数执行调度/限流

3.6 QoS 等级与资源规格的关系

Kubernetes 根据 Request 和 Limit 的设置组合,将 Pod 划分为三个 QoS 等级,直接影响节点压力下的驱逐优先级:

QoS 等级 条件 驱逐优先级 典型场景
Guaranteed 所有容器 Request == Limit(且均设置) 最低(最后被驱逐) 数据库、关键中间件
Burstable 至少一个容器 Request < Limit 或仅设置 Request 中等 Web 服务、批处理任务
BestEffort 所有容器均未设置 Request 和 Limit 最高(最先被驱逐) 低优先级日志收集、缓存
实践建议:生产环境中,核心服务应使用 Guaranteed 等级(Request == Limit),避免因节点资源竞争导致意外驱逐。非关键任务可使用 Burstable 等级,利用空闲资源提升吞吐。

3.7 资源规格的 CRI 数据结构

在 CRI gRPC 接口中,资源规格通过 LinuxContainerResources 消息传递。以下是核心字段映射:

// CRI 接口定义(简化)
message LinuxContainerResources {
  // CPU 资源
  int64 cpu_period = 1;          // 对应 Limit 的 period (微秒)
  int64 cpu_quota = 2;           // 对应 Limit 的 quota (微秒)
  int64 cpu_shares = 3;          // 对应 Request 的 shares (权重)

  // 内存资源
  int64 memory_limit_in_bytes = 4;    // 对应 Limit
  int64 memory_soft_limit_in_bytes = 5; // 对应 Request (部分运行时)

  // 扩展资源(如 GPU)
  map<string, int64> hugepage_limits = 6;
  map<string, int64> unified = 7;     // cgroup v2 统一字段
}

Kubelet 在调用 CreateContainer 或 UpdateContainerResources 时,会将 Pod Spec 中的 Request/Limit 转换为上述 CRI 结构体,再由运行时写入 cgroup 文件系统。

3.8 资源模型设计要点总结

  • CPU 可压缩: 超出 Limit 时被限流,容器继续运行;Request 通过 shares 保证相对权重。
  • 内存不可压缩: 超出 Limit 时触发 OOM Kill;Request 通过 soft limit 提供调度保证。
  • GPU 等扩展资源: Request == Limit,不允许 overcommit;通过设备插件和 CRI 的 UpdateContainerResources 传递。
  • QoS 等级: 由 Request/Limit 组合决定,直接影响节点压力下的驱逐顺序。
  • CRI 传递: Kubelet → CRI gRPC → 容器运行时 → cgroup,形成完整的资源控制闭环。