11.3 Kubernetes 容量治理:调度、扩缩容与中断
Kubernetes 可以把 Pod 放到节点,也可以调整副本数,但它不知道哪种延迟、成本和故障风险对业务可接受。生产容量治理要把 requests、limits、调度约束、HPA、PDB 和租户边界看成一套相互作用的控制系统。
Requests 决定调度,Limits 约束运行
下面是单个容器的 resources 字段片段,应放进 Pod 模板的容器配置中:
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 标签可信且正确,并有三个符合调度条件的可用区:
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-apimaxSkew: 1 限制计数偏差,本身不要求三个可用区;若只有一个合格区,默认条件下三个副本仍可全放那里。示例加上 minDomains: 3:合格域不足三个时按全局最小计数为 0 计算,这会阻止继续向已有域堆副本,也可能让故障后的替代 Pod Pending。hostname 的软约束只影响调度偏好。需要结合各域余量选择分布与故障期间容量的取舍。
Taint/toleration 允许特定 Pod 进入节点,不会保证它一定被调度到那里;需要定向时还要结合 node affinity。不要用用户可随意添加的 label 承载安全隔离,受信任的节点标签必须由受控身份维护。
HPA 的分母来自 Request
CPU utilization 目标大致基于:
当前用量 / CPU request如果容器没有相应 request,HPA 无法正确计算该资源利用率。request 改变也会在真实负载不变时改变 HPA 观察到的百分比。
下面假设同 namespace 已有 atlas-api Deployment,容器都配置了 CPU request,且资源指标 API 可用:
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 只约束自愿中断
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: atlas-api
spec:
minAvailable: 2
selector:
matchLabels:
app: atlas-apiPDB 限制通过 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 也共享控制面和部分节点内核,对不互信租户或严格合规工作负载,应评估更强边界。
生产就绪检查表
发布:滚动策略、readiness、优雅终止、回滚与迁移兼容
容量:requests/limits、峰值余量、HPA 指标、节点扩容时延
故障:跨节点/可用区分布、PDB、依赖超时、恢复演练
安全:工作负载身份、RBAC、PSA、NetworkPolicy、镜像签名
存储:PVC 生命周期、快照一致性、RPO/RTO、异地恢复
运维:事件信号、变更审计、controller 状态、证书与密钥轮换清单的价值不是勾完一次,而是把条件变成 admission policy、CI 检查、持续监控和定期演练。
参考资料
Kubernetes, Resource Management for Pods and Containers
Kubernetes, Horizontal Pod Autoscaling
Kubernetes, Disruptions
Kubernetes, Resource Quotas
Kubernetes, Pod Topology Spread Constraints
Kubernetes, Configuring a PodDisruptionBudget