第 7 章 自动扩缩与资源治理¶
配套实验手册:《Kubernetes 实验手册》(manual/ 目录)实验 05「资源管理和监控」(4 个 Lab:metrics-server/HPA/LimitRange/ResourceQuota)。本章讲两件事:自动扩缩(负载变了,副本数怎么自动跟随)与资源治理(怎么防止资源被滥用)——前者是"弹性"的实现,后者是"秩序"的保障,两者都围绕第 4 章的 requests/limits 展开。
学习目标¶
学完本章,你应该能够:
- 解释指标链路(kubelet → metrics-server → metrics API),知道 HPA 和 kubectl top 的数据来源
- 解释 HPA 的工作原理(控制循环 + 指标 → 期望副本数),说出指标类型与计算公式
- 解释 HPA 的伸缩节奏(稳定窗口/冷却)与 behavior 策略
- 区分三种扩缩(HPA 水平/VPA 垂直/ClusterAutoscaler 节点级)的定位
- 解释资源治理三层防线(requests/limits → LimitRange → ResourceQuota)各自的管辖范围
- 解释 LimitRange 与 ResourceQuota 的拒绝机制(准入控制)
- 说出"没有限制"与"限制过严"的风险,设计合理的资源治理方案
7.1 指标链路:扩缩容的数据基础¶
7.1.1 谁提供"用量数据"¶
第 4 章讲过 requests/limits 是静态声明;但"实际用了多少"需要动态数据——这就是 metrics-server 的角色:
- metrics-server:集群内的指标采集器(kube-system 里的一个 Deployment,实验 01 安装)
- 它从每个节点的 kubelet(cAdvisor) 拉取节点与容器的 CPU/内存用量,聚合后暴露为标准 API
7.1.2 指标链路¶
节点上的容器
│ kubelet 内置 cAdvisor 采集(CPU/内存实际用量)
▼
metrics-server(默认单副本 Deployment,从各节点 kubelet 的 Summary API 拉取)
│ 聚合
▼
metrics.k8s.io API(apiserver 暴露的标准接口)
├─ kubectl top node / top pod(人看)
└─ HPA 控制器(机器用,§7.2)
核心认知:没有 metrics-server,
kubectl top报kubectl top,HPA 也无法工作(指标未知 → 无法决策)。所以实验 05 的 Lab 1 是 HPA 的前提。注意:metrics-server 只提供实时用量(不存历史);历史趋势与告警需要 Prometheus 这类完整监控(第 15 章可观测性展开)。
7.2 HPA:水平自动扩缩¶
7.2.1 原理:又一个控制循环¶
HPA(HorizontalPodAutoscaler) 把第 2 章的控制循环应用在"副本数"上:
flowchart LR
declare["你声明\n目标 CPU 60%\n副本 2-10"] --> read["① 读指标\n(当前利用率)"]
read --> calc["② 计算期望副本\n当前 × 利用率比"]
calc --> cmp{"③ 期望 ≠ 当前?"}
cmp -- "是" --> set["修改 replicas\n(写入 apiserver)"]
set --> rs["④ ReplicaSet 补齐/缩减 Pod"]
rs --> read
cmp -- "否" --> read
style declare fill:#E8F4FD,stroke:#4A90D9
style calc fill:#FFF3E0,stroke:#E08A3C
style set fill:#E8F8E8,stroke:#5BA85B
读图要点:HPA 是控制循环的又一个实例(周期约 15 秒)——读指标 → 算期望副本(当前 × 利用率比)→ 有差异才改 replicas;修改 replicas 只是改期望状态,真正补齐 Pod 的是 ReplicaSet(第 5 章)。
7.2.2 指标类型(autoscaling/v2)¶
| 指标类型 | 含义 | 示例 |
|---|---|---|
| Utilization(利用率) | 实际用量 / requests 的百分比 | CPU 利用率 60%(最常用) |
| AverageValue(平均值) | 每副本的平均绝对用量 | 每副本内存 200Mi |
| Value(总值) | 整个工作负载的总量 | 总请求数 |
| 自定义/外部指标 | Prometheus 等来源(需适配器) | QPS、队列长度(进阶) |
注意 Utilization 的分母是 requests(不是节点容量)——所以 HPA 的准确性依赖 requests 设置合理(第 4 章资源模型的意义又一处体现)。
7.2.3 伸缩节奏:为什么不会"抖"?¶
指标是波动的——如果利用率在 59%/61% 间跳,副本数会不停增减(抖动)。HPA 用稳定窗口平滑:
- scaleUp 稳定窗口(默认 0 秒,可配置如 60s):利用率持续超目标这么久才扩容
- scaleDown 稳定窗口(默认 5 分钟):利用率持续低于目标这么久才缩容——缩容比扩容谨慎(扩错了最多多花钱,缩错了会扛不住流量)
7.2.4 behavior:精细控制伸缩¶
behavior:
scaleUp:
stabilizationWindowSeconds: 60 # 扩容稳定窗口
policies:
- type: Percent
value: 100 # 一次最多翻倍
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300 # 缩容稳定窗口(默认 5 分钟)
policies:
- type: Percent
value: 50 # 一次最多缩一半
生产要点:默认行为(5 分钟缩容稳定窗口)通常够用;关键业务可收紧 scaleUp 窗口(更快扩容)、拉长 scaleDown 窗口(更稳的缩容)。
7.2.5 局限与注意¶
- 指标延迟:metrics-server 采集有延迟(~15s),HPA 决策滞后于流量变化——突发流量场景要预留余量(目标利用率别设 90%,留 60-70%)
- 最小/最大副本:
minReplicas保底(应对冷启动)、minReplicas封顶(防失控) - 与手动 scale 的关系:手动
kubectl scale会被 HPA 覆盖(HPA 是权威)——要么手动、要么 HPA,不要混用(调整 HPA 的 min/max 而不是手动 scale) - 与第 4 章资源模型的关系:HPA 只认 requests——Pod 没配 requests,HPA 的 CPU 利用率指标不可用
7.3 垂直扩缩与集群扩缩:另外两个维度¶
HPA 只是"水平"(加副本)。还有两个扩缩维度:
7.3.1 VPA(Vertical Pod Autoscaler):调 requests 而不是副本数¶
- 原理:根据历史用量自动调整 Pod 的 requests/limits(而不是副本数)
- 为什么需要:应用实际需求会变(内存泄漏前的膨胀、业务高峰)——人工调 requests 很烦
- 机制:VPA 建议 → 修改 Deployment 模板 → 滚动更新(需要重建 Pod 生效,因为是模板变化)
- 注意:VPA 与 HPA 在 CPU/内存指标上不能同时用(会打架)——生产常用"VPA 调 requests + HPA 管副本"
⭐ In-place Pod Resource Updates(v1.27+):Kubernetes 原生支持不重启 Pod 原地更新部分资源字段(
spec.containers[].resources的 Requests/Limits)——改变了 VPA 必须"重建 Pod"的运作模式。开启该特性后,VPA 或手动spec.containers[].resources修改资源可以原地生效(对重启敏感的有状态服务意义重大)。v1.36 已支持(部分字段需要 Pod 不在 QoS 突变范围)。
7.3.2 ClusterAutoscaler(CA):节点级扩缩¶
- 原理:集群资源不足时自动增减节点(云环境,调用云厂商 API)
- 为什么需要:Pod 挤满所有节点(调度过滤失败 Pending)→ 加节点;节点长期空闲 → 减节点
- 注意:需要云环境(裸机集群无法自动加机器);与 HPA 配合形成"应用级 + 节点级"双层弹性
7.3.3 三种扩缩的定位¶
| 维度 | 调整什么 | 生效方式 | 适用 |
|---|---|---|---|
| HPA(水平) | 副本数 | 立即(改 replicas) | 无状态应用,最常用 |
| VPA(垂直) | requests/limits | 需重建 Pod(v1.27+ 可原地) | 有状态/不好水平扩展的应用 |
| ClusterAutoscaler(节点级) | 节点数 | 分钟级(云 API) | 集群容量不足时 |
决策逻辑:默认 HPA(无状态应用的水平扩展是首选);副本数不能随便加(有状态/单实例)→ VPA;节点容量瓶颈 → ClusterAutoscaler。三者可以组合(生产标准组合:HPA + CA)。
7.3.4 KEDA:事件驱动自动扩缩(进阶)¶
HPA 的局限:只认 CPU/内存(或需额外适配器接自定义指标)。生产中常见"消息队列堆积量触发扩容"(RabbitMQ/Kafka 积压 1 万条 → 加消费者)——这是 KEDA(Kubernetes Event-driven Autoscaling) 的场景:
- KEDA 内置 70+ Scaler(Kafka/RabbitMQ/Redis/HTTP 等),直接读外部系统指标
- 以"自定义指标源"形式接入 HPA(KEDA 负责把外部指标变成 HPA 能用的指标)
- 使用:安装 KEDA → 创建
ScaledObject(声明"队列长度 > N 时扩到 M 个")
决策逻辑:标准 CPU/内存 → HPA 原生;外部系统事件(队列/吞吐)驱动 → KEDA(事件驱动弹性,Serverless 化工作负载的方向)。
7.4 资源治理三层防线¶
资源治理回答:"怎么防止某个 Pod/命名空间把集群资源吃光?"——三层防线,层层递进(第 4 章 requests/limits 是地基)。
7.4.1 第一层:requests/limits(Pod 自己声明)¶
- 每容器声明"要多少/最多用多少"(实验 02 Lab 10)
- 问题:靠自觉——Pod 不写就没有;写小了(requests)节点可能超卖;写大了浪费
7.4.2 第二层:LimitRange(命名空间内约束"单个 Pod")¶
LimitRange 在命名空间级别给"单个对象"设默认值与上下限:
命名空间 dev 的 LimitRange:
- 每个 Pod 的 requests 必须在 50m~2 核、内存 32Mi~1Gi
- Pod 没写 requests/limits → 自动填默认值(default/defaultRequest)
三个动作(准入控制实现,第 12 章展开):
- 校验:Pod 声明超出范围 → 创建被拒(
Forbidden) - 填充:Pod 没声明 → 自动补默认值(防止"裸奔"Pod——这是最重要的一条)
- 约束:统一命名空间的资源声明口径
kubectl -n dev apply -f lr-pod.yaml(requests 4 核 > 上限 2 核)
Error from server (Forbidden): ... maximum cpu usage per Pod is 2, but request is 4
核心认知:LimitRange 解决"单个 Pod 不守规矩"——要么超限被拒,要么没写被填默认。
7.4.3 第三层:ResourceQuota(命名空间内约束"总量")¶
ResourceQuota 约束整个命名空间的累计用量——所有 Pod 的 requests/limits 加起来不能超过配额:
命名空间 dev 的 ResourceQuota:
requests.cpu: 10 核、requests.memory: 20Gi
limits.cpu: 20 核、limits.memory: 40Gi
pods: 100、services: 50、pvc: 20 ...
- 超过配额 → 新对象创建被拒(
exceeded quota) - 资源释放后自动恢复(删掉占用后又能建)
- 还能配额对象数量(pods/services/pvc 等)——防止命名空间资源无限膨胀
kubectl -n dev apply -f new-pod.yaml
Error from server (Forbidden): exceeded quota: dev-quota, requested: requests.cpu=500m, used: requests.cpu=9.7, limited: requests.cpu=10
排障关联:创建 Pod 报
exceeded quota(实验 10 Lab 1)→exceeded quota看 Used/Hard——报错直说超了哪个配额。
7.4.4 三层协作与设计建议¶
flowchart TD
subgraph NS["命名空间"]
L1["第一层:Requests/Limits\n(Pod 声明,自觉)"]
L2["第二层:LimitRange\n(单 Pod 上下限 + 默认值,强制)"]
L3["第三层:ResourceQuota\n(命名空间总量,防膨胀)"]
L1 --> L2
L2 --> L3
end
style NS fill:#F5F5F5,stroke:#666666
style L1 fill:#E8F4FD,stroke:#4A90D9
style L2 fill:#FFF3E0,stroke:#E08A3C
style L3 fill:#FDECEA,stroke:#D94F4F
读图要点:三层是"递进约束"——Requests/Limits 是 Pod 自觉声明(不写就没人管);LimitRange 在命名空间内强制单 Pod 的默认值与上下限;ResourceQuota 兜底命名空间总量——后两层都在准入控制执行(第 12 章)。
设计建议(生产视角):
- 每个生产命名空间都配 ResourceQuota(总量兜底)
- 配 LimitRange 的
default(强制每个 Pod 都有 requests——HPA 依赖它、调度依赖它) - 测试命名空间配额可以小(倒逼省资源);生产按业务量评估
- 记住拒绝机制都在准入控制(创建时拦截,第 12 章展开原理)
7.4.5 设计指南:多租户治理体系¶
多团队/多业务共用一个集群时,"怎么隔离 + 怎么分资源"是核心治理问题——与第 11 章 RBAC 联动,构成完整的多租户体系。
命名空间规划模型(按组织规模选):
模型一:按环境划分(小团队) dev / staging / production
模型二:按团队×环境(中型组织) team-order-dev / team-payment-prod
模型三:按业务域划分(大型组织) domain-trade / domain-payment
域内按微服务部署,跨域用 NetworkPolicy 隔离(第 9 章)
多租户隔离四层模型(层层加固):
| 层级 | 机制 | 隔离强度 | 适用 |
|---|---|---|---|
| L1 逻辑隔离 | Namespace + RBAC(第 11 章) | ⭐⭐ | 同信任域内团队 |
| L2 资源隔离 | ResourceQuota + LimitRange(本章) | ⭐⭐⭐ | 防 Noisy Neighbor(吵闹邻居) |
| L3 网络隔离 | NetworkPolicy(第 9 章) | ⭐⭐⭐⭐ | 跨团队安全边界 |
| L4 节点隔离 | Taint/Toleration + 专用节点池(第 6 章) | ⭐⭐⭐⭐⭐ | 合规/安全敏感负载 |
资源超卖策略(配额与 requests 的设计):
测试环境:超卖比 200-300%(requests 低、limits 高,允许争抢)
生产环境:超卖比 120-150%(requests 接近实际用量)
核心服务:超卖比 100%(Guaranteed QoS,requests = limits,零争抢)
监控指标:节点实际利用率 / requests 总和 = 实际超卖比,> 85% 触发扩容
决策逻辑:先定租户模型(命名空间规划)→ 再定隔离级别(四层按需)→ 最后定超卖策略(配额/requests 比例)——多租户治理 = "逻辑划分 + 资源约束 + 网络边界"三件套。
7.5 实验演练指引¶
本章机制对应实验 05「资源管理和监控」(4 个 Lab):
- Lab 1 安装 metrics-server:指标链路的数据源——
kubectl top node/pod有数(requests/limits 基础在实验 02 Lab 10) - Lab 2 启用 HPA:autoscaling/v2 配置 CPU/内存指标,压测观察副本自动增减
- Lab 3 LimitRange:
min/max/default/defaultRequest——超限 Forbidden、缺省自动填充 - Lab 4 ResourceQuota:
hard配额 +hard观察——超配额拒绝、释放恢复
教学建议:Lab 1 是 HPA 的前提(无指标无决策);Lab 3/4 对比记忆——LimitRange 管单个、ResourceQuota 管总量。
本章小结¶
- 指标链路:kubelet(cAdvisor)→ metrics-server → metrics API → kubectl top / HPA——没 metrics-server 就没有 HPA
- HPA:控制循环 + 指标 → 期望副本数(当前 × 利用率比);Utilization 的分母是 requests;稳定窗口防抖动(缩容默认 5 分钟)
- 三种扩缩:HPA 水平(加副本,首选)/ VPA 垂直(调 requests,需重建)/ CA 节点级(云环境加机器)——生产组合 HPA + CA
- 三层防线:requests/limits(自觉)→ LimitRange(单 Pod 默认值/上下限,强制有 requests)→ ResourceQuota(命名空间总量);拒绝都在准入控制(Forbidden/exceeded quota)
- HPA 与资源模型联动:requests 设得准 → 调度准、HPA 准、配额准
衔接:第 8 章讲配置管理(ConfigMap/Secret)——应用"运行参数"的外部化;资源治理管"用多少",配置管理管"怎么配"。
思考题¶
- 没有 metrics-server 时,HPA 会怎样?kubectl top 会怎样?
- HPA 计算期望副本数时,为什么"当前利用率/目标利用率"用乘法?(提示:比例关系)
- 为什么缩容稳定窗口默认比扩容长?极端情况下把两个窗口都设 0 会怎样?
- 某 Pod 没配 requests,HPA 的 CPU 利用率指标为什么不可用?
- LimitRange 与 ResourceQuota 的管辖范围分别是什么?"exceeded quota" 和 "Forbidden: maximum cpu" 分别来自哪层?
- 为什么生产建议给每个命名空间配 LimitRange 的 default?(提示:HPA/调度/配额都依赖 requests)
CKA 考点标注(对应域 2/5): - 必考操作:
kubectl autoscale deployment xxx --cpu=50% --min=2 --max=10(v1.36 语法,旧kubectl autoscale deployment xxx --cpu=50% --min=2 --max=10已弃用)、kubectl autoscale deployment xxx --cpu=50% --min=2 --max=10、kubectl autoscale deployment xxx --cpu=50% --min=2 --max=10- 必考机制:HPA 计算公式与稳定窗口、LimitRange(default/min/max/Forbidden)、ResourceQuota(hard/Used/exceeded quota) - 高频场景题:给定资源策略需求 → 配置 LimitRange/ResourceQuota/HPA - 排障关联(域 5):exceeded quota、exceeded quota、HPA 副本不动的排查