10 HPA 自动伸缩控制器
kubectl autoscale 自动控制在k8s集群中运行的 pod 数量(水平自动伸缩),需要提前设置 pod 范围及触发条件。
k8s 从1.1 版本开始增加了名称为 HPA(Horizontal Pod Autoscaler) 的控制器,用于实现基于 pod 中资源(CPU/Memory) 利用率进行对 pod 的自动扩缩容功能的实现,早期的版本只能基于 Heapster 组件实现对CPU利用率做为触发条件,但是在 k8s 1.11版本开始使用 Metrices Server 完成数据采集,然后将采集到的数据通过 API (AggregatedAPI, 汇总API) , 例如 metrics.k8s.io、 custom.metrics.k8s.io、 external.metrics.k8s.io, 然后再把数据提供给HPA控制器进行查询,以实现基于某个资源利用率对pod进行扩缩容的目的。
10.1 Pod 水平自动扩缩
Pod 水平自动扩缩(Horizontal Pod Autoscaler) 可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。 除了 CPU 利用率,也可以基于其他应程序提供的 自定义度量指标 来执行自动扩缩。 Pod 自动扩缩不适用于无法扩缩的对象,比如 DaemonSet。
Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。 控制器会周期性地调整副本控制器或 Deployment 中的副本数量,以使得类似 Pod 平均 CPU 利用率、平均内存利用率这类观测到的度量值与用户所设定的目标值匹配。
如果现在 pod 数限制为最小 2 个,即使我调成 5 个,过段时间他也会基于 pod 利用率来实现动态伸缩改为 2 个 pod,因为访问量不大,pod 利用率很低,这个时候就会降低我们的 pod 副本。但是如果访问流量上来之后他发现 pod 的 CPU 利用率上来了 HPA 又可能将其改为三个或者 4 个 pod,但是最多只有五个 pod
Pod 水平自动扩缩器的实现是一个控制回路,由控制器管理器的 --horizontal-pod-autoscaler-sync-period 参数指定周期(默认值为 15 秒,可以人为调整但是一般不会修改)查询 metrics 的资源使用情况。
支持一下三种 metrics 指标类型:
1.预定义 metrics (比如 pod 的 cpu) 利用率的方式计算
2.自定义 pod metrics ,以原始值(raw value)的方式计算
3.自定义 object metrics
支持两种 metrics 查询方式:
1.Heapstre
2.自定义的 REST API
支持多 metrics ,可以基于 Prometheus 查到的数据来实现对 pod 缩容
10.2 Pod 水平自动扩缩工作机制
对于 pod 数的调整,我们可以通过命令或者修改 yaml 文件进行调整,但是这些操作都是人为手动调整,而无法做到在访问高峰期让我们的 pod 横向扩容
比如在访问高峰期我们希望我们的 pod 数能够实现自动的扩容,而且在访问量比较低的时候能够实现自动的缩容,这个时候就需要使用到 HPA 控制器
HPA 创建方式:
- 命令行
- yaml 文件
- K8S API
HPA 伸缩原理
具体伸缩的方式就是上面的这张图,图中是通过 kubectl autoscale deployment foo --min=2 --max=5 --cpu-percent=80
命令,创建一个 HPA 控制器,类型是一个 foo 的 deployment 并且最大是 5 个 pod,最小 2 个 pod,而且实在 cpu 利用率在百分之 80 的时候触发,如果 pod cpu 利用率超过了百分之 80 就会扩容 pod ,直到 cpu 利用率低于 80 为止
如果该 deployment 中的 pod 运行一段时间后 CPU 利用率降低了,HPA 会自动将该 deployment 中的 pod 自动删掉两个,如果说后来高峰期访问量又上去了原有的 pod CPU 利用率升高到达 80% 他又会自动的进行扩容
所以我们需要对那个范围和那种控制器类型进行 HPA 创建,创建好之后就会生产一个 HPA 控制器,HPA 控制器会基于 API server 每隔多少秒进行一次数据的查询,可以通过 CPU 内存、或自定义的数据指标进行查询。
通过 API 会查到指定的 deployment 中数据,然后再进行条件的对比是否成立,没有成立就不会做动态扩缩容,如果成立的话也就是 CPU 资源大于 80% 了,那么 HPA 就会调用 deployment ,而 deployment 会调用 RS 动态扩缩容 pod
所以说即使是 deployment 也是控制 RS 来维护 pod 的副本数
10.3 准备 metrics-server
但是 metrics-server 现在是没有安装,需要手动安装。如果没有安装 metrics-server 就直接安装 HPA ,那么 HPA 也不会正常工作,因为 HPA 需要查询数据
metrics-server 地址:https://github.com/kubernetes-sigs/metrics-server
Metrics Server | Metrics API group/version | Supported Kubernetes version |
---|---|---|
0.6.x | metrics.k8s.io/v1beta1 |
*1.19+ |
0.5.x | metrics.k8s.io/v1beta1 |
*1.8+ |
0.4.x | metrics.k8s.io/v1beta1 |
*1.8+ |
0.3.x | metrics.k8s.io/v1beta1 |
1.8-1.21 |
由于我们的 K8S 是 1.21 版本,所以这里我安装 metrics-server 的 0.4 版本,而且这里的镜像是使用的国外镜像站,所以我们需要通过魔法上网将其下载 k8s.gcr.io/metrics-server/metrics-server:v0.4.4
1.导入镜像
# 通过国外服务器下载传到本地,并导入至 docker
[12:48:57 root@k8s-master hpa]#docker load -i metrics-server-v0.4.4.tar.gz
2.修改 tag
[12:50:26 root@k8s-master hpa]#docker tag k8s.gcr.io/metrics-server/metrics-server:v0.4.4 hub.zhangguiyuan.com/baseimage/metrics-server:v0.4.4
# 上传至本地仓库
[12:50:44 root@k8s-master hpa]#docker push hub.zhangguiyuan.com/baseimage/metrics-server:v0.4.4
3.下载 yaml
[12:52:15 root@k8s-master hpa]#wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.4/components.yaml
4.修改 yaml 镜像为本地镜像
[12:52:47 root@k8s-master hpa]#sed -i "s#k8s.gcr.io/metrics-server/metrics-server:v0.4.4#hub.zhangguiyuan.com/baseimage/metrics-server:v0.4.4#g" components.yaml
5.修改 metrics-server 启动参数:--kubelet-insecure-tls
,防止 metrics server 访问 kubelet 采集指标时报证书问题(x509: certificate signed by unknown authority), 在 deploy/1.8+/metrics-server-deployment.yaml 中加 args:
[13:24:58 root@k8s-master hpa]#vim components.yaml
- --kubelet-insecure-tls # 添加该参数
6.安装
[12:53:04 root@k8s-master hpa]#kubectl apply -f components.yaml
7.运行成功
[12:53:43 root@k8s-master hpa]#kubectl get pod -n kube-system | grep metrics
metrics-server-647b56c486-7xqts 1/1 Running 1 39s
8.验证
# 查看 node
[13:26:46 root@k8s-master hpa]#kubectl top node
W1024 13:26:49.506301 1417 top_node.go:119] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
# 能过获取资源信息
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master 159m 7% 2429Mi 51%
k8s-node 112m 5% 1119Mi 23%
k8s-node2 82m 4% 1049Mi 22%
# 查看所有 pod
[13:27:30 root@k8s-master hpa]#kubectl top pod -A
W1024 13:27:34.279494 2245 top_pod.go:140] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
NAMESPACE NAME CPU(cores) MEMORY(bytes)
jenkins jenkins-jenkins-deployment-6fb86f9d65-qz9sn 1m 478Mi
kube-system calico-kube-controllers-6778c45b7b-srv7b 1m 16Mi
kube-system calico-kube-controllers-6778c45b7b-tjqrn 2m 16Mi
kube-system calico-node-79bcr 22m 95Mi
kube-system calico-node-bvxzh 20m 94Mi
kube-system calico-node-wg9xc 24m 96Mi
kube-system coredns-6f6b8cc4f6-p4c6q 2m 10Mi
kube-system coredns-6f6b8cc4f6-zmnpb 3m 11Mi
kube-system etcd-k8s-master 13m 95Mi
kube-system kube-apiserver-k8s-master 39m 315Mi
kube-system kube-controller-manager-k8s-master 14m 44Mi
kube-system kube-proxy-pbtxc 8m 21Mi
kube-system kube-proxy-vsv4r 8m 21Mi
kube-system kube-proxy-z4ls9 6m 20Mi
kube-system kube-scheduler-k8s-master 3m 16Mi
kube-system metrics-server-67ccccd9b5-69z2k 2m 15Mi
mysql mysql-0 9m 200Mi
redis deploy-devops-redis-5f7d956fc9-dq9mn 1m 4Mi
web nginx-dm-57dd86f5cc-bgp99 0m 7Mi
web nginx-dm-57dd86f5cc-fh8tb 0m 7Mi
zookeeper zookeeper1-77548f5584-wfv6j 1m 53Mi
zookeeper zookeeper2-db4d698d7-mf6pv 1m 48Mi
zookeeper zookeeper3-867cc94cc6-fbzbr 2m 58Mi
10.4 命令行创建 hpa
1.获取 hpa
[13:29:31 root@k8s-master hpa]#kubectl get hpa -A
No resources found
# 当前没有 hpa
2.编写我们想要被监控的 yaml
[14:09:31 root@k8s-master hpa]#vim nginx-app1.yaml
apiVersion: v1
kind: Namespace
metadata:
name: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dm
namespace: web
spec:
replicas: 2
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources: # 必须填写字段,不然 HPA 不能拿到 pod 的监控数据
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: web
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx
3.获取想要控制的 deployment
[14:06:49 root@k8s-master hpa]#kubectl get deployments.apps -n web
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-dm 2/2 2 2 64s
4命令创建 hpa
[14:07:06 root@k8s-master hpa]#kubectl autoscale deployment -n web nginx-dm --min=2 --max=5 --cpu-percent=30
# deployment:控制类型 deployment
# -n web nginx-dm :对 web namespace下的 nginx-dm 的 deployment 控制器
# --min=2--max=5:最大 5 个 pod 最小 2 pod
# --cpu-percent=30:cpu 利用率在 30% 时候进行扩缩容
5.由于我们当前的 nginx deployment 是 1 个但是当我们创建完了 hpa 并设置了最小 pod 为 2,我们可以看到 nginx deployment 的 pod 已经更新为了 2
[13:38:32 root@k8s-master hpa]#kubectl get po -n web
NAME READY STATUS RESTARTS AGE
nginx-dm-57dd86f5cc-fh8tb 1/1 Running 1 44h
nginx-dm-57dd86f5cc-zhr5k 1/1 Running 0 4m9s
6.查看 hpa
[14:07:34 root@k8s-master hpa]#kubectl get hpa -n web
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-dm Deployment/nginx-dm 0%/30% 2 5 2 27s
# 创建完之后 unknown 是还没有获取到数据需要等一会
# 0% 就是我们的当前的 pod 利用率比较低
7.删除 HPA
# 这是基于命令行创建,但是在工作中一般不推荐
[14:12:13 root@k8s-master hpa]#kubectl delete hpa -n web nginx-dm
10.8 通过 yaml 文件创建
每个服务中可能都会配置一个 hpa 文件
1.编写 hpa
[14:15:31 root@k8s-master hpa]#cat hpa.yaml
#apiVersion: autoscaling/v2beta1
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
namespace: web
name: nginx-hpa
labels:
app: nginx
version: v2beta1
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment # 指定 hpa 管理类型为 deployment
name: nginx-dm # 指定管理 nginx-dm 的 deployment
minReplicas: 2 # 最小 2 个 pod
maxReplicas: 5 # 最大 5 个 pod
targetCPUUtilizationPercentage: 20 # CPU 条件 20%
2.创建
[14:48:52 root@k8s-master hpa]#kubectl apply -f hpa.yaml
3.创建成功
[14:50:11 root@k8s-master hpa]#kubectl get hpa -n web
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx-dm 0%/20% 2 5 2 79s