HorizontalPodAutoscaler 演练
一个 水平 Pod 自动伸缩器 (简称 HPA) 会自动更新工作负载资源 (例如 部署 或 有状态集),旨在自动扩展工作负载以匹配需求。
水平扩展意味着对增加负载的响应是部署更多 Pod。这与垂直扩展不同,垂直扩展对于 Kubernetes 来说意味着为工作负载已在运行的 Pod 分配更多资源 (例如:内存或 CPU)。
如果负载降低,并且 Pod 的数量超过配置的最小值,则水平 Pod 自动伸缩器会指示工作负载资源 (部署、有状态集或其他类似资源) 向下缩容。
本文档将引导您完成一个启用水平 Pod 自动伸缩器以自动管理示例 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 服务器
为了演示水平 Pod 自动伸缩器,您将首先启动一个使用 hpa-example
镜像运行容器的部署,并将其公开为 服务,使用以下清单
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
创建水平 Pod 自动伸缩器
现在服务器正在运行,请使用 kubectl
创建自动伸缩器。 kubectl autoscale
子命令 (kubectl
的一部分) 可以帮助您完成此操作。
您将很快运行一个命令,创建一个水平 Pod 自动伸缩器,该自动伸缩器将维护由您在这些说明的第一步中创建的 php-apache 部署控制的 Pod 的 1 到 10 个副本。
粗略地说,HPA 控制器 将增加和减少副本数量 (通过更新部署) 以维持所有 Pod 上的平均 CPU 利用率为 50%。然后,部署会更新副本集 - 这是所有 Kubernetes 部署的工作方式的一部分 - 然后副本集会根据其 .spec
中的更改添加或删除 Pod。
由于每个 pod 通过 kubectl run
请求 200 毫核,这意味着平均 CPU 使用率为 100 毫核。参见 算法详细信息 以了解有关算法的更多详细信息。
创建水平 Pod 自动伸缩器
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
您可以通过运行以下命令检查新创建的水平 Pod 自动伸缩器的当前状态
# 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
(如果您看到其他名称不同的水平 Pod 自动伸缩器,则意味着它们已经存在,通常不会造成问题)。
请注意,当前 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%。因此,部署已调整为 7 个副本
kubectl get deployment php-apache
您应该会看到副本数量与水平 Pod 自动伸缩器中的数字匹配
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
部署也显示它已缩容
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
部署时引入其他指标。
首先,以 autoscaling/v2
形式获取水平 Pod 自动伸缩器的 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.type
的 AverageValue
而不是 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
类型为 Value
和 AverageValue
。使用 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 消费大约 50% 的请求 CPU,每秒处理 1000 个数据包,并且所有位于 main-route Ingress 后面的 Pod 每秒总共处理 10000 个请求。
基于更具体的指标进行自动缩放
许多指标管道允许您通过名称或一组称为标签的额外描述符来描述指标。对于所有非资源指标类型(Pod、对象和外部,如下所述),您可以指定一个附加的标签选择器,该选择器将传递给您的指标管道。例如,如果您收集了带有 verb
标签的指标 http_requests
,您可以指定以下指标块,仅根据 GET 请求进行缩放
type: Object
object:
metric:
name: http_requests
selector: {matchLabels: {verb: GET}}
此选择器使用与完整 Kubernetes 标签选择器相同的语法。如果名称和选择器匹配多个系列,则监控管道将确定如何将多个系列折叠为单个值。选择器是累加的,不能选择描述非目标对象的指标(对于 Pods
类型,目标对象是目标 Pod;对于 Object
类型,目标对象是描述的对象)。
基于与 Kubernetes 对象无关的指标进行自动缩放
在 Kubernetes 上运行的应用程序可能需要根据与 Kubernetes 集群中任何对象没有明显关系的指标进行自动缩放,例如描述托管服务的指标,该服务与 Kubernetes 命名空间没有直接关联。在 Kubernetes 1.10 及更高版本中,您可以使用外部指标来解决这种情况。
使用外部指标需要了解您的监控系统;设置类似于使用自定义指标所需的设置。外部指标允许您根据监控系统中可用的任何指标对集群进行自动缩放。提供带有 name
和 selector
的 metric
块,如上所示,并使用 External
指标类型而不是 Object
。如果 metricSelector
匹配多个时间序列,则 HorizontalPodAutoscaler 将使用其值的总和。外部指标支持 Value
和 AverageValue
两种目标类型,它们的功能与使用 Object
类型时的功能完全相同。
例如,如果您的应用程序从托管队列服务处理任务,您可以在 HorizontalPodAutoscaler 清单中添加以下部分,以指定您需要每 30 个待处理任务一个工作程序。
- type: External
external:
metric:
name: queue_messages_ready
selector:
matchLabels:
queue: "worker_tasks"
target:
type: AverageValue
averageValue: 30
如果可能,最好使用自定义指标目标类型而不是外部指标,因为集群管理员更容易保护自定义指标 API。外部指标 API 可能允许访问任何指标,因此集群管理员在公开外部指标 API 时应谨慎。
附录:Horizontal Pod Autoscaler 状态条件
当使用 HorizontalPodAutoscaler 的 autoscaling/v2
表单时,您将能够看到 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 将在可能的情况下返回没有后缀的整数,否则将以毫单位返回数量。这意味着您可能会看到您的指标值在 1
和 1500m
之间波动,或者以十进制表示法写为 1
和 1.5
之间波动。
其他可能的情况
声明式创建自动缩放器
我们可以使用以下清单来声明式地创建 HorizontalPodAutoscaler,而不是使用 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