HorizontalPodAutoscaler 演练

一个 HorizontalPodAutoscaler (简称 HPA) 会自动更新工作负载资源(例如 DeploymentStatefulSet),目标是自动伸缩工作负载以匹配需求。

水平伸缩意味着响应增加的负载是通过部署更多的 Pod 来实现的。这与垂直伸缩不同,对于 Kubernetes 而言,垂直伸缩意味着为已经运行的工作负载的 Pod 分配更多的资源(例如:内存或 CPU)。

如果负载降低,并且 Pod 的数量超过了配置的最小值,HorizontalPodAutoscaler 会指示工作负载资源(Deployment、StatefulSet 或其他类似资源)缩小规模。

本文档将引导您完成一个示例,以启用 HorizontalPodAutoscaler 以自动管理示例 Web 应用的规模。此示例工作负载是运行一些 PHP 代码的 Apache httpd。

开始之前

您需要一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行此教程。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场之一

您的 Kubernetes 服务器必须是 1.23 版本或更高版本。

要检查版本,请输入 kubectl version

如果您正在运行 Kubernetes 的旧版本,请参阅该版本的文档(请参阅 可用文档版本)。

要遵循此演练,您还需要使用已部署并配置 Metrics Server 的集群。Kubernetes Metrics Server 从集群中的 kubelet 收集资源指标,并通过 Kubernetes API 暴露这些指标,使用 APIService 添加新的资源类型来表示指标读数。

要了解如何部署 Metrics Server,请参阅 metrics-server 文档

如果您正在运行 Minikube,请运行以下命令以启用 metrics-server

minikube addons enable metrics-server

运行并暴露 php-apache 服务器

为了演示 HorizontalPodAutoscaler,您将首先启动一个 Deployment,该 Deployment 运行一个使用 hpa-example 镜像的容器,并将其作为 Service 暴露,使用以下清单

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

为此,请运行以下命令

kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created

创建 HorizontalPodAutoscaler

现在服务器正在运行,使用 kubectl 创建自动伸缩器。kubectl autoscale 子命令,是 kubectl 的一部分,可以帮助您执行此操作。

您将很快运行一个命令,该命令创建一个 HorizontalPodAutoscaler,以维持由您在这些说明的第一个步骤中创建的 php-apache Deployment 控制的 Pod 之间的 1 到 10 个副本。

粗略地说,HPA 控制器 将增加和减少副本数量(通过更新 Deployment)以维持所有 Pod 的平均 CPU 利用率达到 50%。然后 Deployment 更新 ReplicaSet - 这是所有 Deployment 的工作方式 - 然后 ReplicaSet 根据对 .spec 的更改添加或删除 Pod。

由于每个 pod 通过 kubectl run 请求 200 毫核,这意味着 100 毫核的平均 CPU 使用量。有关算法详细信息,请参阅 算法详细信息

创建 HorizontalPodAutoscaler

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled

您可以通过运行以下命令来检查新创建的 HorizontalPodAutoscaler 的当前状态

# You can use "hpa" or "horizontalpodautoscaler"; either name works OK.
kubectl get hpa

输出类似于

NAME         REFERENCE                     TARGET    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%  1         10        1          18s

(如果您看到其他具有不同名称的 HorizontalPodAutoscaler,这意味着它们已经存在,通常不是问题)。

请注意,当前的 CPU 消耗为 0%,因为没有客户端向服务器发送请求(TARGET 列显示受相应部署控制的所有 Pod 的平均值)。

增加负载

接下来,查看自动伸缩器如何响应增加的负载。为此,您将启动另一个 Pod 作为客户端。容器内的客户端 Pod 在无限循环中运行,向 php-apache 服务发送查询。

# Run this in a separate terminal
# so that the load generation continues and you can carry on with the rest of the steps
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

现在运行

# type Ctrl+C to end the watch when you're ready
kubectl get hpa php-apache --watch

在一分钟左右,您应该会看到更高的 CPU 负载;例如

NAME         REFERENCE                     TARGET      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   305% / 50%  1         10        1          3m

然后,更多的副本。例如

NAME         REFERENCE                     TARGET      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   305% / 50%  1         10        7          3m

这里,CPU 消耗增加到请求的 305%。因此,Deployment 的大小调整为 7 个副本

kubectl get deployment php-apache

您应该看到副本计数与 HorizontalPodAutoscaler 中的数字匹配

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   7/7      7           7           19m

停止生成负载

要完成示例,请停止发送负载。

在创建运行 busybox 镜像的 Pod 的终端中,通过键入 <Ctrl> + C 终止负载生成。

然后验证结果状态(一分钟左右)

# type Ctrl+C to end the watch when you're ready
kubectl get hpa php-apache --watch

输出类似于

NAME         REFERENCE                     TARGET       MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%     1         10        1          11m

Deployment 也显示它已缩小规模

kubectl get deployment php-apache
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   1/1     1            1           27m

一旦 CPU 利用率降至 0,HPA 会自动将副本数量缩减回 1。

自动伸缩可能需要几分钟。

使用多个指标和自定义指标进行自动伸缩

您可以通过使用 autoscaling/v2 API 版本来引入其他指标,以用于自动伸缩 php-apache Deployment。

首先,获取 autoscaling/v2 形式的 HorizontalPodAutoscaler 的 YAML

kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml

打开 /tmp/hpa-v2.yaml 文件,您应该会看到如下 YAML

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
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
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      current:
        averageUtilization: 0
        averageValue: 0

请注意,targetCPUUtilizationPercentage 字段已被名为 metrics 的数组替换。CPU 利用率指标是资源指标,因为它表示为 Pod 容器上指定的资源的百分比。请注意,您可以指定其他资源指标,而不仅仅是 CPU。默认情况下,唯一支持的另一个资源指标是 memory。这些资源不会从集群到集群更改名称,只要 metrics.k8s.io API 可用,就应该始终可用。

您还可以使用 target.typeAverageValue 而不是 Utilization,并设置相应的 target.averageValue 字段,而不是 target.averageUtilization,以直接值来指定资源指标。

  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: AverageValue
        averageValue: 500Mi

还有两种其他类型的指标,两者都被认为是自定义指标:Pod 指标和对象指标。这些指标可能具有集群特定的名称,并且需要更高级的集群监控设置。

这些替代指标类型中的第一种是Pod 指标。这些指标描述 Pod,并在 Pod 上求平均值,然后与目标值进行比较以确定副本计数。它们的工作方式与资源指标非常相似,除了它们支持 target 类型为 AverageValue

Pod 指标使用如下指标块指定

type: Pods
pods:
  metric:
    name: packets-per-second
  target:
    type: AverageValue
    averageValue: 1k

第二种替代指标类型是对象指标。这些指标描述同一命名空间中的不同对象,而不是描述 Pod。这些指标不一定从对象中获取;它们只是描述它。对象指标支持 target 类型为 ValueAverageValue。使用 Value,目标直接与 API 返回的指标进行比较。使用 AverageValue,从自定义指标 API 返回的值除以 Pod 数量,然后与目标进行比较。以下示例是 requests-per-second 指标的 YAML 表示形式。

type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k

如果您提供多个这样的指标块,HorizontalPodAutoscaler 将会依次考虑每个指标。HorizontalPodAutoscaler 将会为每个指标计算建议的副本数量,然后选择副本数量最多的那个。

例如,如果您有监控系统收集关于网络流量的指标,您可以使用 kubectl edit 更新上面的定义,使其看起来像这样

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
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
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      target:
        type: AverageValue
        averageValue: 1k
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: main-route
      target:
        type: Value
        value: 10k
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
    current:
      averageUtilization: 0
      averageValue: 0
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: main-route
      current:
        value: 10k

然后,您的 HorizontalPodAutoscaler 将会尝试确保每个 Pod 消耗其请求 CPU 的大约 50%,每秒处理 1000 个数据包,并且主路由 Ingress 后面的所有 Pod 每秒处理总共 10000 个请求。

基于更具体的指标进行自动伸缩

许多指标管道允许您通过名称或一组称为标签的附加描述符来描述指标。对于所有非资源指标类型(Pod、对象和外部,如下所述),您可以指定一个附加的标签选择器,该选择器会传递给您的指标管道。例如,如果您收集一个名为 http_requests 的指标,并带有 verb 标签,您可以指定以下指标块,仅基于 GET 请求进行伸缩

type: Object
object:
  metric:
    name: http_requests
    selector: {matchLabels: {verb: GET}}

此选择器使用与完整的 Kubernetes 标签选择器相同的语法。监控管道确定如何将多个系列折叠成单个值,如果名称和选择器匹配多个系列。选择器是累加的,不能选择描述不是目标对象(对于 Pods 类型,是目标 Pod;对于 Object 类型,是描述的对象)的对象的指标。

在 Kubernetes 上运行的应用程序可能需要基于与 Kubernetes 集群中的任何对象没有明显关系的指标进行自动伸缩,例如描述没有与 Kubernetes 命名空间直接相关的托管服务的指标。在 Kubernetes 1.10 及更高版本中,您可以使用外部指标来解决此用例。

使用外部指标需要了解您的监控系统;设置方式与使用自定义指标时类似。外部指标允许您基于监控系统中可用的任何指标来自动伸缩您的集群。提供一个带有 nameselectormetric 块,如上所述,并使用 External 指标类型代替 Object。如果多个时间序列与 metricSelector 匹配,则它们的总和将由 HorizontalPodAutoscaler 使用。外部指标支持 ValueAverageValue 目标类型,它们的功能与使用 Object 类型时完全相同。

例如,如果您的应用程序从托管队列服务中处理任务,您可以将以下部分添加到您的 HorizontalPodAutoscaler 清单文件中,以指定您需要每个 30 个未处理的任务一个 worker。

- type: External
  external:
    metric:
      name: queue_messages_ready
      selector:
        matchLabels:
          queue: "worker_tasks"
    target:
      type: AverageValue
      averageValue: 30

在可能的情况下,最好使用自定义指标目标类型而不是外部指标,因为自定义指标 API 更易于集群管理员保护。外部指标 API 可能会允许访问任何指标,因此集群管理员在公开它时应小心。

附录:Horizontal Pod Autoscaler 状态条件

在使用 autoscaling/v2 形式的 HorizontalPodAutoscaler 时,您将能够看到 Kubernetes 在 HorizontalPodAutoscaler 上设置的状态条件。这些状态条件指示 HorizontalPodAutoscaler 是否能够伸缩,以及它是否受到任何限制。

这些条件出现在 status.conditions 字段中。要查看影响 HorizontalPodAutoscaler 的条件,我们可以使用 kubectl describe hpa

kubectl describe hpa cm-test
Name:                           cm-test
Namespace:                      prom
Labels:                         <none>
Annotations:                    <none>
CreationTimestamp:              Fri, 16 Jun 2017 18:09:22 +0000
Reference:                      ReplicationController/cm-test
Metrics:                        ( current / target )
  "http_requests" on pods:      66m / 500m
Min replicas:                   1
Max replicas:                   4
ReplicationController pods:     1 current / 1 desired
Conditions:
  Type                  Status  Reason                  Message
  ----                  ------  ------                  -------
  AbleToScale           True    ReadyForNewScale        the last scale time was sufficiently old as to warrant a new scale
  ScalingActive         True    ValidMetricFound        the HPA was able to successfully calculate a replica count from pods metric http_requests
  ScalingLimited        False   DesiredWithinRange      the desired replica count is within the acceptable range
Events:

对于这个 HorizontalPodAutoscaler,您可以看到几个处于健康状态的条件。首先,AbleToScale 指示 HPA 是否能够获取和更新缩放,以及是否有任何回退相关的条件会阻止缩放。其次,ScalingActive 指示 HPA 是否已启用(即目标的副本计数不为零)并且能够计算所需的缩放。当它为 False 时,通常表示获取指标时出现问题。最后,最后一个条件,ScalingLimited,指示所需的缩放被 HorizontalPodAutoscaler 的最大值或最小值所限制。这表明您可能希望提高或降低 HorizontalPodAutoscaler 上的最小或最大副本计数约束。

数量

HorizontalPodAutoscaler 和指标 API 中的所有指标都使用 Kubernetes 中称为 数量 的特殊整数表示法。例如,数量 10500m 在十进制表示法中将写为 10.5。指标 API 将在可能的情况下返回没有后缀的整数,并且通常会以毫单位返回数量。这意味着您可能会看到您的指标值在 11500m 之间波动,或者在以十进制表示法书写时在 11.5 之间波动。

其他可能的情况

以声明方式创建自动伸缩器

与其使用 kubectl autoscale 命令以命令方式创建 HorizontalPodAutoscaler,不如我们可以使用以下清单以声明方式创建它

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
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

然后,通过执行以下命令创建自动伸缩器

kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created
最后修改时间为 2025 年 11 月 23 日下午 1:47 PST:移动 HorizontalPodAutoscaler 概念页面 (57e1fdd7f9)