在这里插入图片描述

引言

Kubernetes(K8s)是一个强大的容器编排平台,它通过声明式 API 为应用提供自动调度、弹性伸缩和资源隔离能力。然而,许多生产故障(Pod OOMKilled、节点不均衡、关键服务被驱逐)往往都与requests/limits 配置不当密切相关。

本文将深入剖析 Kubernetes 在调度与资源管理上的核心机制,包括:

  1. requestslimits 的定义与作用
  2. QoS 类别(Guaranteed、Burstable、BestEffort)及其驱逐机制
  3. OOM(Out-Of-Memory)与 Eviction 的区别与触发逻辑
  4. 生产环境常见问题与误区
  5. 最佳实践与优化策略(结合实战案例)

1. requests 与 limits:K8s 调度的基石

1.1 requests

  • 定义:容器在调度时至少需要的资源(CPU、内存)。

  • 作用:调度器根据 requests 计算 Pod 需要的资源,从而决定其能否放到某个节点。

    • CPU requests = scheduler 用于调度的“最小保证值”。
    • Memory requests = Pod 保证能获得的最小内存。

示例:

resources:
  requests:
    cpu: "200m"       # 200m = 0.2 vCPU
    memory: "256Mi"

1.2 limits

  • 定义:容器在运行时能够使用的最大资源上限

  • 超过 limits 的表现:

    • CPU:容器会被 限流(throttling),不会直接杀死。
    • Memory:如果超出内存 limit → 容器触发 OOMKill。

示例:

resources:
  limits:
    cpu: "500m"
    memory: "512Mi"

1.3 requests vs limits 的关系

  • requests ≤ limits(K8s 强制要求)
  • requests 决定调度,limits 决定运行时的约束
  • 生产实践:通常设置 requests = 平均用量limits = 峰值(合理冗余)

2. QoS 类别与驱逐策略

Kubernetes 根据 Pod 中 requests/limits 的配置,将 Pod 分为三类 QoS(Quality of Service),决定节点资源紧张时的驱逐顺序

2.1 Guaranteed

  • 条件:每个容器requests == limits,且 CPU/内存都设置了。
  • 特点:最高优先级,最不容易被驱逐。
  • 场景:关键业务(数据库、核心微服务)。

2.2 Burstable

  • 条件:至少有一个容器设置了 requests,但 requests ≠ limits。
  • 特点:介于 Guaranteed 和 BestEffort 之间,资源使用灵活。
  • 场景:大部分普通微服务。

2.3 BestEffort

  • 条件:没有容器设置 requests/limits
  • 特点:最低优先级,节点资源不足时最先被驱逐。
  • 场景:开发环境、临时批处理任务。

2.4 驱逐顺序

当节点资源不足时,驱逐优先级:

  1. BestEffort
  2. Burstable(超出 requests 且内存紧张时)
  3. Guaranteed(几乎最后才被驱逐)

3. OOM 与 Eviction:不一样的“被杀”

很多人容易混淆 OOMKillEviction,实际上它们的触发机制不同。

3.1 OOMKill(容器级别)

  • 触发条件:容器使用内存 > limits。
  • 行为:Linux cgroup 内存隔离机制触发,直接杀死容器(状态:OOMKilled)。
  • 日志表现:
kubectl describe pod <pod>
# Events 中会显示 OOMKilled

3.2 Eviction(节点级别)

  • 触发条件:节点整体内存/磁盘压力,超出 kubelet 配置的 eviction threshold。
  • 行为:kubelet 按照 QoS 优先级驱逐 Pod。
  • 日志表现:
kubectl describe node <node>
# Events 中会显示 "MemoryPressure" 或 "Evicted"

3.3 区别总结

特性 OOMKill (容器) Eviction (节点)
触发者 Linux cgroup kubelet
范围 单个容器 整个节点
条件 容器内存 > limits 节点内存/disk 不足
表现形式 Pod 状态 OOMKilled Pod 状态 Evicted

4. 常见问题与误区

4.1 未设置 requests/limits

  • 表现:调度器认为容器“零资源需求”,调度倾向于某些节点 → 节点资源倾斜。
  • 风险:BestEffort QoS → 最容易被驱逐。
  • 典型事故:关键 Pod 没有 requests,被驱逐导致业务中断。

4.2 requests 设置过大

  • 表现:Pod 明明只需要 200m CPU,却设置了 2 核 → 调度器认为节点资源不足,Pod Pending。
  • 风险:资源浪费,调度失败。
  • 典型事故:CI/CD 自动化创建的 Pod 全部 Pending。

4.3 limits 设置过小

  • 表现:应用有内存峰值,limits 配置过低 → 容器频繁 OOMKilled。
  • 风险:应用可用性差,频繁重启。
  • 典型事故:大查询时数据库容器被 OOMKill。

4.4 requests = limits(过于保守)

  • 好处:Guaranteed QoS,稳定性最高。
  • 风险:如果所有服务都这样配置,整体资源利用率会很低(因为 requests 过高)。

5. 最佳实践与优化策略

5.1 基于历史指标设定 requests/limits

  • 使用 Prometheus + kube-state-metrics + VPA(Vertical Pod Autoscaler)收集实际使用数据。

  • 经验值:

    • requests = P50(中位数用量)
    • limits = P95(峰值用量)

5.2 LimitRange 与 ResourceQuota

  • 在命名空间内设置默认 requests/limits,防止用户忘记配置。
apiVersion: v1
kind: LimitRange
metadata:
  name: ns-defaults
spec:
  limits:
  - default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 200m
      memory: 256Mi
    type: Container
  • ResourceQuota 控制整个命名空间资源上限,避免资源抢占。

5.3 QoS 策略应用

  • 核心业务:Guaranteed
  • 普通服务:Burstable
  • 临时任务:BestEffort(需容忍被驱逐)

5.4 Eviction 策略优化

  • 配置 kubelet --eviction-hard / --eviction-soft 参数,合理预留节点资源。
  • 配置 system-reservedkube-reserved,确保节点本身稳定。

5.5 自动化与治理

  • 使用 Admission Controller(OPA/Gatekeeper)强制要求所有 Pod 必须配置 requests/limits。
  • 使用 VPA(垂直自动扩缩容)或 HPA(水平扩缩容)动态调整。

6. 案例分析

项目线上事故分析:

  • 背景:交易网关服务容器配置 memory: 512Mi,但高峰时瞬时内存需求达到 800Mi。
  • 现象:容器频繁 OOMKilled,导致交易失败。
  • 原因:limits 设置过低,且 requests = limits,QoS 虽高,但没有给出峰值冗余。
  • 解决:通过历史数据分析,将 requests=500Milimits=1Gi,稳定运行,且通过 HPA 保证横向扩容。

结语

在 Kubernetes 中,调度与资源配置是稳定性的基石
合理设置 requests/limits → 正确分配 QoS → 避免 OOM 与无序驱逐 → 提升资源利用率与业务可用性。

在实际工程中,最关键的是:

  • 监控与数据驱动:基于真实指标设定 requests/limits,而不是拍脑袋。
  • 策略与自动化:通过 LimitRange/ResourceQuota/OPA 保证配置合规。
  • 演练与迭代:持续优化 requests/limits,避免资源浪费和业务中断。
Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐