使用自定义指标进行弹性伸缩


通过 Prometheus adaptor 来自定义监控指标

使用自定义指标进行弹性伸缩

通过 Prometheus adaptor 来自定义监控指标

Tue Jun 19, 2018

2800 Words|Read in about 6 Min|本文总阅读量
Tags: kubernetes  

从 Kubernetes 1.8 开始,资源使用指标(如容器 CPU 和内存使用率)可以通过 Metrics API 在 Kubernetes 中获取。 这些指标可以直接被用户访问(例如通过使用 kubectl top 命令),或由集群中的控制器使用(例如,Horizontal Pod Autoscale 可以使用这些指标作出决策)。

例如,可以使用 kubectl top nodekubectl top pod 查看资源使用情况:

$ kubectl top node

NAME              CPU(cores)   CPU%      MEMORY(bytes)   MEMORY%
192.168.123.248   245m         12%       2687Mi          34%
192.168.123.249   442m         22%       3270Mi          42%
192.168.123.250   455m         22%       4014Mi          52%

$ kubectl top pod

NAME                              CPU(cores)   MEMORY(bytes)
details-v1-64b86cd49-52g82        0m           11Mi
podinfo-6b86c8ccc9-5qr8b          0m           7Mi
podinfo-6b86c8ccc9-hlxm7          0m           12Mi
podinfo-6b86c8ccc9-qxhng          0m           6Mi


1. Resource Metrics API


通过 Metrics API,您可以获取指定 node 或 pod 当前使用的资源量。这个 API 不存储指标值, 因此想要获取某个指定 node 10分钟前的资源使用量是不可能的。

Metrics API 和其他的 API 没有什么不同,它可以通过与 /apis/metrics.k8s.io/ 路径下的其他 Kubernetes API 相同的端点来发现,并且提供了相同的安全性、可扩展性和可靠性保证,Metrics API 在 k8s.io/metrics 仓库中定义,你可以在这里找到关于 Metrics API 的更多信息。

注意: Metrics API 需要在集群中部署 Metrics Server。否则它将不可用。

2. Metrics Server


Metrics Server 实现了Resource Metrics API。

Metrics Server 是集群范围资源使用数据的聚合器。 从 Kubernetes 1.8 开始,它作为一个 Deployment 对象默认部署在由 kube-up.sh 脚本创建的集群中。 如果你使用了其他的 Kubernetes 安装方法,您可以使用 Kubernetes 1.7+ (请参阅下面的详细信息) 中引入的 deployment yamls 文件来部署。

Metrics Server 从每个节点上的 Kubelet 公开的 Summary API 中采集指标信息。

通过在主 API server 中注册的 Metrics Server Kubernetes 聚合器 来采集指标信息, 这是在 Kubernetes 1.7 中引入的。在 设计文档 中可以了解到有关 Metrics Server 的更多信息。

3. custom metrics api


该 API 允许消费者访问通过任意指标描述的 Kubernetes 资源。如果你想实现这个 API Service,请参阅 kubernetes-incubator/custom-metrics-apiserver,这是一个用来实现 Kubernetes 自定义指标的框架。

4. HPA


自动伸缩是一种根据资源使用情况自动伸缩工作负载的方法。自动伸缩在 Kubernetes 中有两个维度:

  • Cluster Autoscaler : 用来处理节点扩容。
  • Horizontal Pod Autoscaler : 自动缩放 rs 或 rc 中的 pod。

Cluster Autoscaler 和 Horizontal Pod Autoscaler 一起可用于动态调整集群的计算能力。虽然 Cluster Autoscaler 高度依赖于托管集群的云服务商提供的底层功能,但是 HPA 可以独立于你的 IaaS/PaaS 提供商进行操作。

Kubernetes 自 1.2 版本引入 HPA 机制,到 1.6 版本之前一直是通过 kubelet 来获取监控指标来判断是否需要扩缩容,1.6 版本之后必须通过 API server、Heapseter 或者 kube-aggregator 来获取监控指标。

Kubernetes 1.7 引入了聚合层,允许第三方应用程序通过注册为 API 附加组件来扩展 Kubernetes API。 自定义指标 API 以及聚合层使得像 Prometheus 这样的监控系统可以向 HPA 控制器公开针对特定应用程序的指标。

hpa 实现了一个控制环,可以周期性的从 Resource Metrics API 查询特定应用的 CPU 和内存信息。

5. 实战


以下是一份为 Kubernetes 1.9 或更高版本配置 HPA v2 的分步指南。首先将会安装提供核心指标的 Metrics Server 附件组件,然后使用一个 demo 来演示基于 CPU 和内存使用的 Pod 的自动伸缩。在指南的第二部分,将会部署 Prometheus 和一个 custom metrics apiserver。聚合层会自动注册 custom metrics apiserver,然后通过一个 demo 来演示自定义指标的 HPA。

前提

$ cd $GOPATH
$ git clone https://github.com/stefanprodan/k8s-prom-hpa


安装 Metrics Server

Kubernetes Metrics Server 是一个集群范围内的资源使用量的聚合器,它是 Heapster 的继承者。Metrics Server 通过汇集来自 kubernetes.summary_api 的数据来收集 node 和 pod 的 CPU 和内存使用情况。summary API 是用于将数据从 Kubelet/cAdvisor 传递到 Metrics Server 的高效内存 API。

在安装 Metrics Server 之前需要先进行如下配置:

  • 将 kube-controller-manager 的启动参数 --horizontal-pod-autoscaler-use-rest-clients 的值设置为 true。
  • 在 kube-controller-manager 的启动参数 –master 设置为 kube-apiserver 的地址,如:--master=http://172.20.0.113:8080

kube-system 命名空间部署 metrics-server:

$ kubectl create -f ./metrics-server

一分钟后,度量服务器开始报告节点和 Pod 的 CPU 和内存使用情况。 查看 nodes 指标:

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq .

查看 pods 指标:

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/pods" | jq .

基于 CPU 和内存使用的自动缩放

下面使用一个基于 golang 的小程序来测试 HPA。

default 命名空间中部署 podinfo:

$ kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yaml

可以通过 http://PODINFO_SVC_IP:9898 来访问 podinfo。

接下来定义一个保持最少两个副本的 HPA,如果 CPU 平均使用量超过 80% 或内存超过 200Mi,则最高可扩展到 10 个副本:

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: podinfo
spec:
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: podinfo
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 80
  - type: Resource
    resource:
      name: memory
      targetAverageValue: 200Mi

创建 HPA:

$ kubectl create -f ./podinfo/podinfo-hpa.yaml

几秒钟之后,HPA 控制器与 metrics server 进行通信,然后获取 CPU 和内存使用情况。

$ kubectl get hpa

NAME      REFERENCE            TARGETS                      MINPODS   MAXPODS   REPLICAS   AGE
podinfo   Deployment/podinfo   2826240 / 200Mi, 15% / 80%   2         10        2          5m

为了提高 CPU 使用率、运行 rakyll/hey 进行压力测试:

#install hey
$ go get -u github.com/rakyll/hey

#do 10K requests
hey -n 10000 -q 10 -c 5 http://PODINFO_SVC_IP:9898/

你可以通过以下命令获取 HPA event:

$ kubectl describe hpa podinfo

Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  7m    horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
  Normal  SuccessfulRescale  3m    horizontal-pod-autoscaler  New size: 8; reason: cpu resource utilization (percentage of request) above target

先将 podinfo 删除,稍后将会重新部署:

$ kubectl delete -f ./podinfo/podinfo-hpa.yaml,./podinfo/podinfo-dep.yaml,./podinfo/podinfo-svc.yaml

安装 Custom Metrics Server

为了让 HPA 可以根据 custom metrics 进行扩展,你需要有两个组件:

  • Prometheus : 从应用程序中收集指标并将其存储为 Prometheus 时间序列数据库。
  • custom-metrics-apiserver : 使用 k8s-prometheus-adapter 提供的 metrics 来扩展 Kubernetes 自定义指标 API。

创建 monitoring 命名空间:

$ kubectl create -f ./namespaces.yaml

将 Prometheus v2 部署到 monitoring 命名空间:

$ kubectl create -f ./prometheus

生成 Prometheus adapter 所需的 TLS 证书:

$ make certs

部署 custom-metrics-apiserver:

$ kubectl create -f ./custom-metrics-api

列出由 Prometheus 提供的自定义指标:

$ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .

获取 monitoring 命名空间中所有 pod 的 FS 信息:

$ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitoring/pods/*/fs_usage_bytes" | jq .

基于自定义指标的自动扩容

default 命名空间中部署 podinfo:

$ kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yaml

podinfo 应用暴露了一个自定义的度量指标:http_requests_total。Prometheus adapter(即 custom-metrics-apiserver)删除了 _total 后缀并将该指标标记为 counter metric

从自定义指标 API 获取每秒的总请求数:

$ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests" | jq .
{
  "kind": "MetricValueList",
  "apiVersion": "custom.metrics.k8s.io/v1beta1",
  "metadata": {
    "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/http_requests"
  },
  "items": [
    {
      "describedObject": {
        "kind": "Pod",
        "namespace": "default",
        "name": "podinfo-6b86c8ccc9-kv5g9",
        "apiVersion": "/__internal"
      },
      "metricName": "http_requests",
      "timestamp": "2018-01-10T16:49:07Z",
      "value": "901m"
    },
    {
      "describedObject": {
        "kind": "Pod",
        "namespace": "default",
        "name": "podinfo-6b86c8ccc9-nm7bl",
        "apiVersion": "/__internal"
      },
      "metricName": "http_requests",
      "timestamp": "2018-01-10T16:49:07Z",
      "value": "898m"
    }
  ]
}

m 表示 ,例如,901m 表示 901 毫次/每秒。

创建一个 HPA,如果请求数超过每秒 10 次将扩大 podinfo 副本数:

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: podinfo
spec:
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: podinfo
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metricName: http_requests
      targetAverageValue: 10

在 default 命名空间部署 podinfo HPA:

$ kubectl create -f ./podinfo/podinfo-hpa-custom.yaml

几秒钟后 HPA 从 metrics API 获取 http_requests 的值:

$ kubectl get hpa

NAME      REFERENCE            TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
podinfo   Deployment/podinfo   899m / 10   2         10        2          1m

以每秒 25 个请求数的速度给 podinfo 加压:

#install hey
$ go get -u github.com/rakyll/hey

#do 10K requests rate limited at 25 QPS
$ hey -n 10000 -q 5 -c 5 http://PODINFO_SVC_IP:9898/healthz

几分钟后,HPA 开始扩大 podinfo 的副本数:

$ kubectl describe hpa podinfo

Name:                       podinfo
Namespace:                  default
Reference:                  Deployment/podinfo
Metrics:                    ( current / target )
  "http_requests" on pods:  9059m / 10
Min replicas:               2
Max replicas:               10

Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  2m    horizontal-pod-autoscaler  New size: 3; reason: pods metric http_requests above target

以目前的请求速度,podinfo 的副本数永远不会扩展到最大值,三个副本足以让每个 Pod 的请求速度保持在每秒 10 次以下。

停止加压后,HPA 会将副本数缩减成最小值:

Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  5m    horizontal-pod-autoscaler  New size: 3; reason: pods metric http_requests above target
  Normal  SuccessfulRescale  21s   horizontal-pod-autoscaler  New size: 2; reason: All metrics below target

6. 总结


并非所有的系统都可以仅依靠 CPU 和内存指标来满足 SLA,大多数 Web 应用的后端都需要基于每秒的请求数量进行弹性伸缩来处理突发流量。对于 ETL 应用程序,可以通过设置 Job 队列长度超过某个阈值来触发弹性伸缩。通过 Prometheus 来监控应用程序并暴露出用于弹性伸缩的指标,可以微调应用程序以更好地处理突发事件,从而确保其高可用性。

7. 参考



扫一扫关注微信公众号


-----------他日江湖相逢 再当杯酒言欢-----------

「真诚赞赏,手留余香」

杨传胜

真诚赞赏,手留余香

使用微信扫描二维码完成支付

See Also