跳到主要内容

自动扩缩容

自动扩缩容是 Kubernetes 最重要的特性之一,它让集群能够根据负载自动调整资源,既保证了应用的可用性,又避免了资源浪费。Kubernetes 提供了多种自动扩缩容机制,本章将详细介绍水平 Pod 自动扩缩容(HPA)、垂直 Pod 自动扩缩容(VPA)以及它们的使用方法。

扩缩容的基本概念

在深入了解具体技术之前,我们需要理解两种基本的扩缩容方式。

水平扩缩容 vs 垂直扩缩容

水平扩缩容(Horizontal Scaling)意味着增加或减少 Pod 的副本数量。当负载增加时,启动更多的 Pod 来分担压力;当负载减少时,关闭多余的 Pod 节省资源。这就像是餐厅在繁忙时段增加服务员数量。

垂直扩缩容(Vertical Scaling)意味着调整单个 Pod 的资源配置,比如增加 CPU 或内存的请求量和限制量。这就像是给现有的服务员分配更大的工作区域。

两种方式各有优缺点:

方式优点缺点适用场景
水平扩缩容无需重启,响应快,适合无状态应用需要应用支持多副本Web 服务、API 服务
垂直扩缩容不增加复杂度,适合单实例应用需要重启 Pod,调整范围有限数据库、有状态应用

水平 Pod 自动扩缩容(HPA)

HorizontalPodAutoscaler(HPA)是 Kubernetes 内置的水平扩缩容控制器,它根据观测到的 CPU 利用率、内存使用量或自定义指标自动调整 Pod 副本数。

HPA 的工作原理

HPA 的核心是一个控制循环,定期检查目标工作负载的指标,然后计算期望的副本数。整个过程可以概括为以下几个步骤:

  1. 指标采集:HPA 控制器通过 Metrics API 获取当前指标值
  2. 计算期望副本数:根据当前指标值和目标值计算期望副本数
  3. 调整副本数:更新工作负载的 replicas 字段

计算公式如下:

desiredReplicas=currentReplicas×currentMetricValuedesiredMetricValue\text{desiredReplicas} = \lceil \text{currentReplicas} \times \frac{\text{currentMetricValue}}{\text{desiredMetricValue}} \rceil

例如,当前有 4 个副本,CPU 利用率为 80%,目标利用率为 40%:

desiredReplicas=4×8040=8\text{desiredReplicas} = \lceil 4 \times \frac{80}{40} \rceil = 8

前提条件

使用 HPA 需要安装 Metrics Server,它负责收集 Pod 和节点的资源使用指标。

# 安装 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 验证安装
kubectl get deployment metrics-server -n kube-system
kubectl get pods -n kube-system -l k8s-app=metrics-server

# 测试指标采集
kubectl top nodes
kubectl top pods

如果 Metrics Server 正常工作,kubectl top 命令会显示节点和 Pod 的资源使用情况。

创建 HPA

命令行方式

最简单的方式是使用 kubectl autoscale 命令:

# 为 Deployment 创建 HPA
kubectl autoscale deployment my-app --cpu-percent=50 --min=2 --max=10

# 查看创建的 HPA
kubectl get hpa

这条命令创建了一个 HPA,它会保持 my-app 的 CPU 利用率在 50% 左右,副本数在 2 到 10 之间。

YAML 方式

更推荐使用 YAML 文件定义 HPA,便于版本控制和复用:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50

基于多种指标的扩缩容

HPA 支持同时使用多种指标,取计算结果的最大值:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
# CPU 利用率
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
# 内存利用率
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70

当多个指标同时配置时,HPA 会为每个指标计算期望副本数,然后选择最大的那个值。这样保证了任何一个指标超标都能触发扩容。

自定义指标扩缩容

除了 CPU 和内存,HPA 还支持自定义指标,比如请求速率、队列长度等。这需要安装 Prometheus Adapter 来暴露自定义指标。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
# 使用 Pods 类型的自定义指标
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000

这个例子中,当每个 Pod 的 HTTP 请求速率超过 1000 次/秒时,就会触发扩容。

扩缩容行为配置

Kubernetes 允许精细控制扩缩容的行为,避免副本数剧烈波动:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
# 缩容行为
scaleDown:
stabilizationWindowSeconds: 300 # 稳定窗口 5 分钟
policies:
- type: Percent
value: 10 # 每次最多缩容 10%
periodSeconds: 60
- type: Pods
value: 2 # 每次最多缩容 2 个 Pod
periodSeconds: 60
selectPolicy: Min # 选择限制最严格的策略
# 扩容行为
scaleUp:
stabilizationWindowSeconds: 0 # 无稳定窗口,立即扩容
policies:
- type: Percent
value: 100 # 可以翻倍扩容
periodSeconds: 15
- type: Pods
value: 4 # 每次最多扩容 4 个 Pod
periodSeconds: 15
selectPolicy: Max # 选择允许最大扩容的策略

配置说明

  • stabilizationWindowSeconds:稳定窗口期,在此期间内即使指标满足条件也不会执行扩缩容,防止震荡
  • policies:扩缩容策略列表,可以定义多个策略
  • selectPolicy:策略选择方式
    • Max:选择允许最大变化的策略(默认)
    • Min:选择允许最小变化的策略
    • Disabled:禁用该方向的扩缩容

容器级别的资源指标

从 Kubernetes 1.30 开始,HPA 支持容器级别的资源指标,可以针对 Pod 中的特定容器进行扩缩容:

metrics:
- type: ContainerResource
containerResource:
name: cpu
container: application # 指定容器名称
target:
type: Utilization
averageUtilization: 60

这对于包含 sidecar 容器的 Pod 特别有用,可以根据主要应用的资源使用情况扩缩容,忽略 sidecar 的影响。

查看 HPA 状态

# 查看 HPA 列表
kubectl get hpa

# 查看详细信息
kubectl describe hpa my-app-hpa

# 查看扩缩容事件
kubectl get events --field-selector reason=SuccessfulRescale

kubectl get hpa 的输出示例:

NAME          REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
my-app-hpa Deployment/my-app 45%/50% 2 10 4 10m

常见问题排查

HPA 无法获取指标

# 检查 Metrics Server 是否正常运行
kubectl get deployment metrics-server -n kube-system
kubectl get pods -n kube-system -l k8s-app=metrics-server

# 检查 Metrics Server 日志
kubectl logs -n kube-system deployment/metrics-server

Pod 没有设置资源请求

HPA 需要知道 Pod 的资源请求才能计算利用率。如果 Pod 没有设置 resources.requests,HPA 无法工作:

# 确保 Pod 定义中包含资源请求
resources:
requests:
cpu: 100m
memory: 128Mi

扩缩容过于频繁

调整稳定窗口期和扩缩容策略:

behavior:
scaleDown:
stabilizationWindowSeconds: 600 # 增加稳定窗口
scaleUp:
stabilizationWindowSeconds: 60

垂直 Pod 自动扩缩容(VPA)

VerticalPodAutoscaler(VPA)自动调整 Pod 的 CPU 和内存请求,确保应用获得足够的资源而不浪费。与 HPA 不同,VPA 不是 Kubernetes 内置功能,需要单独安装。

VPA 的工作原理

VPA 由三个组件组成:

  1. Recommender:监控历史资源使用情况,生成资源推荐
  2. Updater:检查 Pod 是否需要更新,驱逐需要更新的 Pod
  3. Admission Controller:在 Pod 创建时注入推荐的资源请求

安装 VPA

# 下载 VPA
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler

# 安装 VPA(需要 kubectl 连接到集群)
./hack/vpa-up.sh

# 验证安装
kubectl get deployment -n kube-system | grep vpa

VPA 更新模式

VPA 支持四种更新模式:

模式说明行为
Off推荐只生成推荐,不自动更新
Initial仅在创建时更新新 Pod 使用推荐值,现有 Pod 不变
Recreate重建更新驱逐现有 Pod,新 Pod 使用推荐值
Auto自动目前等同于 Recreate 模式

创建 VPA

推荐模式(Off)

先使用 Off 模式观察推荐值:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # 只生成推荐
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 4Gi
controlledResources: ["cpu", "memory"]

查看推荐值:

kubectl describe vpa my-app-vpa

输出示例:

Recommendation:
Container Recommendations:
Container Name: app
Lower Bound:
Cpu: 100m
Memory: 256Mi
Target:
Cpu: 250m # 推荐的 CPU 请求
Memory: 512Mi # 推荐的内存请求
Uncapped Target:
Cpu: 250m
Memory: 512Mi
Upper Bound:
Cpu: 500m
Memory: 1Gi

自动更新模式

确认推荐值合理后,切换到 Auto 模式:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 4Gi

资源边界控制

VPA 允许设置资源的最小和最大边界,防止资源设置过低或过高:

resourcePolicy:
containerPolicies:
- containerName: app
mode: Auto
minAllowed:
cpu: 100m
memory: 256Mi
maxAllowed:
cpu: 4
memory: 8Gi
# 设置资源边界为推荐值的百分比
minReplicas: 1
maxReplicas: 100

HPA 与 VPA 的配合使用

HPA 和 VPA 可以配合使用,但需要谨慎配置以避免冲突。

配合原则

  1. 不要对同一资源同时启用 HPA 和 VPA 的 CPU 扩缩容
  2. HPA 负责副本数,VPA 负责单个 Pod 的资源配置
  3. HPA 使用自定义指标或内存指标,VPA 负责 CPU

推荐配置

# VPA 配置 - 管理资源配置
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Initial" # 只在创建时更新
resourcePolicy:
containerPolicies:
- containerName: "*"
controlledResources: ["cpu"] # VPA 只管理 CPU
---
# HPA 配置 - 管理副本数
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: memory # HPA 使用内存指标
target:
type: Utilization
averageUtilization: 70

集群自动扩缩容(Cluster Autoscaler)

当 Pod 因资源不足无法调度时,Cluster Autoscaler 可以自动添加节点;当节点长时间闲置时,可以自动删除节点。

工作原理

  1. 监控集群中 Pending 的 Pod
  2. 如果有 Pod 因资源不足无法调度,触发扩容
  3. 计算需要的节点数,请求云提供商创建节点
  4. 当节点利用率低于阈值(默认 50%)且持续一定时间,触发缩容

部署示例

在云环境中部署 Cluster Autoscaler:

apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
spec:
serviceAccountName: cluster-autoscaler
containers:
- name: cluster-autoscaler
image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.8.0
command:
- ./cluster-autoscaler
- --scale-down-unneeded-time=10m
- --balance-similar-node-groups
- --expander=priority
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-credentials
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-credentials
key: secret-access-key
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi

最佳实践

1. 始终设置资源请求

HPA 和 VPA 都依赖资源请求来工作:

resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi

2. 合理设置扩缩容范围

spec:
minReplicas: 2 # 保证高可用
maxReplicas: 20 # 防止资源失控

3. 使用稳定窗口防止震荡

behavior:
scaleDown:
stabilizationWindowSeconds: 300
scaleUp:
stabilizationWindowSeconds: 60

4. 先使用 VPA Off 模式观察

不要一开始就启用 VPA Auto 模式,先用 Off 模式观察推荐值是否合理。

5. 配置 Pod 中断预算

自动扩缩容会导致 Pod 重启,配置 PDB 保证服务可用性:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: my-app

6. 监控扩缩容事件

# 实时监控 HPA 事件
kubectl get events -w --field-selector reason=SuccessfulRescale

# 查看 VPA 推荐
kubectl describe vpa my-app-vpa

7. 测试扩缩容行为

使用负载测试工具验证扩缩容是否正常工作:

# 使用 kubectl run 生成负载
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://my-app; done"

小结

本章我们学习了:

  1. 扩缩容概念:水平扩缩容和垂直扩缩容的区别
  2. HPA:基于 CPU/内存/自定义指标的自动扩缩容
  3. VPA:自动调整 Pod 资源配置
  4. 配合使用:HPA 和 VPA 如何协同工作
  5. Cluster Autoscaler:自动调整集群节点数
  6. 最佳实践:资源请求、稳定窗口、监控等

自动扩缩容是 Kubernetes 弹性伸缩的核心能力,合理配置可以让应用在保证性能的同时最大化资源利用率。

练习

  1. 安装 Metrics Server 并验证 kubectl top 命令
  2. 创建一个 Deployment 并配置 HPA,测试自动扩缩容
  3. 安装 VPA,使用 Off 模式查看资源推荐
  4. 配置扩缩容行为,设置稳定窗口期
  5. 使用负载生成工具测试 HPA 的扩容效果

参考资料