Horizontal Pod Autoscaler 演练

    本文将引领你了解如何为 php-apache 服务器配置和使用 Horizontal Pod Autoscaler。 与 Horizontal Pod Autoscaler 相关的更多信息请参阅 。

    本文示例需要一个运行中的 Kubernetes 集群以及 kubectl,版本为 1.2 或更高。 Metrics 服务器 需要被部署到集群中,以便通过 提供度量数据。 Horizontal Pod Autoscaler 根据此 API 来获取度量数据。 要了解如何部署 metrics-server,请参考 metrics-server 文档

    如果需要为 Horizontal Pod Autoscaler 指定多种资源度量指标,你的 Kubernetes 集群以及 kubectl 至少需要达到 1.6 版本。 此外,如果要使用自定义度量指标,你的 Kubernetes 集群还必须能够与提供这些自定义指标 的 API 服务器通信。 最后,如果要使用与 Kubernetes 对象无关的度量指标,则 Kubernetes 集群版本至少需要 达到 1.10 版本,同样,需要保证集群能够与提供这些外部指标的 API 服务器通信。 更多详细信息,请参阅 。

    运行 php-apache 服务器并暴露服务

    为了演示 Horizontal Pod Autoscaler,我们将使用一个基于 php-apache 镜像的 定制 Docker 镜像。Dockerfile 内容如下:

    该文件定义了一个 index.php 页面来执行一些 CPU 密集型计算:

    1. $x = 0.0001;
    2. for ($i = 0; $i <= 1000000; $i++) {
    3. $x += sqrt($x);
    4. }
    5. echo "OK!";
    6. ?>

    首先,我们使用下面的配置启动一个 Deployment 来运行这个镜像并暴露一个服务:

    application/php-apache.yaml

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: php-apache
    5. spec:
    6. selector:
    7. matchLabels:
    8. run: php-apache
    9. replicas: 1
    10. template:
    11. metadata:
    12. labels:
    13. run: php-apache
    14. spec:
    15. containers:
    16. - name: php-apache
    17. image: k8s.gcr.io/hpa-example
    18. ports:
    19. - containerPort: 80
    20. resources:
    21. limits:
    22. cpu: 500m
    23. requests:
    24. cpu: 200m
    25. ---
    26. apiVersion: v1
    27. kind: Service
    28. metadata:
    29. name: php-apache
    30. labels:
    31. run: php-apache
    32. spec:
    33. ports:
    34. - port: 80
    35. selector:
    36. run: php-apache

    运行下面的命令:

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

    创建 Horizontal Pod Autoscaler

    现在,php-apache 服务器已经运行,我们将通过 命令创建 Horizontal Pod Autoscaler。 以下命令将创建一个 Horizontal Pod Autoscaler 用于控制我们上一步骤中创建的 Deployment,使 Pod 的副本数量维持在 1 到 10 之间。 大致来说,HPA 将(通过 Deployment)增加或者减少 Pod 副本的数量以保持所有 Pod 的平均 CPU 利用率在 50% 左右(由于每个 Pod 请求 200 毫核的 CPU,这意味着平均 CPU 用量为 100 毫核)。 算法的详情请参阅相关文档

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

    我们可以通过以下命令查看 Autoscaler 的状态:

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

    请注意当前的 CPU 利用率是 0%,这是由于我们尚未发送任何请求到服务器 (CURRENT 列显示了相应 Deployment 所控制的所有 Pod 的平均 CPU 利用率)。

    现在,我们将看到 Autoscaler 如何对增加负载作出反应。 我们将启动一个容器,并通过一个循环向 php-apache 服务器发送无限的查询请求 (请在另一个终端中运行以下命令):

    1. kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

    一分钟时间左右之后,通过以下命令,我们可以看到 CPU 负载升高了:

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

    这时,由于请求增多,CPU 利用率已经升至请求值的 305%。 可以看到,Deployment 的副本数量已经增长到了 7:

    1. kubectl get deployment php-apache
    1. NAME READY UP-TO-DATE AVAILABLE AGE
    2. php-apache 7/7 7 7 19m

    停止负载

    我们将通过停止负载来结束我们的示例。

    在我们创建 busybox 容器的终端中,输入<Ctrl> + C 来终止负载的产生。

    然后我们可以再次检查负载状态(等待几分钟时间):

    1. kubectl get hpa
    1. NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
    1. kubectl get deployment php-apache
    1. NAME READY UP-TO-DATE AVAILABLE AGE
    2. php-apache 1/1 1 1 27m

    这时,CPU 利用率已经降到 0,所以 HPA 将自动缩减副本数量至 1。

    说明: 自动扩缩完成副本数量的改变可能需要几分钟的时间。

    基于多项度量指标和自定义度量指标自动扩缩

    利用 autoscaling/v2beta2 API 版本,你可以在自动扩缩 php-apache 这个 Deployment 时使用其他度量指标。

    首先,将 HorizontalPodAutoscaler 的 YAML 文件改为 autoscaling/v2beta2 格式:

    1. kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml

    在编辑器中打开 /tmp/hpa-v2.yaml

    1. apiVersion: autoscaling/v2beta2
    2. kind: HorizontalPodAutoscaler
    3. metadata:
    4. name: php-apache
    5. spec:
    6. scaleTargetRef:
    7. apiVersion: apps/v1
    8. kind: Deployment
    9. name: php-apache
    10. minReplicas: 1
    11. maxReplicas: 10
    12. metrics:
    13. - type: Resource
    14. resource:
    15. name: cpu
    16. target:
    17. averageUtilization: 50
    18. status:
    19. observedGeneration: 1
    20. lastScaleTime: <some-time>
    21. currentReplicas: 1
    22. desiredReplicas: 1
    23. currentMetrics:
    24. - type: Resource
    25. resource:
    26. name: cpu
    27. current:
    28. averageUtilization: 0
    29. averageValue: 0

    需要注意的是,targetCPUUtilizationPercentage 字段已经被名为 metrics 的数组所取代。 CPU 利用率这个度量指标是一个 resource metric(资源度量指标),因为它表示容器上指定资源的百分比。 除 CPU 外,你还可以指定其他资源度量指标。默认情况下,目前唯一支持的其他资源度量指标为内存。 只要 metrics.k8s.io API 存在,这些资源度量指标就是可用的,并且他们不会在不同的 Kubernetes 集群中改变名称。

    你还可以指定资源度量指标使用绝对数值,而不是百分比,你需要将 target.typeUtilization 替换成 AverageValue,同时设置 target.averageValue 而非 target.averageUtilization 的值。

    还有两种其他类型的度量指标,他们被认为是 custom metrics(自定义度量指标): 即 Pod 度量指标和 Object 度量指标。 这些度量指标可能具有特定于集群的名称,并且需要更高级的集群监控设置。

    第一种可选的度量指标类型是 Pod 度量指标。这些指标从某一方面描述了 Pod, 在不同 Pod 之间进行平均,并通过与一个目标值比对来确定副本的数量。 它们的工作方式与资源度量指标非常相像,只是它们仅支持 target 类型为 AverageValue

    pod 度量指标通过如下代码块定义:

    第二种可选的度量指标类型是对象(Object)度量指标。这些度量指标用于描述 在相同名字空间中的别的对象,而非 Pods。 请注意这些度量指标不一定来自某对象,它们仅用于描述这些对象。 对象度量指标支持的 target 类型包括 ValueAverageValue。 如果是 Value 类型,target 值将直接与 API 返回的度量指标比较, 而对于 AverageValue 类型,API 返回的度量值将按照 Pod 数量拆分, 然后再与 target 值比较。 下面的 YAML 文件展示了一个表示 requests-per-second 的度量指标。

    1. type: Object
    2. object:
    3. metric:
    4. name: requests-per-second
    5. describedObject:
    6. apiVersion: networking.k8s.io/v1
    7. kind: Ingress
    8. name: main-route
    9. target:
    10. type: Value
    11. value: 2k

    比如,如果你的监控系统能够提供网络流量数据,你可以通过 kubectl edit 命令 将上述 Horizontal Pod Autoscaler 的定义更改为:

    1. apiVersion: autoscaling/v2beta1
    2. kind: HorizontalPodAutoscaler
    3. metadata:
    4. name: php-apache
    5. spec:
    6. scaleTargetRef:
    7. apiVersion: apps/v1
    8. kind: Deployment
    9. name: php-apache
    10. minReplicas: 1
    11. maxReplicas: 10
    12. metrics:
    13. - type: Resource
    14. resource:
    15. name: cpu
    16. target:
    17. type: AverageUtilization
    18. averageUtilization: 50
    19. - type: Pods
    20. pods:
    21. metric:
    22. name: packets-per-second
    23. target:
    24. type: AverageValue
    25. averageValue: 1k
    26. - type: Object
    27. object:
    28. metric:
    29. describedObject:
    30. apiVersion: networking.k8s.io/v1beta1
    31. kind: Ingress
    32. name: main-route
    33. target:
    34. kind: Value
    35. value: 10k
    36. status:
    37. observedGeneration: 1
    38. lastScaleTime: <some-time>
    39. currentReplicas: 1
    40. desiredReplicas: 1
    41. currentMetrics:
    42. - type: Resource
    43. resource:
    44. current:
    45. averageUtilization: 0
    46. averageValue: 0
    47. - type: Object
    48. object:
    49. metric:
    50. name: requests-per-second
    51. describedObject:
    52. apiVersion: networking.k8s.io/v1beta1
    53. kind: Ingress
    54. name: main-route
    55. current:
    56. value: 10k

    这样,你的 HorizontalPodAutoscaler 将会尝试确保每个 Pod 的 CPU 利用率在 50% 以内, 每秒能够服务 1000 个数据包请求, 并确保所有在 Ingress 后的 Pod 每秒能够服务的请求总数达到 10000 个。

    许多度量流水线允许你通过名称或附加的 标签 来描述度量指标。 对于所有非资源类型度量指标(Pod、Object 和后面将介绍的 External), 可以额外指定一个标签选择算符。例如,如果你希望收集包含 verb 标签的 http_requests 度量指标,可以按如下所示设置度量指标块,使得扩缩操作仅针对 GET 请求执行:

    1. type: Object
    2. object:
    3. metric:
    4. name: `http_requests`
    5. selector: `verb=GET`

    这个选择算符使用与 Kubernetes 标签选择算符相同的语法。 如果名称和标签选择算符匹配到多个系列,监测管道会决定如何将多个系列合并成单个值。 选择算符是可以累加的,它不会选择目标以外的对象(类型为 Pods 的目标 Pods 或者 类型为 Object 的目标对象)。

    运行在 Kubernetes 上的应用程序可能需要基于与 Kubernetes 集群中的任何对象 没有明显关系的度量指标进行自动扩缩, 例如那些描述与任何 Kubernetes 名字空间中的服务都无直接关联的度量指标。 在 Kubernetes 1.10 及之后版本中,你可以使用外部度量指标(external metrics)。

    使用外部度量指标时,需要了解你所使用的监控系统,相关的设置与使用自定义指标时类似。 外部度量指标使得你可以使用你的监控系统的任何指标来自动扩缩你的集群。 你只需要在 metric 块中提供 nameselector,同时将类型由 Object 改为 External。 如果 metricSelector 匹配到多个度量指标,HorizontalPodAutoscaler 将会把它们加和。 外部度量指标同时支持 ValueAverageValue 类型,这与 Object 类型的度量指标相同。

    例如,如果你的应用程序处理来自主机上消息队列的任务, 为了让每 30 个任务有 1 个工作者实例,你可以将下面的内容添加到 HorizontalPodAutoscaler 的配置中。

    1. - type: External
    2. external:
    3. metric:
    4. name: queue_messages_ready
    5. selector: "queue=worker_tasks"
    6. target:
    7. type: AverageValue
    8. averageValue: 30

    如果可能,还是推荐定制度量指标而不是外部度量指标,因为这便于让系统管理员加固定制度量指标 API。 而外部度量指标 API 可以允许访问所有的度量指标。 当暴露这些服务时,系统管理员需要仔细考虑这个问题。

    使用 autoscaling/v2beta2 格式的 HorizontalPodAutoscaler 时,你将可以看到 Kubernetes 为 HorizongtalPodAutoscaler 设置的状态条件(Status Conditions)。 这些状态条件可以显示当前 HorizontalPodAutoscaler 是否能够执行扩缩以及是否受到一定的限制。

    status.conditions 字段展示了这些状态条件。 可以通过 kubectl describe hpa 命令查看当前影响 HorizontalPodAutoscaler 的各种状态条件信息:

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

    对于上面展示的这个 HorizontalPodAutoscaler,我们可以看出有若干状态条件处于健康状态。 首先,AbleToScale 表明 HPA 是否可以获取和更新扩缩信息,以及是否存在阻止扩缩的各种回退条件。 其次,ScalingActive 表明 HPA 是否被启用(即目标的副本数量不为零) 以及是否能够完成扩缩计算。 当这一状态为 False 时,通常表明获取度量指标存在问题。 最后一个条件 ScalingLimitted 表明所需扩缩的值被 HorizontalPodAutoscaler 所定义的最大或者最小值所限制(即已经达到最大或者最小扩缩值)。 这通常表明你可能需要调整 HorizontalPodAutoscaler 所定义的最大或者最小副本数量的限制了。

    附录:量纲

    HorizontalPodAutoscaler 和 度量指标 API 中的所有的度量指标使用 Kubernetes 中称为 的特殊整数表示。 例如,数量 10500m 用十进制表示为 10.5。 如果可能的话,度量指标 API 将返回没有后缀的整数,否则返回以千分单位的数量。 这意味着你可能会看到你的度量指标在 11500m (也就是在十进制记数法中的 11.5)之间波动。

    附录:其他可能的情况

    除了使用 kubectl autoscale 命令,也可以文件创建 HorizontalPodAutoscaler:

    application/hpa/php-apache.yaml Horizontal Pod Autoscaler 演练 - 图1

    1. apiVersion: autoscaling/v1
    2. kind: HorizontalPodAutoscaler
    3. metadata:
    4. name: php-apache
    5. spec:
    6. scaleTargetRef:
    7. apiVersion: apps/v1
    8. kind: Deployment
    9. name: php-apache
    10. minReplicas: 1
    11. maxReplicas: 10
    12. targetCPUUtilizationPercentage: 50
      1. horizontalpodautoscaler.autoscaling/php-apache created