如何实现K8s Pod自定义指标弹性伸缩

弹性伸缩介绍

自动弹性伸缩(AutoScaling),是Kubernetes的一大功能和亮点。在OpenStack IaaS云计算中也有类似的服务,即Senlin。即基于资源使用情况自动弹性缩容和扩容工作负载。Kubernetes的自动弹性伸缩有两个维度:

  • Cluster Autoscaler:处理K8s集群Node节点伸缩,该功能依赖于IaaS云提供商云主机服务和资源监控服务。
  • Horizontal Pod Autoscaler(HPA):处理Pod自动弹性伸缩副本集,该功能依赖于监控服务采集到的资源指标数据。

简言之,Cluster Autoscaling和Horizontal Pod Autoscaler(HPA)可用于动态调整计算能力以满足系统SLA的要求。

通常,扩/缩容都是根据内存或者CPU资源的使用率实现,但是现实中,很多时候扩/缩容的依据通常是业务监控指标。如何根据业务监控指标来进行扩/缩容,将是本文探讨的内容。

自Kubernetes 1.11版本起,K8s资源采集指标由Resource Metrics API(Metrics Server 实现)和Custom metrics api(Prometheus实现)两种API实现,传统Heapster监控被废弃。前者主要负责采集Node、Pod的核心资源数据,如内存、CPU等;而后者则主要负责自定义指标数据采集,如网卡流量,磁盘IOPS、HTTP请求数、数据库连接数等。

Custom Metrics Server介绍

前面已提过,自heapster被废弃以后,所有的指标数据都从API接口中获取,由此kubernetes将资源指标分为了两种:

  • Core metrics(核心指标):由metrics-server提供API,即 metrics.k8s.io,仅提供Node和Pod的CPU和内存使用情况。
  • Custom Metrics(自定义指标):由Prometheus Adapter提供API,即 custom.metrics.k8s.io,由此可支持任意Prometheus采集到的自定义指标。

想让K8s的HPA,获取核心指标以外的其它自定义指标,则必须部署一套prometheus监控系统,让prometheus采集其它各种指标,但是prometheus采集到的metrics并不能直接给k8s用,因为两者数据格式不兼容,还需要另外一个组件(kube-state-metrics),将prometheus的metrics数据格式转换成k8s API接口能识别的格式,转换以后,因为是自定义API,所以还需要用Kubernetes aggregator在Master节点上的kube-apiserver中注册,以便直接通过/apis/来访问。

Custom Metrics组件介绍

  • node-exporter:prometheus的agent端,收集Node级别的监控数据。
  • prometheus:监控服务端,从node-exporter拉取数据并存储为时序数据。
  • kube-state-metrics: 将prometheus中可以用PromQL查询到的指标数据转换成k8s对应的数据格式,即转换成Custerom Metrics API接口格式的数据,但是它不能聚合进apiserver中的功能。
  • k8s-prometheus-adpater:聚合apiserver,即提供了一个apiserver(cuester-metrics-api),自定义APIServer通常都要通过Kubernetes aggregator聚合到apiserver。

Custom Metrics部署

获取部署文件

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

创建monitoring命名空间

 
# kubectl create -f ./namespaces.yaml

编辑prometheus部署文件

 
# vim ./prometheus/prometheus-dep.yaml
image: prom/prometheus:v2.1.0
//修改为image: prom/prometheus:v2.5.0

将 Prometheus部署到monitoring命名空间

 
# kubectl create -f ./prometheus

生成由Prometheus adapter所需的TLS证书

 
# make certs

编辑custom-metrics-apiserve部署文件

 
# vim ./custom-metrics-api/custom-metrics-apiserver-deployment.yaml
- --prometheus-url=http://prometheus.monitoring.svc.cluster.local:9090/      
//将该参数修改为Prometheus的 service域名地址
 
image: quay.io/coreos/k8s-prometheus-adapter-amd64:v0.2.0
//修改为image: quay.io/coreos/k8s-prometheus-adapter-amd64:v0.4.1

部署Prometheus自定义api适配器

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

列出由prometheus提供的自定义指标

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

查看创建的namespace

 
# kubectl get namespace
NAME             STATUS   AGE
default          Active   10d
kube-public      Active   10d
kube-system      Active   10d
monitoring       Active   6d23h

查看创建的pod

 
# kubectl get pods -n monitoring
NAME                                        READY   STATUS    RESTARTS   AGE
custom-metrics-apiserver-855cbf8644-6qhmv   1/1     Running   0          2d21h
prometheus-788f78d959-xs74p                 1/1     Running   0          2d21h

查看创建的service

 
# kubectl get svc -n monitoring
NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
custom-metrics-apiserver   ClusterIP   10.233.7.116   <none>        443/TCP          2d21h
prometheus                 NodePort    10.233.49.23   <none>        9090:30090/TCP   2d21h

到了这里,我们便可以通过 http://节点IP:30090方式访问Prometheus页面。

查看新创建的api群组

 
# kubectl api-versions  | grep metrics
custom.metrics.k8s.io/v1beta1
metrics.k8s.io/v1beta1

列出由prometheus提供的自定义指标

 
# yum -y install jq

# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "custom.metrics.k8s.io/v1beta1",
  "resources": [.............]               //输出信息太多,此处省略
}

列示Pod 上的Prometheus 适配器所提供的缺省定制指标。

 
#  kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .  |grep "pods/"

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

 
#  kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitoring/pods/*/fs_usage_bytes" | jq .
{
  "kind": "MetricValueList",
  "apiVersion": "custom.metrics.k8s.io/v1beta1",
  "metadata": {
    "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitoring/pods/%2A/fs_usage_bytes"
  },
  "items": [
    {
      "describedObject": {
        "kind": "Pod",
        "namespace": "monitoring",
        "name": "custom-metrics-apiserver-855cbf8644-6qhmv",
        "apiVersion": "/__internal"
      },
      "metricName": "fs_usage_bytes",
      "timestamp": "2019-01-15T14:14:22Z",
      "value": "233570304"
    },
    {
      "describedObject": {
        "kind": "Pod",
        "namespace": "monitoring",
        "name": "prometheus-788f78d959-xs74p",
        "apiVersion": "/__internal"
      },
      "metricName": "fs_usage_bytes",
      "timestamp": "2019-01-15T14:14:22Z",
      "value": "36864"
    }
  ]
}

验证

创建一个使用Custom Metrics APIs的Pod,来验证自定义指标弹性伸缩功能。

 
# cd k8s-prom-hpa/

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

在default命名空间中创建podinfo服务,podinfo应用程序暴露了一个自定义的指标,即http_requests。

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

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

 
# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests" | jq .

m代表milli-units,例如,901m 意味着901 milli-requests (就是大约0.9个请求)。

创建一个HPA,如果请求数超过每秒10,将扩容podinfo这个Pod的副本数。

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

过几秒钟HPA从自定义指标API取得http_requests的值:

 
# kubectl get hpa
NAME      REFERENCE            TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
podinfo   Deployment/podinfo   899m / 10   2         10        2          1m

用每秒25次请求数给podinfo服务加压
安装hey

 
# go get -u github.com/rakyll/hey
# hey -n 10000 -q 5 -c 5 http://<K8S-IP>:31198/healthz

几分钟后,HPA开始扩容该Pod副本数。

 
# kubectl describe hpa
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

可看到,在当前压力测试下,Pod副本将自动扩容到三副本,但不会超过10副本这个最大值。同时三副本Pod已经满足当前负载。

负载测试结束后,HPA向下自动缩容到1个副本Pod。

 
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

后续

custom metrics大大丰富了K8s pod弹性伸缩的能力,使K8s Pod AutoScaling从资源伸缩向业务应用伸缩方向转变成为现实。限于篇幅,后面将介绍部署Grafana+Influxdb集成Prometheus可视化查看K8s集群资源使用情况。

此外,在生产环境中,应当使用NFS、hostPath等方式持久化存储Prometheus监控数据。

参考资料:
https://github.com/stefanprodan/k8s-prom-hpa

转载自:https://xuchao918.github.io/2019/01/10/如何实现K8s-Pod自定义指标弹性伸缩/

发布了39 篇原创文章 · 获赞 247 · 访问量 103万+

猜你喜欢

转载自blog.csdn.net/zhongbeida_xue/article/details/105067793