K8S – HPA自动弹性伸缩容
上K8S并不能直接带来成本的降低,除非实现自动弹性伸缩容。
自动弹性伸缩容包含了2个层面,只有同时实现才能降低成本:
- Pod级:根据POD的资源负载,自动增加/减少Pod数量。
- Node级:根据Node的资源负载,自动增加/减少Node数量。
Pod级弹性依靠K8S官方自带方案HPA(Horizontal Pod Autoscaler)即可解决。
而Node级弹性则需要与IAAS平台联动实现虚拟机的动态添加与摘除,我们叫做CA(Cluster Autoscaler),开源项目已经支持了AWS/Google/Aliyun/Baiduyun等主流平台,国内云平台估计各自进行了二次开发适配自己的IAAS虚拟化平台。
我公司选择是ucloud云平台托管的K8S集群,所以只需要在ucloud后台点点鼠标把它的CA配置并部署到K8S集群里即可。
因此,这篇博客主要讲讲HPA,原生K8S自带的POD水平伸缩容方案。
搭建minikube环境
顺便说说K8S的实验环境问题。
推荐大家自己整一台虚拟机,下载一个minikube做实验,而不是安装一个复杂的K8S集群。
minikue安装步骤很简单:
- 安装docker ce
- 安装minikube
- 配置minikube插件
- 启动minikube
- 下载kubectl二进制(minikube不包含命令行工具,所以需要单独安装,见链接)
minikube提供了一个addon插件机制,很多K8S组件不用自己去创建YAML,直接安装addon即可,比如:metrics-server、dashboard只需要安装一下插件就可以使用了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
root@debian:~/hpa# minikube addons list - addon-manager: enabled - dashboard: disabled - default-storageclass: enabled - efk: disabled - freshpod: disabled - gvisor: disabled - helm-tiller: disabled - ingress: disabled - ingress-dns: disabled - logviewer: disabled - metrics-server: enabled - nvidia-driver-installer: disabled - nvidia-gpu-device-plugin: disabled - registry: disabled - registry-creds: disabled - storage-provisioner: enabled - storage-provisioner-gluster: disabled |
HPA依赖metrics-server提供的POD级CPU/MEM监控数据,所以必须部署metrics-server:
minikube addons enable metrics-server
记得安装完插件重新启动minikube,相关命令:
1 2 3 4 |
# 启动 minikube start --vm-driver=none --image-mirror-country='cn' # 停止 minikube stop |
启动minikube很有学问:
- –vm-driver:指定none才会使用docker作为runc。
- –image-mirror:指定cn会使用国内源下载docker镜像,否则你会被墙的死去活来。
如果你遵照我说的搭建,一切都将非常顺利。
HPA资料
我从2个渠道了解了HPA:
- ucloud官方文档:https://docs.ucloud.cn/compute/uk8s/bestpractice/autoscaling/hpa
- k8s官方文档:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
大家读完博客之后,可以按需再详细看一遍。
使用示例
我们首先需要deployment一个应用,然后为这个deployment创建一个HPA对象,此后该HPA对象会监督该deployment的POD负载并弹性伸缩POD数量。
创建deployment
1 |
kubectl apply -f https://docs.ucloud.cn/compute/uk8s/yaml/hpa/hpa-example.yaml |
这个YAML部署了一个PHP应用,以及对应的service负载均衡:
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 33 34 35 36 37 38 39 40 41 |
root@debian:~/hpa# cat hpa-example.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hpa-example labels: app: hpa-example spec: replicas: 5 selector: matchLabels: app: hpa-example template: metadata: labels: app: hpa-example spec: containers: - name: hpa-example image: uhub.service.ucloud.cn/testforfun/hpa-example:v1 ports: - containerPort: 80 resources: requests: cpu: 1 --- apiVersion: v1 kind: Service metadata: name: hpa-example labels: app: hpa-example spec: selector: app: hpa-example ports: - protocol: TCP name: http port: 80 targetPort: 80 type: ClusterIP |
我们重点关注到2个配置项,稍后有用:
- replicas指定了5个POD
- requests指定了最低要求1核CPU
目前已经拉起5个POD(因为我机器只有4核,而每个POD requests了1核,所以有部分POD资源不足无法拉起):
1 2 3 4 5 6 7 |
root@debian:~/hpa# kubectl get pods NAME READY STATUS RESTARTS AGE hpa-example-67778f9bf5-2pkxg 1/1 Running 0 3m32s hpa-example-67778f9bf5-jfx8s 0/1 Pending 0 3m32s hpa-example-67778f9bf5-kpkfh 1/1 Running 0 3m33s hpa-example-67778f9bf5-n2f44 1/1 Running 0 3m33s hpa-example-67778f9bf5-pfm9s 0/1 Pending 0 3m33s |
然而这些POD目前压根没有负载压力,属于资源浪费状态:
1 2 3 4 5 |
root@debian:~/hpa# kubectl top pod NAME CPU(cores) MEMORY(bytes) hpa-example-67778f9bf5-2pkxg 0m 9Mi hpa-example-67778f9bf5-kpkfh 0m 9Mi hpa-example-67778f9bf5-n2f44 0m 9Mi |
POD的CPU使用为0,内存占用9M,目前有3个POD在running。
如果这时候能有弹性伸缩把POD数量降下来,不就可以让出很多闲置资源了吗?
配置HPA
因此,我们为这个deployment配置1个HPA对象,让它负责弹性伸缩该部署。
1 |
kubectl apply -f https://docs.ucloud.cn/compute/uk8s/yaml/hpa/hpa.yaml |
这个hpa.yaml里面定义了一个HPA对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
root@debian:~/hpa# cat hpa.yaml apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-exmaple namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpa-example minReplicas: 1 maxReplicas: 2 targetCPUUtilizationPercentage: 50 |
其位于autocaling/v1下面,类型是HorizontalPodAutoscaler,核心配置如下:
- scaleTargetRef:指定要弹性伸缩哪个资源,这里就是指定了上述deployment。(注意:hpa必须和target处于一个namespace下面。
- min/maxReplicas:指定伸缩之后最少以及最多的POD数量,这里指定了1~2个POD。
- targetCPUUtilizationPercentage:指定了POD的CPU使用率阈值,一旦超过50%就新增POD,直到所有POD的平均CPU使用率低于50%或者POD数量先到达了maxReplicas。
我们可以查看HPA的信息:
1 2 3 |
root@debian:~/.minikube# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpa-exmaple Deployment/hpa-example 0%/50% 1 2 1 38m |
TARGET说明了所有POD的平均CPU使用率以及我们指定的阈值50%之间的关系,同时也观察到HPA已经将deployment的replicas从5个调低为1个了。
我们可以查看一下实际POD信息:
1 2 3 |
root@debian:~/hpa# kubectl get pods NAME READY STATUS RESTARTS AGE hpa-example-67778f9bf5-kpkfh 1/1 Running 0 13m |
说明HPA在缩容方面的确有效。
验证扩容
只需要给POD造成请求压力,令其CPU打高超过50%使用率(相对于request的1核计算),那么HPA会很快弹性扩容。
1 |
kubectl apply -f https://docs.ucloud.cn/compute/uk8s/yaml/hpa/load.yaml |
该YAML部署了一个死循环请求PHP的压测客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
root@debian:~/hpa# cat load.yaml apiVersion: apps/v1 kind: Deployment metadata: name: load-generator labels: app: load-generator spec: replicas: 1 selector: matchLabels: app: load-generator template: metadata: labels: app: load-generator spec: containers: - name: load-generator image: uhub.service.ucloud.cn/library/busybox:latest command: - "sh" - "-c" - "while true; do wget -q -O- http://hpa-example.default.svc.cluster.local; done" |
所以,现在查看HPA已经从1个POD扩容到上限2个POD(耐心等待,因为metrics-server采集以及HPA检测资源利用率是周期性间隔的):
1 2 3 |
root@debian:~/hpa# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpa-exmaple Deployment/hpa-example 0%/50% 1 2 2 39s |
控制HPA行为
如果你实际使用的话,应该会感受到HPA在压力突变后响应动作是有延迟的,这是受到HPA调度算法的影响,可以通过参数调节。
有一些参数已经废弃了,我讲的都是最新的状态。
阅读后续内容?
你必须付费加入我的知识星球,为有效知识付费是对作者最好的回报。
二维码见下方 或者 右侧边栏。

1
1