自动弹性伸缩(AutoScaling),是Kubernetes的一大功能和亮点。在OpenStack IaaS云计算中也有类似的服务,即Senlin。即基于资源使用情况自动弹性缩容和扩容工作负载。Kubernetes的自动弹性伸缩有两个维度:
简言之,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请求数、数据库连接数等。
前面已提过,自heapster被废弃以后,所有的指标数据都从API接口中获取,由此kubernetes将资源指标分为了两种:
想让K8s的HPA,获取核心指标以外的其它自定义指标,则必须部署一套prometheus监控系统,让prometheus采集其它各种指标,但是prometheus采集到的metrics并不能直接给k8s用,因为两者数据格式不兼容,还需要另外一个组件(kube-state-metrics),将prometheus的metrics数据格式转换成k8s API接口能识别的格式,转换以后,因为是自定义API,所以还需要用Kubernetes aggregator在Master节点上的kube-apiserver中注册,以便直接通过/apis/来访问。
获取部署文件
1 2 |
# git clone https://github.com/stefanprodan/k8s-prom-hpa # cd k8s-prom-hpa/ |
创建monitoring命名空间
1 |
# kubectl create -f ./namespaces.yaml |
编辑prometheus部署文件
1 2 3 |
# vim ./prometheus/prometheus-dep.yaml image: 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部署文件
1 2 3 4 5 6 |
# 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
1 2 3 4 5 6 |
# kubectl get namespace NAME STATUS AGE default Active 10d kube-public Active 10d kube-system Active 10d monitoring Active 6d23h |
查看创建的pod
1 2 3 4 |
# 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
1 2 3 4 |
# kubectl get svc -n monitoring NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE custom-metrics-apiserver ClusterIP 10.233.7.116 |
到了这里,我们便可以通过 http://节点IP:30090方式访问Prometheus页面。
查看新创建的api群组
1 2 3 |
# kubectl api-versions | grep metrics custom.metrics.k8s.io/v1beta1 metrics.k8s.io/v1beta1 |
列出由prometheus提供的自定义指标
1 2 3 4 5 6 7 8 9 |
# 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信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# 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的值:
1 2 3 |
# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE podinfo Deployment/podinfo 899m / 10 2 10 2 1m |
用每秒25次请求数给podinfo服务加压
安装hey
1 2 |
# go get -u github.com/rakyll/hey # hey -n 10000 -q 5 -c 5 http:// |
几分钟后,HPA开始扩容该Pod副本数。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 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。
1 2 3 4 5 |
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监控数据。