the site subtitle

Kubernetes 中的弹性伸缩 Autoscaler

2018.09.25

弹性伸缩是一个比较吸引人的话题,类似与云计算中所提倡的按需付费,合理使用可以减少所需计算资源,降低相关的服务器成本。对于k8s来说目前一共有两种弹性伸缩:

  1. Cluster 即自动增加删除节点
  2. Pod 分为水平和垂直两种,水平伸缩在k8s里已经支持,垂直伸缩需要安装

相关repo https://github.com/kubernetes/autoscaler ,下面分别介绍下相关信息。

Node

Cluster-autoscaler

ClusterScaler安装相对来说比较简单,和其他插件类似,定义好ServiceAccount,Deployment以及伸缩组等即可,但是比较强依靠公有云。目前支持的AliCloud,Azure,AWS,BaiduCloud等,注意需要配置Access Key以及根证书(访问API时需要)等信息。关键配置如下:

            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --scale-down-delay-after-add=3m
            - --nodes=1:5:nodes.demo.k8s.local

按照正常步骤,向集群添加节点一共需要三步:

  1. 新开一台机器,
  2. 配置bootstap token等信息,
  3. 最后加入集群。

ClusterScaler相当于替我们做了这些工作,仔细阅读相关文档,可以看到阿里云依赖的是ESS,而kops下的aws依赖的是ASG(auto scaling group),通过自动伸缩组可以几乎无干预的完成扩容。

这里穿插一个小知识,对于大多数公有云来说,都支持一个叫做cloud-init的东西,也叫做user data,也就是在机器初始化的时候执行的一段shell脚本,这也就是上面的第二步。

那么它是如何判断集群需要扩容、缩容呢?我们先启动一个request为4C8G的nginx做测试,或者是5个1C2G的nginx,目的就是超过现有集群剩余的计算资源,正常情况下一定会有pod处于pending状态,这时候通过观察日志可以发现,ClusterScaler就会触发扩容节点。

I0408 04:46:52.022024       1 scale_up.go:249] Pod default/demo-589b486fbb-r5fn4 is unschedulable
I0408 04:46:52.022039       1 scale_up.go:249] Pod default/demo-589b486fbb-rzlpn is unschedulable

源码在https://github.com/kubernetes/autoscaler/blob/cluster-autoscaler-1.2.2/cluster-autoscaler/core/scale_up.go#L59

Pod

HPA 水平伸缩

现在官方支持的就是HorizontalPodAutoscaler,可以根据CPU和memory使用情况来判断伸缩,需要注意的是,伸缩的条件是CPU利用率超过多少就触发扩容,所以至少需要两个参数,pod现在的CPU,以及它request的CPU, 所以我们首先需要部署metric-server,用来获取pod的实时CPU使用情况。 https://github.com/kubernetes-incubator/metrics-server

kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/aggregated-metrics-reader.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/auth-delegator.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/auth-reader.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/metrics-apiservice.yaml
# 可以修改下镜像
kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/metrics-server-deployment.yaml
 
kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/metrics-server-service.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes-incubator/metrics-server/master/deploy/1.8%2B/resource-reader.yaml

报错一

> unable to fully collect metrics: unable to fully scrape metrics from source kubelet_summary:east1-monitor1: unable to fetch metrics from Kubelet xxx: Get https://xxx1:10250/stats/summary/: dial tcp: lookup xxx on 10.96.0.10:53: no such host

修改Deployment,加上

      - args:
        - --kubelet-preferred-address-types=InternalIP
        - --kubelet-insecure-tls

完成之后执行 kubectl top po 或者kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"命令应该会返回一串json,那就是安装完成了。接下来我们就试着用hpa来实现Pod水平扩容。

首先运行一个nginx的pod

kubectl run nginx --image=nginx:alpine --port=80 --requests='cpu=20m,memory=20m'

接着规定CPU超过80%就扩容,最多为3个

# kubectl autoscale deployment nginx --max=3 --cpu-percent=20
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  creationTimestamp: "2019-05-26T11:09:52Z"
  name: nginx
spec:
  maxReplicas: 3
  minReplicas: 1
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: nginx
  targetCPUUtilizationPercentage: 80
status:
  currentReplicas: 0
  desiredReplicas: 0
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: podinfo
spec:
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: podinfo
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 80
  - type: Resource
    resource:
      name: memory
      targetAverageValue: 200Mi

然后我们使用工具去压测一下Nginx,这里用的是vegeta

echo "GET http://10.244.0.16" | vegeta attack -rate=1000 -duration=50s | tee results.bin | vegeta report`

# 查看hpa情况。已经严重超过目标值了
kubectl get hpa
NAME    REFERENCE          TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
nginx   Deployment/nginx   1075%/20%   1         3         3          4m52s

# 已经扩容了
kubectl get po
NAME                    READY   STATUS    RESTARTS   AGE
nginx-584fd85d4-bdvbj   1/1     Running   0          22s
nginx-584fd85d4-hg6hl   1/1     Running   0          22m
nginx-584fd85d4-sntkc   1/1     Running   0          22s

VPA 垂直扩容

TODO

###Custom Metrics自定义指标

metrics在微服务的监控体系运用的可谓是相当广泛,仅依靠Pod的CPU就做扩容可能有些不是很完善,更符合的是依靠服务质量来扩容,比如90%的请求都是5s才返回,于是custom metrics就诞生了,它扩展了新的API Server Groupcustom.metrics.k8s.io,相关repo: https://github.com/stefanprodan/k8s-prom-hpa,需要注意的是生成证书的环节。

├── cm-adapter-serving-certs.yaml
├── custom-metrics-apiserver-auth-delegator-cluster-role-binding.yaml
├── custom-metrics-apiserver-auth-reader-role-binding.yaml
├── custom-metrics-apiserver-deployment.yaml
├── custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
├── custom-metrics-apiserver-service-account.yaml
├── custom-metrics-apiserver-service.yaml
├── custom-metrics-apiservice.yaml
├── custom-metrics-cluster-role.yaml
├── custom-metrics-config-map.yaml
├── custom-metrics-resource-reader-cluster-role.yaml
└── hpa-custom-metrics-cluster-role-binding.yaml

如下是一个http_requests 超过10 就扩容的scaler定义,可以使用上面的命令再次压测一下。

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: podinfo
spec:
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: podinfo
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metricName: http_requests
      targetAverageValue: 10

Ref