K8S弹性伸缩之基于Metrics Server CPU指标的HPA
基于CPU指标缩放
1、 Kubernetes API Aggregation
什么是k8sapi聚合?
它是允许k8s的开发人员编写一个自己的服务,可以把这个服务注册到k8s的api里面,这样,就像k8s自己的api一样,你的服务只要运行在k8s集群里面,k8s 的Aggregate通过service名称就可以转发到你写的service里面去了。
当然看如下图↓:你也可以把agg当作一个nginx的反代,它就是代理层。
在 Kubernetes 1.7 版本引入了聚合层,允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个 API 聚合层(API Aggregation Layer),用于将扩展 API 的访问请求转发到用户服务的功能。

当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。
如果你使用kubeadm部署的,默认已开启。如果你使用==二进制方式部署==的话,需要在kube-APIServer中添加启动参数,增加以下配置:
# vi /opt/kubernetes/cfg/kube-apiserver.conf
...
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
--proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem \
--requestheader-allowed-names=kubernetes \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \
...
在设置完成重启 kube-apiserver 服务,就启用 API 聚合功能了。
2、部署 Metrics Server
Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。
Metric server从每个节点上Kubelet公开的摘要API收集指标。
Metrics server通过Kubernetes聚合器注册在Master APIServer中。

# git clone https://github.com/kubernetes-incubator/metrics-server
# cd metrics-server/deploy/1.8+/
# vi metrics-server-deployment.yaml # 添加2条启动参数
...
containers:
- name: metrics-server
image: zhdya/metrics-server-amd64:v0.3.1
command:
- /metrics-server
- --kubelet-insecure-tls ##忽略证书的验证
- --kubelet-preferred-address-types=InternalIP ##一般node都是用主机名注册的,但是metricserver是通过pod启动的,解析不到hostname,所以需要采集节点的IP
...
# kubectl create -f .
可通过Metrics
API在Kubernetes中获得资源使用率指标,例如容器CPU和内存使用率。这些度量标准既可以由用户直接访问(例如,通过使用kubectl top
命令),也可以由集群中的控制器(例如,Horizontal
Pod Autoscaler)用于进行决策。
[root@k8s-master1 metrics-server]# kubectl get po -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-6d8cfdd59d-pbbbc 1/1 Running 0 131m 10.244.2.2 k8s-node2 <none> <none>
kube-flannel-ds-amd64-4gj8p 1/1 Running 1 142m 192.168.171.11 k8s-master1 <none> <none>
kube-flannel-ds-amd64-k5lfh 1/1 Running 1 75m 192.168.171.14 k8s-node3 <none> <none>
kube-flannel-ds-amd64-kddhv 1/1 Running 1 142m 192.168.171.12 k8s-node1 <none> <none>
kube-flannel-ds-amd64-q8g25 1/1 Running 1 141m 192.168.171.13 k8s-node2 <none> <none>
metrics-server-7dbbcf4c7-v5zpm 1/1 Running 0 49s 10.244.2.4 k8s-node2 <none> <none>
查看是否注册到apiservice
[root@k8s-master1 metrics-server]# kubectl get apiservice
v1beta1.metrics.k8s.io kube-system/metrics-server True 3m22s
测试:
[root@k8s-master1 metrics-server]# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[{"metadata":{"name":"k8s-master1","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-master1","creationTimestamp":"2019-12-10T15:41:01Z"},"timestamp":"2019-12-10T15:40:34Z","window":"30s","usage":{"cpu":"104718141n","memory":"1158508Ki"}},{"metadata":{"name":"k8s-node1","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-node1","creationTimestamp":"2019-12-10T15:41:01Z"},"timestamp":"2019-12-10T15:40:26Z","window":"30s","usage":{"cpu":"61460193n","memory":"556328Ki"}},{"metadata":{"name":"k8s-node2","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-node2","creationTimestamp":"2019-12-10T15:41:01Z"},"timestamp":"2019-12-10T15:40:32Z","window":"30s","usage":{"cpu":"57896643n","memory":"570056Ki"}},{"metadata":{"name":"k8s-node3","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-node3","creationTimestamp":"2019-12-10T15:41:01Z"},"timestamp":"2019-12-10T15:40:30Z","window":"30s","usage":{"cpu":"30890872n","memory":"403264Ki"}}]}
[root@k8s-master1 metrics-server]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master1 105m 5% 1131Mi 65%
k8s-node1 62m 3% 543Mi 31%
k8s-node2 58m 2% 556Mi 32%
k8s-node3 31m 1% 393Mi 22%
[root@k8s-master1 metrics-server]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
web-944cddf48-4x6qr 0m 3Mi
web-944cddf48-64d7r 0m 2Mi
web-944cddf48-hjwng 0m 3Mi
web-944cddf48-skh82 0m 3Mi
3、autoscaling/v1(CPU指标实践)
autoscaling/v1版本只支持CPU一个指标。
首先部署一个应用:
[root@k8s-master1 hpa]# kubectl run web --image=nginx --replicas=8 --requests="cpu=100m,memory=100Mi" --expose 80 --port 80 --dry-run -o yaml >app.yaml
创建HPA策略:
[root@k8s-master1 hpa]# kubectl autoscale deployment web --min=2 --max=8 -o yaml --dry-run >hpav1.yaml
[root@k8s-master1 hpa]# kubectl apply -f hpav1.yaml
horizontalpodautoscaler.autoscaling/web created
###cat hpav1.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
maxReplicas: 8
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
targetCPUUtilizationPercentage: 60
scaleTargetRef:表示当前要伸缩对象是谁
targetCPUUtilizationPercentage:当整体的资源利用率超过50%的时候,会进行扩容。
查看当前状态:
[root@k8s-master1 hpa]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web 0%/60% 2 8 3 24s
开启压测:
# yum install httpd-tools
# ab -n 100000 -c 100 http://10.1.206.176/status.php
10.0.0.147 为ClusterIP。
检查扩容状态:
# kubectl get hpa
# kubectl top pods
# kubectl get pods
[root@k8s-master1 hpa]# ab -n 1000000 -c 1000 http://10.0.0.201/index.html ##压测
关闭压测,过一会检查缩容状态。
[root@k8s-master1 ~]# kubectl top po
NAME CPU(cores) MEMORY(bytes)
web-77cfdb7c6c-dpm5t 116m 5Mi
web-77cfdb7c6c-lwkbj 343m 5Mi
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-77cfdb7c6c-94p6x 1/1 Running 0 7s
web-77cfdb7c6c-9xwbj 1/1 Running 0 23s
web-77cfdb7c6c-dpm5t 1/1 Running 0 33m
web-77cfdb7c6c-gpk6d 1/1 Running 0 7s
web-77cfdb7c6c-l7b4r 1/1 Running 0 23s
web-77cfdb7c6c-lwkbj 1/1 Running 0 33m
web-77cfdb7c6c-w6lz6 1/1 Running 0 7s
web-77cfdb7c6c-wpzb5 1/1 Running 0 7s
==工作流程==:hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)
4、autoscaling/v2beta2(多指标)
为满足更多的需求, HPA 还有 autoscaling/v2beta1和 autoscaling/v2beta2两个版本。
这两个版本的区别是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(应用程序指标),而在 autoscaling/v2beta2的版本中额外增加了 External Metrics的支持。
# kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: web
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 1
maxReplicas: 10
metrics:
- resource:
type: Resource
name: cpu
target:
averageUtilization: 60
type: Utilization
与上面v1版本效果一样,只不过这里格式有所变化。
v2还支持其他另种类型的度量指标,:Pods和Object。
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
metrics中的type字段有四种类型的值:Object、Pods、Resource、External。
Resource:指的是当前伸缩对象下的pod的cpu和memory指标,只支持Utilization和AverageValue类型的目标值。
Object:指的是指定k8s内部对象的指标,数据需要第三方adapter提供,只支持Value和AverageValue类型的目标值。
Pods:指的是伸缩对象Pods的指标,数据需要第三方的adapter提供,只允许AverageValue类型的目标值。
External:指的是k8s外部的指标,数据同样需要第三方的adapter提供,只支持Value和AverageValue类型的目标值。
# hpa-v2.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: web
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
==工作流程==:hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!