4. 容器化成本基础:Docker与Kubernetes资源模型
在云原生环境中,成本控制的第一道防线并非事后账单分析,而是资源申明。Docker 与 Kubernetes 的资源模型定义了容器如何“请求”和“限制”计算资源,直接决定了调度决策、节点密度以及最终的账单金额。理解这一模型,是 FinOps 从“被动看账”转向“主动控费”的起点。
4.1 Docker 资源约束:容器的“沙箱配额”
Docker 通过 Linux cgroups 对容器进行资源隔离。在 docker run 或 Compose 文件中,可以设置 CPU 和内存的软硬限制:
| 参数 | 类型 | 含义 | 成本影响 |
|---|---|---|---|
--memory |
硬限制 | 容器最多使用的内存量,超过则 OOM Kill | 防止单容器内存泄漏撑爆节点,避免节点扩容成本 |
--memory-reservation |
软限制 | 当宿主机内存竞争时,优先回收至此值以下 | 允许超卖,提升节点装箱率,降低单位 Pod 成本 |
--cpus |
硬限制 | 容器可使用的 CPU 核心数(如 1.5) | 限制 CPU 突发,避免干扰同节点其他容器 |
--cpu-shares |
软权重 | CPU 时间片分配权重(默认 1024) | 空闲时可用全部 CPU,竞争时按比例分配 |
--memory 和 --memory-reservation。仅设置硬限制会导致节点内存碎片化;仅设置软限制则无法阻止单容器失控。两者配合可在“稳定性”与“装箱率”之间取得平衡。
4.2 Kubernetes 资源模型:Requests 与 Limits
Kubernetes 将 Docker 的底层约束抽象为两个核心字段——requests 和 limits,分别对应“调度保证”和“运行时上限”。
apiVersion: v1
kind: Pod
metadata:
name: finops-demo
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
memory: "256Mi"
cpu: "500m" # 0.5 核
limits:
memory: "512Mi"
cpu: "1000m" # 1 核
4.2.1 Requests:调度决策的“承诺”
- 调度依据: kube-scheduler 只检查
requests,确保节点剩余资源 ≥ Pod 的 requests 总和。 - 成本绑定: 云厂商(如 EKS、AKS、GKE)的节点计费按实际运行时长,但内部成本分摊通常按 requests 比例计算。一个 Pod 即使空闲,也会按 requests 值占用成本。
- 超卖风险: 若所有 Pod 的 requests 总和超过节点容量,但实际使用量较低,节点仍可正常运行;一旦突发,则触发 CPU 节流或 OOM。
4.2.2 Limits:运行时“防爆墙”
- CPU Limits: 通过 CFS 配额控制,超过时强制节流(throttle),不会 OOM,但延迟会飙升。
- Memory Limits: 硬限制,超过即触发 OOM Kill,容器被重启。
- 成本陷阱: 设置过高的 limits 而不调整 requests,会导致节点资源碎片化,降低装箱效率。
4.3 CPU 与内存的计价方式
在公有云 Kubernetes 环境中,CPU 和内存的计价并非直接按“Pod 规格 × 单价”,而是通过节点成本分摊间接计算。以下是三种主流计价模型:
| 计价模型 | 计算方式 | 适用场景 | FinOps 关注点 |
|---|---|---|---|
| 节点级分摊 | 节点总成本 ÷ 节点可分配资源 × Pod requests | 混合负载、节点共享 | 需排除系统组件(kube-system)的资源占用 |
| 预留实例/节省计划 | 预付折扣价 + 按需价 × 超出部分 | 稳态工作负载 | 预留覆盖率 ≥ 80% 时成本最优 |
| Spot 实例 | 按实时竞价,通常为按需价的 60%~90% 折扣 | 无状态、容错、批处理 | 需配合 PodDisruptionBudget 和节点中断处理 |
4.3.1 单位成本换算示例
假设一个 m6i.large 节点(2 vCPU, 8 GiB)按需价格为 $0.096/小时,可分配资源扣除系统开销后约为 1.8 vCPU 和 7 GiB 内存:
- CPU 单价: $0.096 ÷ 1.8 = $0.0533 / vCPU·小时
- 内存单价: $0.096 ÷ 7 = $0.0137 / GiB·小时
- Pod 成本: 若 Pod requests 为 0.5 vCPU + 1 GiB,则每小时成本 = 0.5×0.0533 + 1×0.0137 = $0.0404
注意:limits 不直接参与成本计算,但过高的 limits 会降低节点可调度 Pod 数量,间接推高单 Pod 成本。
4.4 资源模型与成本控制的关系图
下图展示了从 Docker 容器约束到 Kubernetes 资源申明,再到云厂商计费模型的完整链路:
4.5 资源模型对比:QoS 类与成本权衡
Kubernetes 根据 requests 和 limits 的配置关系,将 Pod 分为三种 QoS 类,直接影响调度优先级和成本效率:
| QoS 类 | 配置条件 | 调度保证 | 成本效率 | 推荐场景 |
|---|---|---|---|---|
| Guaranteed | requests == limits(CPU 和内存均相等) | 最高,不会被 OOM 或驱逐 | 低(资源预留多,装箱率低) | 关键数据库、有状态中间件 |
| Burstable | requests < limits(至少一个资源不等) | 中等,资源充足时可突发 | 高(允许超卖,装箱率高) | 微服务、Web 应用、批处理 |
| BestEffort | 未设置 requests 和 limits | 最低,资源不足时优先被驱逐 | 极高(完全超卖) | 非生产、可中断任务 |
4.6 资源请求与限制的常见陷阱
- 陷阱一:requests 设置过高 —— 导致节点资源浪费,单 Pod 成本虚高。例如将 requests 设为 2 vCPU 但实际使用仅 0.3 vCPU,成本被放大 6 倍。
- 陷阱二:limits 设置过低 —— 导致 CPU 频繁节流,应用延迟增加,进而触发 HPA 扩容,产生额外 Pod 成本。
- 陷阱三:忽略内存的不可压缩性 —— CPU 可以节流,内存超过 limits 直接 OOM。内存 requests 应基于实际使用量 + 安全缓冲(通常 20%~30%)。
- 陷阱四:所有容器使用相同资源规格 —— 不同微服务的资源特征差异巨大,应逐服务进行压测和调优。
教训: 没有经过压测的资源申明,本质上是“拍脑袋”的成本浪费。
4.7 本章小结
容器化成本的基础在于理解资源申明(requests/limits)与计价模型之间的映射关系。Docker 提供底层约束能力,Kubernetes 将其抽象为调度和运行时策略,而云厂商的计费最终落在节点级分摊上。FinOps 工程师的核心任务,就是通过持续压测、动态调整和成本可视化,找到每个工作负载的“资源甜点”——既满足性能 SLO,又最大化节点装箱率,从而降低单位业务成本。