摘要
Pod 能否稳定运行,不只取决于副本数,也取决于 CPU 和内存请求、限制是否符合真实负载。Kubernetes 调度器依据 requests 放置 Pod,容器运行时依据 limits 约束资源;Horizontal Pod Autoscaler(HPA)则结合指标调整工作负载副本数。
从一个可运行的 CPU 扩缩容示例开始,理解 requests、limits、QoS、Metrics Server 和 HPA 的关系,再学习如何避免 CPU 节流、内存 OOM、扩容抖动和节点容量不足。扩缩容配置最终要由压测、监控和容量预算共同校准,不能只复制一组看似合理的数值。
一、背景与问题
资源请求设置过低,调度器可能把过多 Pod 放在同一节点,实际负载上来后发生 CPU 争抢或内存驱逐;设置过高,则会让节点看起来没有足够容量,Pod 长期 Pending,集群资源利用率也会下降。没有 CPU request 时,基于 CPU 利用率的 HPA 甚至无法正确计算目标利用率。
只给 Deployment 增加副本数也不一定能提高吞吐。如果每个副本都因 CPU limit 受到严重节流,扩容可能增加等待和成本,却不能按比例增加处理能力。如果瓶颈在数据库连接池、下游限流、队列消费速度或单实例锁竞争,单纯增加 Pod 还可能放大依赖压力。
资源治理要同时回答三个问题:单个 Pod 需要多少资源、工作负载应该运行多少副本、集群是否有能力承载这些副本。requests 和 limits 控制单 Pod 的资源边界,HPA 调整 Pod 数量,Cluster Autoscaler 等节点扩缩容组件则处理节点容量;它们相互配合,但不是同一个控制器。
二、核心概念
1. CPU 与内存 requests
resources.requests 是调度器为容器计算资源需求时使用的值。CPU request 以核为单位,100m 表示 0.1 个 CPU 核;内存常用 Mi、Gi 表示。requests 不是进程的硬上限,容器在节点有空闲资源时可能使用超过 request 的资源。
节点可分配资源会被 Pod 的 requests 逐步占用。即使 kubectl top 显示当前 CPU 用量很低,只要 request 已占满可分配容量,新 Pod 也可能无法调度。容量规划应看节点 Allocatable、已有工作负载 requests、系统预留和扩容峰值,而不是只看瞬时使用率。
2. CPU 与内存 limits
CPU limit 是可使用的 CPU 上限,超出后容器会被 CFS 配额节流。它通常不会像内存 limit 那样立即终止容器,但持续节流会增加排队和尾延迟。内存 limit 是硬边界,容器超出后可能被内核 OOM Killer 终止,Pod 状态中常见 OOMKilled。
CPU 和内存的取舍不同。CPU 使用可以被调度和节流;内存无法通过同样方式安全地无限超用。不要把 CPU limit 与内存 limit 当作完全对称的开关。高延迟服务需要在节点保护、CPU 节流和业务 SLO 之间验证取舍;内存 limit 则应结合峰值、运行时开销和 OOM 风险评估。
3. QoS Class
Kubernetes 根据 Pod 中容器的 requests 和 limits 将 Pod 分为 Guaranteed、Burstable 或 BestEffort。当所有容器都为 CPU、内存设置了 requests 和 limits,且每项 request 等于对应 limit 时,Pod 才满足 Guaranteed 条件;只要有容器未设置资源值,或 request 与 limit 不相等,通常属于 Burstable;所有容器都没有 requests 和 limits 时属于 BestEffort。
QoS Class 会影响节点内存压力下的驱逐优先级,但不是资源隔离的替代品。给一个关键服务设置 Guaranteed 也不代表节点上一定有足够容量,更不代表服务的延迟和吞吐已满足要求。
4. HPA 与资源利用率
HPA 根据 CPU、内存、自定义或外部指标调整 Deployment、StatefulSet 等可伸缩目标的副本数。CPU averageUtilization: 50 表示目标 Pod 平均 CPU 使用量约为其 CPU request 的 50%,不是节点 CPU 总使用率的 50%。没有合适的 CPU request,利用率百分比就失去可靠分母。
HPA 读取资源指标通常需要 Metrics Server。kubectl top pods 能返回近似实时的 CPU 和内存使用量时,说明基本资源指标链路可用;Prometheus 通常用于长期监控和自定义指标,不会自动替代 Kubernetes Resource Metrics API。
5. HPA 与节点自动扩缩容
HPA 增加的是 Pod 副本。如果新 Pod 因节点资源不足而 Pending,只有已安装并配置 Cluster Autoscaler 或云厂商节点自动扩缩容能力时,节点池才可能进一步增加容量。HPA 不会自动创建节点;节点扩容也需要时间,必须把镜像拉取、调度和应用启动时延纳入容量设计。
三、工作原理
对一个资源指标,HPA 会比较当前观测值与目标值,按比例估算期望副本数。CPU 利用率场景的简化关系是:
期望副本数 ≈ ceil(当前副本数 × 当前平均 CPU 利用率 ÷ 目标 CPU 利用率)
例如:
当前副本数 = 2
当前平均 CPU 利用率 = 100%
目标 CPU 利用率 = 50%
期望副本数 ≈ ceil(2 × 100 ÷ 50) = 4
实际控制器还会处理指标误差、缺失指标、容忍区间、最小和最大副本数、冷却与速率策略,因此结果不一定严格等于简化公式。HPA 周期性读取指标并调整 scale 子资源;Deployment Controller 随后创建或删除 ReplicaSet 中的 Pod。
一次自动扩容链路如下:
容器运行并产生 CPU/内存使用量
│
▼
Metrics Server 从节点采集资源指标
│
▼
HPA 计算当前值与目标值的差距
│
┌─────┴─────┐
│ │
低于目标值 高于目标值
│ │
保持或缩容 提高期望副本数
│
▼
Deployment 创建新 Pod
│
▼
Scheduler 放置并等待 Pod Ready
缩容往往比扩容更谨慎。流量短时回落后立即删除副本,下一波流量又触发扩容,会造成抖动。HPA 的 behavior 可设置扩容速度和缩容稳定窗口,但窗口不能修复错误的 requests、应用冷启动慢或容量不足。
四、实战示例
下面的示例需要练习 Kubernetes 集群、kubectl 和可用的 Metrics Server。先确认当前上下文确实是练习集群;没有 Resource Metrics API 时,HPA 会显示指标获取错误,不能仅靠创建 HPA 对象判断扩缩容已经可用。
1. 创建带资源请求的示例服务
保存为 resource-hpa-demo.yaml。示例镜像用于演示 CPU 自动扩缩容;生产环境应固定并验证镜像版本或 digest,并为真实服务配置符合其行为的探针和安全上下文。
apiVersion: v1
kind: Namespace
metadata:
name: capacity-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
namespace: capacity-demo
spec:
replicas: 1
selector:
matchLabels:
app: php-apache
template:
metadata:
labels:
app: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- name: http
containerPort: 80
resources:
requests:
cpu: 200m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
namespace: capacity-demo
spec:
selector:
app: php-apache
ports:
- name: http
port: 80
targetPort: http
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: capacity-demo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
scaleUp:
stabilizationWindowSeconds: 0
selectPolicy: Max
policies:
- type: Percent
value: 100
periodSeconds: 60
- type: Pods
value: 4
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
2. 检查资源指标与 HPA
应用清单前先检查上下文和 Metrics Server:
kubectl config current-context
kubectl top nodes
kubectl apply -f resource-hpa-demo.yaml
kubectl -n capacity-demo get deployment,pods,service,hpa
kubectl -n capacity-demo top pods
kubectl -n capacity-demo describe hpa php-apache
HPA 的 TARGETS 初始可能显示 <unknown>/50%,刚启动时也可能需要等待指标采集。检查 HPA Events、Metrics API 和 Pod 是否 Ready。若 kubectl top 不可用,先按集群发行版文档安装或修复 Metrics Server;不要通过修改 HPA 数字掩盖监控链路缺失。
3. 产生负载并观察扩容
在终端启动持续请求的负载 Pod。命令创建 Pod 后会返回,但容器中的循环会继续运行:
kubectl run load-generator -n capacity-demo --image=busybox:1.36 --restart=Never -- /bin/sh -c "while true; do wget -q -O- http://php-apache; done"
观察 HPA 和 Pod 数量变化;-w 会持续占用当前终端,按 Ctrl+C 退出观察后再运行下一条命令,或在不同终端分别执行:
kubectl -n capacity-demo get hpa -w
kubectl -n capacity-demo get pods -w
也可以在负载运行期间查看指标和事件:
kubectl -n capacity-demo top pods
kubectl -n capacity-demo describe hpa php-apache
kubectl -n capacity-demo get events --sort-by=.lastTimestamp
扩容不是即时动作。Metrics Server 采样、HPA 计算、调度、镜像拉取和应用启动都会产生时延;Pod 可能在节点不足时 Pending。完成观察后,删除负载 Pod 才能停止容器中的请求循环:
kubectl -n capacity-demo delete pod load-generator --ignore-not-found
缩容会受到 300 秒稳定窗口影响。等副本回落后清理练习 Namespace:
kubectl delete namespace capacity-demo
不要在生产集群执行这个清理命令;Namespace 删除会清除其中全部练习资源。
五、常见问题与实践建议
1. HPA 创建成功,但 TARGETS 是 <unknown>
HPA 对象被 API Server 接受,不代表指标链路可用。确认 Metrics Server 已安装且能访问 kubelet,执行 kubectl top pods 检查资源指标,再检查 HPA Events 和 API Service 状态。CPU 利用率目标还要求目标 Pod 的容器正确声明 CPU request。
2. Pod 一直 Pending,HPA 却继续增加副本
HPA 负责调整副本数,不负责创造节点容量。查看 Pod Events 中的 Insufficient cpu、Insufficient memory、配额和调度约束信息,核算节点可分配资源与所有副本 requests。需要自动增加节点时,另行部署并配置节点自动扩缩容组件。
3. CPU 使用不高,接口延迟却很高
CPU 利用率只是一个信号。延迟也可能来自线程池耗尽、数据库等待、锁竞争、网络重试或下游限流。结合请求速率、错误率、P95/P99 延迟、队列长度和依赖服务指标诊断,不要仅凭 CPU 指标扩容。
4. CPU limit 导致节流
检查容器 CPU throttling 指标和延迟趋势,确认 limit 是否低于负载峰值所需。盲目调高 limit 会影响节点共享,也可能把过载推给下游;应在压测环境中测试 requests、limits、并发数和尾延迟的关系。
5. 内存不断增长并触发 OOMKilled
检查 kubectl describe pod、重启次数和应用堆、缓存、工作集指标。内存 request 影响调度,limit 触发硬约束;如果是内存泄漏,单纯提高 limit 只能推迟故障。还要把 JVM 堆外内存、线程栈、直接内存和容器总内存预算一起计算。
6. HPA 扩容和缩容频繁
设置合理的缩容稳定窗口和扩缩容速率策略,减少瞬时指标波动的影响。扩大窗口会增加资源保留时间,缩短窗口则可能增加抖动;应结合流量峰值长度、冷启动时延和成本目标选择,而不是照搬示例参数。
7. 副本增加后,下游数据库先过载
为连接池、并发请求和队列消费者设置总量预算。最大副本数乘以每个 Pod 的最大连接数必须在数据库容量内;必要时采用队列削峰、并发限制、缓存或下游隔离。HPA 的 maxReplicas 是保护依赖的一部分,不只是成本上限。
六、进阶思考
CPU 和内存利用率未必是业务最合适的扩缩容信号。异步消费者可以按队列积压或最老消息等待时间扩容;HTTP 服务可以评估并发请求数或每副本请求速率。自定义和外部指标需要 Prometheus Adapter、KEDA 等指标适配组件,且要确认指标延迟、缺失值和权限配置。
HPA 与 VPA 同时作用于同一工作负载时要规划字段所有权。HPA 根据 CPU 利用率而 VPA 又不断调整 CPU requests,可能改变利用率分母并导致扩缩容行为变化。可以让 VPA 先在推荐模式收集建议,再经压测和变更评审更新 requests;不要未经设计就让多个控制器竞争同一资源字段。
发布期间也要纳入容量约束。滚动发布的 maxSurge 会短时增加 Pod 数量;每个新 Pod 都计入资源需求。PDB 保护自愿中断时的可用副本数,不会替代 HPA,也不能解决节点无容量的问题。需要把扩容峰值、升级 surge、节点维护和故障冗余一起放入容量模型。
结论
requests 决定调度与资源利用率基准,limits 限制容器可使用资源,HPA 根据指标调整 Pod 副本数,而节点自动扩缩容负责增加或减少集群容量。只有把这些层次和应用瓶颈分开分析,资源配置才不会沦为试错数字。
从可观测的 requests 与 limits 开始,用 Metrics Server 确认资源指标链路,再在练习集群验证 HPA 的扩容、稳定缩容和 Pending 场景。生产配置还要通过压测校准、限制下游并发、预算升级 surge,并用服务级 SLO 评估扩缩容效果。
参考资料
- Kubernetes 文档:容器资源管理
- Kubernetes 文档:Horizontal Pod Autoscaling
- Kubernetes 文档:HPA 任务示例
- Kubernetes 文档:Metrics Server 与资源指标管道
- Metrics Server 项目
- Kubernetes 文档:节点自动扩缩容
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/m0_62221377/article/details/170777707




