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 的访问请求转发到用户服务的功能。

mark

当你访问 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中。

mark
# 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