跳到内容

第 7 卷 / 第 11 章 / 第 3 课

11.3 Kubernetes 容量治理:调度、扩缩容与中断 ​

Kubernetes 可以把 Pod 放到节点,也可以调整副本数,但它不知道哪种延迟、成本和故障风险对业务可接受。生产容量治理要把 requests、limits、调度约束、HPA、PDB 和租户边界看成一套相互作用的控制系统。

Requests 决定调度,Limits 约束运行 ​

下面是单个容器的 resources 字段片段,应放进 Pod 模板的容器配置中:

yaml
resources:
  requests:
    cpu: 500m
    memory: 768Mi
  limits:
    cpu: "2"
    memory: 1Gi

调度器按 requests 判断节点是否容纳 Pod,而不是按瞬时实际用量。request 长期高估会让节点看似已满;低估则会在峰值时过度装箱。

CPU limit 通常通过节流执行,可能在节点还有空闲 CPU 时也增加尾延迟;内存 limit 超出后进程可能被 OOM kill。是否设置 CPU limit 应由多租户风险和延迟测试决定,不能把同一模板套给所有服务。内存 request 与 limit 则应结合工作集、峰值和 OOM 恢复成本设置。

副本要跨故障域分布 ​

三个副本若都在同一节点或可用区,数量并没有转化为可用性。以下 Pod spec 片段要求 Pod 带有 app: atlas-api 标签,节点的 zone/hostname 标签可信且正确,并有三个符合调度条件的可用区:

yaml
topologySpreadConstraints:
  - maxSkew: 1
    minDomains: 3
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: atlas-api
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app: atlas-api

maxSkew: 1 限制计数偏差,本身不要求三个可用区;若只有一个合格区,默认条件下三个副本仍可全放那里。示例加上 minDomains: 3:合格域不足三个时按全局最小计数为 0 计算,这会阻止继续向已有域堆副本,也可能让故障后的替代 Pod Pending。hostname 的软约束只影响调度偏好。需要结合各域余量选择分布与故障期间容量的取舍。

Taint/toleration 允许特定 Pod 进入节点,不会保证它一定被调度到那里;需要定向时还要结合 node affinity。不要用用户可随意添加的 label 承载安全隔离,受信任的节点标签必须由受控身份维护。

HPA 的分母来自 Request ​

CPU utilization 目标大致基于:

text
当前用量 / CPU request

如果容器没有相应 request,HPA 无法正确计算该资源利用率。request 改变也会在真实负载不变时改变 HPA 观察到的百分比。

下面假设同 namespace 已有 atlas-api Deployment,容器都配置了 CPU request,且资源指标 API 可用:

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: atlas-api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: atlas-api
  minReplicas: 3
  maxReplicas: 30
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 25
          periodSeconds: 60
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

忽略容差、缺失指标和启动修正时,期望副本约为 ceil(当前副本数 × 当前利用率 / 目标利用率)。例如 3 个副本平均 90%,目标 60%,得到 5 个副本,再受上下限与伸缩策略约束。缩容的 300 秒稳定窗口取窗口内较高的副本建议,不是每次简单睡满 300 秒。

对队列消费者,积压量或最老消息年龄通常比 CPU 更接近需求,需配相应 custom/external metrics 接口。对延迟敏感服务,可用并发数驱动扩容,并以业务 SLI 校验效果;若延迟来自已过载的共享数据库,增加应用副本未必能改善。指标管线失效、冷启动时间和节点扩容延迟必须进入容量预算,否则 HPA 只会生成一批 Pending Pod。

不要让 HPA 和 VPA 同时争夺同一资源信号而不分析反馈回路:VPA 改 request 会改变 HPA 的 utilization 分母。

PDB 只约束自愿中断 ​

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: atlas-api
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: atlas-api

PDB 限制通过 Eviction API 发起的自愿中断,例如尊重 PDB 的节点 drain。它不能阻止节点宕机,也不会限制 Deployment 自己的滚动升级,更不能替代足够副本和跨域分布。

例子在 3 个匹配 Pod 都 Ready 时允许驱逐 1 个;已有 1 个不健康时,通常不再允许驱逐其他健康 Pod。直接删除 Pod、工作负载缩容也不靠 PDB 阻止。若不健康 Pod 卡住 drain,可评估 unhealthyPodEvictionPolicy: AlwaysAllow,但必须确认驱逐后的恢复方式。

过严 PDB 会让节点无法维护。设置前要同时检查副本数、maxUnavailable、readiness、终止时间和集群升级策略。

Namespace 不是完整安全边界 ​

共享集群中常组合:

  • RBAC:谁能操作哪些 API 对象;
  • ResourceQuota:限制 namespace 的总 requests、limits 和对象数量;
  • LimitRange:为单个容器设置默认值和上下界;
  • NetworkPolicy:限制通信;
  • Pod Security Admission:限制高风险 Pod 配置;
  • 独立节点池、配置隔离运行时的 RuntimeClass 或独立集群:处理更强隔离需求。

ResourceQuota 独立于真实集群容量;所有 namespace 的 quota 总和可以超过节点资源,因此它不能替代容量规划。Namespace 也共享控制面和部分节点内核,对不互信租户或严格合规工作负载,应评估更强边界。

生产就绪检查表 ​

text
发布:滚动策略、readiness、优雅终止、回滚与迁移兼容
容量:requests/limits、峰值余量、HPA 指标、节点扩容时延
故障:跨节点/可用区分布、PDB、依赖超时、恢复演练
安全:工作负载身份、RBAC、PSA、NetworkPolicy、镜像签名
存储:PVC 生命周期、快照一致性、RPO/RTO、异地恢复
运维:事件信号、变更审计、controller 状态、证书与密钥轮换

清单的价值不是勾完一次,而是把条件变成 admission policy、CI 检查、持续监控和定期演练。

参考资料 ​

Built with VitePress | Software Systems Atlas