弹性伸缩介绍
自动弹性伸缩(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部署
获取部署文件
12 | # git clone https://github.com/stefanprodan/k8s-prom-hpa# cd k8s-prom-hpa/ |
创建monitoring命名空间
1 | # kubectl create -f ./namespaces.yaml |
编辑prometheus部署文件
123 | # vim ./prometheus/prometheus-dep.yamlimage: prom/prometheus:v2.1.0//修改为image: prom/prometheus:v2.5.0 |
将 Prometheus部署到monitoring命名空间
1 | # kubectl create -f ./prometheus |
生成由Prometheus adapter所需的TLS证书
1 | # make certs |
编辑custom-metrics-apiserve部署文件
123456 | # 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适配器
1 | # kubectl create -f ./custom-metrics-api |
列出由prometheus提供的自定义指标
1 | # kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq . |
查看创建的namespace
123456 | # kubectl get namespaceNAME STATUS AGEdefault Active 10dkube-public Active 10dkube-system Active 10dmonitoring Active 6d23h |
查看创建的pod
1234 | # kubectl get pods -n monitoringNAME READY STATUS RESTARTS AGEcustom-metrics-apiserver-855cbf8644-6qhmv 1/1 Running 0 2d21hprometheus-788f78d959-xs74p 1/1 Running 0 2d21h |
查看创建的service
1234 | # kubectl get svc -n monitoringNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEcustom-metrics-apiserver ClusterIP 10.233.7.116 <none> 443/TCP 2d21hprometheus NodePort 10.233.49.23 <none> 9090:30090/TCP 2d21h |
到了这里,我们便可以通过 http://节点IP:30090方式访问Prometheus页面。
查看新创建的api群组
123 | # kubectl api-versions | grep metricscustom.metrics.k8s.io/v1beta1metrics.k8s.io/v1beta1 |
列出由prometheus提供的自定义指标
123456789 | # 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 适配器所提供的缺省定制指标。
1 | # kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq . |grep "pods/" |
获取monitoring命名空间中所有pod的fs_usage_bytes信息
1234567891011121314151617181920212223242526272829303132 | # 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,来验证自定义指标弹性伸缩功能。
1 | # cd k8s-prom-hpa/ |
podinfo 应用暴露了一个自定义的度量指标:http_requests_total。Prometheus adapter(即 custom-metrics-apiserver)删除了 _total 后缀并将该指标标记为 counter metric。
在default命名空间中创建podinfo服务,podinfo应用程序暴露了一个自定义的指标,即http_requests。
1 | # kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yaml |
从自定义指标API获取每秒的总请求数:
1 | # 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的副本数。
1 | # kubectl create -f ./podinfo/podinfo-hpa-custom.yaml |
过几秒钟HPA从自定义指标API取得http_requests的值:
123 | # kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEpodinfo Deployment/podinfo 899m / 10 2 10 2 1m |
用每秒25次请求数给podinfo服务加压
安装hey
12 | # go get -u github.com/rakyll/hey# hey -n 10000 -q 5 -c 5 http://<K8S-IP>:31198/healthz |
几分钟后,HPA开始扩容该Pod副本数。
12345678910111213 | # kubectl describe hpaName: podinfoNamespace: defaultReference: Deployment/podinfoMetrics: ( current / target ) "http_requests" on pods: 9059m / 10Min replicas: 2Max replicas: 10Events: 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。
12345 | 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监控数据。