弹性之舞 - 自动伸缩 HPA、VPA 与 Cluster Autoscaler 详解
想象一下经营一家餐厅:如果总是按照最大客流量来配备厨师和服务员(静态资源配置),那么在客人少的时候就会有大量人力闲置浪费。反之,如果人手不足,高峰期客人就会等待过久,体验下降。理想的餐厅经理(自动伸缩机制)应该能根据客流量自动增减人手,甚至在长期爆满时考虑扩建餐厅(增加节点)。
Kubernetes 的自动伸缩就是为了解决类似的资源匹配问题。
1\. Pod 水平自动伸缩:Horizontal Pod Autoscaler (HPA)
- 作用: HPA 根据观察到的指标(最常见的是 CPU 或内存使用率,也可以是自定义指标)自动增加或减少 Deployment、ReplicaSet 或 StatefulSet 中 Pod 的副本数量。
- 工作原理 (简化版):
- HPA 控制器定期从 Metrics Server(针对 CPU/内存)或自定义/外部指标 API 获取目标工作负载下所有 Pod 的指标数据。
- 将当前指标的平均值(或原始值,取决于目标类型)与 HPA 配置中设定的目标值进行比较。
- 根据比较结果,计算出期望的 Pod 副本数量(例如,如果当前 CPU 平均利用率是 80%,目标是 50%,HPA 可能会尝试增加副本数来降低平均利用率)。
- HPA 更新目标工作负载(如 Deployment)的
.spec.replicas
字段。Deployment Controller 接着会调整实际的 Pod 数量。
- 指标来源:
- 资源指标 (Resource Metrics):最常用的是基于 Pod 的平均 CPU 利用率 (
target.type: Utilization
) 或平均内存使用量 (target.type: AverageValue
)。这需要集群中安装 Metrics Server 组件。 - 自定义指标 (Custom Metrics):基于应用程序自身暴露的、更能反映业务负载的指标(例如,每秒处理的队列任务数、每个 Pod 的活跃用户数)。通常需要通过 Prometheus Adapter 或其他自定义指标 API 服务器将这些指标暴露给 HPA。
- 外部指标 (External Metrics):基于集群外部系统的指标(例如,云消息队列中的消息数量、外部负载均衡器的 QPS)。
- 配置示例 (HPA YAML):
apiVersion: autoscaling/v2 # 推荐使用 v2 或 v2beta2,功能更全
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-app-namespace
spec:
scaleTargetRef: # 指向要伸缩的工作负载
apiVersion: apps/v1
kind: Deployment
name: my-app-deployment
minReplicas: 2 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource # 基于资源指标
resource:
name: cpu
target:
type: Utilization # 目标类型为平均利用率
averageUtilization: 70 # 目标平均 CPU 利用率为 70%
# - type: Resource # 也可以基于内存
# resource:
# name: memory
# target:
# type: AverageValue # 目标类型为平均值 (更推荐 Utilization)
# averageValue: 500Mi # 目标平均内存使用量 (注意: 内存伸缩比 CPU 复杂,因为内存是不可压缩资源)
# - type: Pods # 基于 Pod 暴露的自定义指标
# pods:
# metric:
# name: http_requests_per_second # Pod 暴露的自定义指标名
# target:
# type: AverageValue
# averageValue: "100" # 每个 Pod 平均处理 100 QPS
- 关键字段:
scaleTargetRef
(指向目标工作负载),minReplicas
,maxReplicas
,metrics
(列表,可定义多个伸缩指标,HPA 会分别计算并取最大的期望副本数)。 - 效果: 创建 HPA后 (
kubectl apply -f ...
),K8s 会根据负载自动调整my-app-deployment
的副本数。可以通过kubectl get hpa
和kubectl describe hpa my-app-hpa
查看 HPA 的状态、当前副本数、目标值和事件。 - 对 SRE 的意义: HPA 是实现成本优化(低峰期自动缩容)和保障服务性能/可用性(高峰期自动扩容)的关键工具。SRE 需要配置、监控和调优 HPA 的参数。
2\. Pod 垂直自动伸缩:Vertical Pod Autoscaler (VPA)
- 作用: 与 HPA 调整 Pod 数量不同,VPA 专注于自动调整单个 Pod 的资源请求 (
requests
) 和限制 (limits
),主要是 CPU 和内存,使其更接近实际使用量,实现“量体裁衣”。 - 工作原理 (简化版): VPA 通常包含几个组件:
- Recommender: 监控 Pod 的历史资源使用情况,并给出新的 CPU 和内存
requests
的推荐值。 - Updater: 如果 VPA 的
updateMode
设置为自动应用推荐值,当推荐值与当前值差异较大时,Updater 会驱逐 (evict) Pod,以便其控制器(如 Deployment)能够使用新的资源请求值来重建该 Pod。 - Admission Controller: 在新 Pod 创建时(或被 Updater 驱逐重建时),根据 VPA 的推荐值(或配置的策略)修改 Pod 的资源请求。
- 更新模式 (
updateMode
):
"Off"
(或旧版中的"None"
): VPA 只会生成推荐值,不自动应用任何变更。适合初期观察和获取优化建议。"Initial"
: 只在 Pod 创建时设置资源请求,之后不再更改。"Recreate"
(或新版中"Auto"
通常默认行为): VPA 会根据推荐值自动更新 Pod 的资源请求,这通常需要重启 Pod。
- 配置示例 (VPA YAML):
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
namespace: my-app-namespace
spec:
targetRef: # 指向要垂直伸缩的工作负载
apiVersion: "apps/v1"
kind: Deployment
name: my-app-deployment
updatePolicy:
updateMode: "Auto" # 或 "Recreate", "Initial", "Off"
# resourcePolicy: # (可选) 控制 VPA 调整的资源范围和上下限
# containerPolicies:
# - containerName: '*' # 应用于所有容器
# minAllowed:
# cpu: "100m"
# memory: "128Mi"
# maxAllowed:
# cpu: "2"
# memory: "2Gi"
# controlledResources: ["cpu", "memory"] # 控制哪些资源
# controlledValues: RequestsAndLimits # 或 RequestsOnly (更安全)
- 关键字段:
targetRef
(指向目标工作负载),updatePolicy.updateMode
(更新模式),resourcePolicy
(可选,用于限制 VPA 的调整范围,防止推荐值过高或过低)。 - 效果: VPA 会持续监控目标 Pod 的资源使用,并在
kubectl describe vpa my-app-vpa
中给出推荐的requests
值。如果updateMode
是"Auto"
或"Recreate"
,当推荐值与当前值有显著差异时,Pod 会被重启并应用新的资源请求。 - 对 SRE 的意义: VPA 有助于提高资源利用率(避免资源浪费)、减少因资源不足导致的 OOMKilled 或 CPU 节流。重要提示:VPA 和 HPA(如果 HPA 基于 CPU/内存指标)通常不应同时作用于同一个工作负载的相同指标。因为它们一个调整资源请求,一个调整副本数,可能会互相干扰导致不可预测的行为。通常做法是:
- 要么选择 HPA(更常见),要么选择 VPA(如果应用本身不适合水平扩展,或者副本数固定)。
- 或者,VPA 运行在
"Off"
模式(只提供推荐),然后人工参考 VPA 的推荐值来调整 Pod 的requests
和 HPA 的targetAverageUtilization/Value
。 - 较新版本的 HPA (
autoscaling/v2
) 可以配置为使用 VPA 推荐作为其伸缩目标的基础(较高级用法)。
3\. 集群节点自动伸缩:Cluster Autoscaler (CA)
- 作用: 当集群中由于资源不足导致某些 Pod 无法被调度(处于
Pending
状态)时,CA 会自动向云服务商申请创建新的 Node。反之,当某些 Node 长时间处于低负载状态,并且其上运行的 Pod 可以被安全地重新调度到其他 Node 时,CA 会自动缩减这些 Node。 - 工作原理 (简化版):
- CA 监视那些因为资源不足而
Pending
的 Pod。 - 如果 CA 判断通过增加一个新的 Node(从预先配置好的节点组/池中选择实例类型)可以让这些
Pending
Pod 成功调度,它就会向云服务商 API 发起创建 Node 的请求。 - CA 也会监控 Node 的资源利用率。如果一个 Node 长时间(可配置)利用率很低,并且其上所有 Pod 都可以被安全地驱逐并重新调度到其他 Node 上(会检查 PodDisruptionBudget, Affinity/Anti-affinity, PV 亲和性等),CA 就会先“排空 (drain)”该 Node 上的 Pod,然后向云服务商 API 发起删除 Node 的请求。
- 与云服务商强相关: CA 的实现与具体的云平台(AWS, GCP, Azure 等)紧密耦合,因为它需要调用云平台的 API 来增删虚拟机实例。
- 配置: 通常在集群层面进行配置,定义哪些节点池可以被 CA 管理,每个节点池的最小/最大节点数,以及一些伸缩参数。
- 对 SRE 的意义: CA 是实现集群级别成本效益(按需使用节点资源)和容量保障(在负载增加时自动补充节点)的关键。SRE 需要部署、配置和监控 CA 的行为,理解其决策逻辑,并确保 Pod 的调度约束(如 PDB, 亲和性规则)与 CA 的行为兼容,避免不期望的驱逐。
协同工作与注意事项
- HPA + CA: 这是最经典和有效的组合。HPA 负责应用层面的 Pod 副本数伸缩。当 HPA 想要增加 Pod 副本但现有 Node 资源不足时,
Pending
的 Pod 会触发 CA 来增加新的 Node。当 HPA 缩减 Pod 副本导致某些 Node 空闲时,CA 最终会移除这些 Node。 - VPA + CA: 也可以协同工作。VPA 负责优化单个 Pod 的资源请求。如果 VPA 增大了 Pod 的资源请求,导致现有 Node 放不下,
Pending
的 Pod 可能会触发 CA 增加新的 Node(或更大规格的 Node,如果节点池支持)。 - HPA + VPA 的谨慎使用: 如前所述,避免它们直接在 CPU/内存这两个指标上同时对同一个工作负载进行自动调整。
- 调优至关重要: 所有的自动伸缩器都需要仔细调整参数(如目标值、阈值、冷却时间、扫描间隔等),以避免“抖动”(过于频繁地扩缩容)或响应过慢/过快。监控伸缩器的行为和事件是 SRE 的日常工作。
总结
Kubernetes 的自动伸缩三剑客——HPA(Pod 数量)、VPA(Pod 资源)和 Cluster Autoscaler(Node 数量)——为我们提供了强大的自动化能力,以应对动态变化的负载,优化资源利用率和成本,同时保障服务性能。作为 SRE,理解它们各自的职责、工作原理以及它们之间的协同与制约,是构建真正弹性、高效系统的关键。
现在,我们的应用不仅能被智能调度、持久化存储,还能根据负载自动伸缩了。但一个大规模的 K8s 集群本身就是一个复杂的分布式系统,我们如何监控集群自身的状态以及运行在上面的众多应用呢?下一篇,我们将探讨 Kubernetes 集群的监控与日志管理,了解 Metrics Server, kube-state-metrics, cAdvisor 等组件以及常见的日志收集方案。敬请期待!