从 Kubernetes HPA 的基本概念、指标接口到资源定义与注意事项,系统梳理原生自动扩缩容的核心知识。 通过 CPU 与内存两个场景,实战演示 Kubernetes HPA 的部署、扩缩容触发和压力验证流程。

一、K8s HPA概念及工作流程

1.1 Pod水平自动扩缩-HPA是什么

HPA是指Kubernetes水平Pod自动扩缩容(Horizontal Pod Autoscaler)是一个Kubernetes原生的自动化伸缩工具。主要用于根据服务的度量指标(如CPU使用率、内存使用率或其他自定义指标)自动调整服务的副本。

HPA可以通过增加或减少工作负载的副本数来确保应用程序能够处理当前的流量和负载,同时避免资源浪费。

在 Kubernetes 中,HorizontalPodAutoscaler自动更新工作负载资源 (例如Deployment或者StatefulSet), 目的是自动扩缩工作负载以满足需求。

Pod水平自动扩缩相对于垂直扩缩所用资源相对较少。

如果负载减少,并且Pod的数量高于配置的最小值, HorizontalPodAutoscaler 会指示工作负载资(Deployment、StatefulSet 或其他类似资源)缩减。

由于DaemonSet会在每个节点上都会部署,不适用于水平Pod自动扩缩。

1.2 Pod水平自动扩缩接口类型

可以通过以下命令查看所有Pod水平自动扩缩接口类型:

$ k get apiservices | grep autoscal
v1.autoscaling                         Local                        True        8d
v2.autoscaling                         Local                        True        8d
v2beta1.autoscaling                    Local                        True        8d
v2beta2.autoscaling                    Local                        True        8d

其中主要分为v1和v2,v2又分为v2beta1和v2beta2:

  • v1:稳定版自动水平伸缩,只支持CPU指标
  • v2beta1:支持CPU、内存和自定义指标
  • v2beta2:支持CPU、内存、自定义指标Custom和额外指标ExternalMetrics

1.3 Pod水平自动扩缩是如何工作的

Day022-K8s弹性能力-基于KEDA的下一代弹性伸缩-图1

HPA(Horizontal Pod Autoscaler)的工作流程可分为以下步骤:

1、监控指标:HPA 控制器定期(默认每 15 秒)查询目标 Deployment 管理的所有 Pod 的 CPU 使用情况,与 Pod 的 CPU 请求(Request)进行比较。

2、计算平均利用率:将所有 Pod 的 CPU 利用率取平均值。

3、判断扩缩容条件

  • 当平均 CPU 利用率超过 50%(即配置中的 averageUtilization)时,HPA 会尝试增加 Pod 数量,但不会超过 maxReplicas 设定的 10 个。
  • 当平均 CPU 利用率低于设定阈值时,HPA 会减少 Pod 数量,但不会低于 minReplicas 设定的 1 个。

4、自动调整:HPA 通过修改目标 Deployment 的副本数,实现自动扩缩容,达到资源利用率与系统负载之间的平衡。

Kubernetes 将水平 Pod 自动扩缩实现为一个间歇运行的控制回路(它不是一个连续的过程)。间隔由 kube-controller-manager--horizontal-pod-autoscaler-sync-period 参数设置(默认间隔为15 秒)。

在每个时间段内,控制器管理器都会根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。 控制器管理器找到由 scaleTargetRef 定义的目标资源,然后根据目标资源的 .spec.selector 标签选择 Pod, 并从资源指标 API(针对每个 Pod 的资源指标)或自定义指标获取指标 API(适用于所有其他指标)。

二、K8s HPA资源定义及注意事项

2.1 HPA资源定义

yaml资源文件如下:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

1、API 版本和资源类型

  • apiVersion: autoscaling/v2 使用 autoscaling/v2 版本意味着该 HPA 使用的是较新版本的自动扩缩容 API。相较于 v1,该版本支持更多指标类型(如外部指标、对象指标等)以及更复杂的配置选项。
  • kind: HorizontalPodAutoscaler 资源类型为 HorizontalPodAutoscaler,表示该配置用于自动根据指标(如 CPU 使用率)调整 Pod 副本数,实现水平扩展(scale out)或缩减(scale in)。

2、元数据部分

  • metadata.name: nginx-hpa 指定了 HPA 的名称为 nginx-hpa。在同一命名空间内,该名称必须唯一,用于后续管理和查询。
  • metadata.namespace: default 指定该 HPA 所在的命名空间为 default。在 Kubernetes 中,不同命名空间可以隔离资源,因此要确保 HPA 与目标 Deployment 在同一命名空间中。

3、规格(spec)配置

3.1 目标引用(scaleTargetRef)

scaleTargetRef:
  apiVersion: apps/v1
  kind: Deployment
  name: nginx-deployment
  • apiVersion: apps/v1 目标资源的 API 版本,此处为 Deployment 的版本。
  • kind: Deployment 表示自动扩缩容的目标是一个 Deployment 对象。
  • name: nginx-deployment 指定具体的 Deployment 名称为 nginx-deployment。HPA 将监控该 Deployment 所管理的 Pod,并根据定义的指标来调整其副本数。

3.2 副本数控制

  • minReplicas: 1 定义了自动扩缩容时,Pod 的最小副本数为 1。即使负载较低,副本数也不会少于 1。
  • maxReplicas: 10 定义了 Pod 的最大副本数为 10,避免因为负载突增导致无限制扩容,保护集群资源。

3.3 监控指标(metrics)

metrics:
- type: Resource
  resource:
    name: cpu
    target:
      type: Utilization
      averageUtilization: 50
  • type: Resource 指明本次监控的指标类型为资源指标,这里主要针对 CPU 资源。
  • resource.name: cpu 指定监控的具体资源是 CPU。
  • target.type: Utilization 目标类型设置为 Utilization,表示使用请求资源利用率来计算平均负载。
  • target.averageUtilization: 50 定义了目标平均 CPU 利用率为 50%(即 Pod 中所有容器的 CPU 请求平均达到 50% 时触发扩容)。当实际平均利用率超过该值时,HPA 将增加 Pod 数量;当低于该值且满足缩容条件时,会减少 Pod 数量。

2.2 Pod水平自动扩缩注意事项

Pod水平自动扩缩注意事项有以下方面:

  • 必须安装metrics-server或其他自定义metrics-server
  • 必须配置requests参数
  • 不能扩容无法缩放的对象,比如DaemonSet

列出与监控指标相关的API资源

[root@k8s-master01 ~]# k api-resources | grep metrics
nodes                                          metrics.k8s.io/v1beta1                 false        NodeMetrics
pods                                           metrics.k8s.io/v1beta1                 true         PodMetrics

三、Pod水平自动扩缩实战

下面进行演示Pod水平自动扩缩示例,示例步骤如下:

  • 启动一个Deployment 并暴露服务
  • 创建HPA
  • 模拟压力测试

1.1 基于CPU的弹性伸缩

1.1.1 启动一个Deployment并暴露服务

1.定义一个yaml文件

# 生成模板文件
[root@k8s-master01 ~]# kubectl create deploy nginx-server --image=registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2 --dry-run=client -oyaml > nginx-server.yaml

# 重新编辑模板文件
[root@k8s-master01 ~]# vim  nginx-server.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-server
  name: nginx-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-server
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx-server
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
        name: nginx
        resources: 
          requests:
            cpu: 10m
            memory: 128Mi

2.创建Deployment

[root@k8s-master01 ~]# k create -f nginx-server.yaml

3.查看pod

[root@k8s-master01 ~]# k get po 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-server-5f44c4b986-4rvjd   1/1     Running   0          14s

4.暴露出80端口

[root@k8s-master01 ~]# k expose deployment nginx-server --port=80

5.验证服务暴露是否成功

(1)查看服务IP

[root@k8s-master01 ~]# k get svc nginx-server
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-server   ClusterIP   10.107.94.116   <none>        80/TCP    17s

(2)测试服务,观察到返回200

[root@k8s-master01 ~]# curl -I 10.107.94.116  2>/dev/null | head -1 | awk '{print $2}'
200

6.查看cpu指标

[root@k8s-master01 ~]# k top po
NAME                            CPU(cores)   MEMORY(bytes)   
nginx-server-5f44c4b986-4rvjd   1m           1Mi

1.3.1.2 创建HPA

1.启动水平自动扩缩器

[root@k8s-master01 ~]# k autoscale deploy nginx-server --cpu-percent=10 --min=1 --max=10

上面参数说明:

  • --cpu-percent=10:指定 Deployment 的目标 CPU 利用率百分比。水平 Pod 自动缩放器将根据当前 CPU 利用率自动调整副本数量,以尝试维持此目标。
  • --min=1:指定 Deployment 应具有的最小副本数。即使 CPU 利用率很低,水平 Pod 自动缩放器也不会将 Deployment 缩小到此数以下。
  • --max=10:指定 Deployment 应具有的最大副本数。如果 CPU 利用率非常高,水平 Pod 自动缩放器也不会将 Deployment 扩展到此数以上。

2.检查新制作的HorizontalPodAutoscaler的当前状态

[root@k8s-master01 ~]# k get hpa
NAME           REFERENCE                 TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
nginx-server   Deployment/nginx-server   cpu: 0%/10%   1         10        1          20s

1.3.1.3 模拟压力测试

1.设置死循环进行测试,这里的IP为svc显示的IP

$ while true; do wget -q -O- http://10.107.94.116  > /dev/null; done

2.查看pod状态,发现pod节点已经扩容

[root@k8s-master01 ~]# k get po 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-server-5f44c4b986-4rvjd   1/1     Running   0          4m33s
nginx-server-5f44c4b986-5stxp   1/1     Running   0          21s
nginx-server-5f44c4b986-77nxj   1/1     Running   0          36s
nginx-server-5f44c4b986-bv4hv   1/1     Running   0          21s
nginx-server-5f44c4b986-dtm49   1/1     Running   0          6s
nginx-server-5f44c4b986-fqjff   1/1     Running   0          36s
nginx-server-5f44c4b986-psg8m   1/1     Running   0          6s
nginx-server-5f44c4b986-rdh7c   1/1     Running   0          21s
nginx-server-5f44c4b986-tpk4c   1/1     Running   0          21s
nginx-server-5f44c4b986-zvd75   1/1     Running   0          36s

3.按ctrl +c 停止死循环

4.等待5分钟后查看hpa,观察已低于10%。等待pod节点缩容

$ k get hpa
NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa-nginx   Deployment/hpa-nginx   0%/10%    1         10        10         10m

5.查看pod,观察pod节点已缩容

[root@k8s-master01 ~]# k get po 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-server-5f44c4b986-77nxj   1/1     Running   0          7m51s

6.环境复原

# 删除资源文件
[root@k8s-master01 ~]# kubectl delete -f  nginx-server.yaml

# 删除hpa
[root@k8s-master01 ~]# k delete hpa nginx-server

1.3.2 基于内存的弹性伸缩

说明:一般不使用基于内存的弹性伸缩

1.3.2.1 启动一个Deployment 并暴露服务

1.定义一个yaml文件

# 生成模板文件
[root@k8s-master01 ~]# kubectl create deploy memory-consumer --image=registry.cn-hangzhou.aliyuncs.com/zq-demo/stress:latest -oyaml > memory-consumer.yaml

# 重新定义模板文件
[root@k8s-master01 ~]# vim memory-consumer.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: memory-consumer
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: memory-consumer
  template:
    metadata:
      labels:
        app: memory-consumer
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/zq-demo/stress:latest
        imagePullPolicy: IfNotPresent 
        name: stress
        resources: 
          requests:
            cpu: "250m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "1024Mi"
        args: 
        - stress
        - --vm
        - "1"
        - --vm-bytes
        - "64M"
        - --verbose
        - --vm-hang
        - "3600"

2.创建Deployment

[root@k8s-master01 ~]# kaf  memory-consumer.yaml

3.查看pod

[root@k8s-master01 ~]# kgp 
NAME                               READY   STATUS    RESTARTS   AGE
memory-consumer-6986dd8798-6nwht   1/1     Running   0          36s

4.查看memory指标

[root@k8s-master01 ~]# k top po 
NAME                               CPU(cores)   MEMORY(bytes)   
memory-consumer-6986dd8798-6nwht   0m           64Mi   

1.3.2.2 创建HPA

1.启动水平自动扩缩器

# 编写memory-consumer-hpa.yaml
[root@k8s-master01 ~]# vim memory-consumer-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: memory-consumer-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: memory-consumer
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80


# 应用
[root@k8s-master01 ~]# kaf memory-consumer-hpa.yaml

2.检查新制作的HorizontalPodAutoscaler的当前状态

[root@k8s-master01 ~]# kg hpa
NAME                  REFERENCE                    TARGETS                 MINPODS   MAXPODS   REPLICAS   AGE
memory-consumer-hpa   Deployment/memory-consumer   memory: <unknown>/80%   1         5         0          15s

1.3.2.3 模拟压力测试

1、升高内存使用率

# 修改第40行内容,将其修改为2
[root@k8s-master01 ~]# k edit deploy memory-consumer
...
...
 40         - "2"
...
...

2、查看资源相关情况

# 查看pod,观察到已经新启动一个pod
[root@k8s-master01 ~]# kgp
NAME                               READY   STATUS    RESTARTS   AGE
memory-consumer-5876b8466f-bx629   1/1     Running   0          37s

# 查看hpa,观察到此时内存使用率高于80%
[root@k8s-master01 ~]# kg hpa
NAME                  REFERENCE                    TARGETS            MINPODS   MAXPODS   REPLICAS   AGE
memory-consumer-hpa   Deployment/memory-consumer   memory: 100%/80%   1         5         2          3m19s


# 这里因为设置最大副本数为5个,所以最多5个
[root@k8s-master01 ~]# kgp
NAME                               READY   STATUS    RESTARTS   AGE
memory-consumer-5876b8466f-b7sdj   1/1     Running   0          2m16s
memory-consumer-5876b8466f-bx629   1/1     Running   0          2m58s
memory-consumer-5876b8466f-c74cm   1/1     Running   0          75s
memory-consumer-5876b8466f-ttwwb   1/1     Running   0          45s
memory-consumer-5876b8466f-zn8wp   1/1     Running   0          105s

# 观察到pod副本扩成5个后,内存使用率仍然高于80%
[root@k8s-master01 ~]# kg hpa
NAME                  REFERENCE                    TARGETS            MINPODS   MAXPODS   REPLICAS   AGE
memory-consumer-hpa   Deployment/memory-consumer   memory: 100%/80%   1         5         5          6m47s

3、环境复原

[root@k8s-master01 ~]# k delete -f  memory-consumer.yaml -f memory-consumer-hpa.yaml 

三、Pod水平自动扩缩实战

下面进行演示Pod水平自动扩缩示例,示例步骤如下:

  • 启动一个Deployment 并暴露服务
  • 创建HPA
  • 模拟压力测试