Kubernetes基于HPA 实现 CPU、内存指标自动扩缩容
搭建的基础
- Linux: CentOS-7-x86_64-DVD-1810.iso
- Docker: docker-ce-18.03.1.ce
- kubernetes: kubernetes v1.16.7
基于此篇博文的进一步实践
kubernetes 简单操作deployment,service,pod,标签
参考博文
Horizontal Pod Autoscaler Walkthrough
Kubernetes:HPA 详解-基于 CPU、内存和自定义指标自动扩缩容
当系统资源过高的时候,我们可以使用kubectl scale 命令可以来实现 Pod 的扩缩容功能,但是这个过程是手动操作的。在实际项目中,我们需要做到是的是一个自动化感知并自动扩容的操作。Kubernetes 也为提供了这样的一个资源对象:Horizontal Pod Autoscaling(Pod 水平自动伸缩),简称HPA。
HPA 通过监控分析一些控制器控制的所有 Pod 的负载变化情况来自动动态调整pod的数量。
要使用 HPA,就需要在集群中安装 Metrics Server 服务,要安装 Metrics Server 就需要开启 Aggregator,因为 Metrics Server 就是通过该代理进行扩展的。这里我的集群环境是通过 Kubeadm 搭建的,默认已经开启了。
检查是否安装Mertics Sercer
kubectl api-versions
如果没有,就需要安装
image.png
安装Metrics Server
master节点执行
k8s通过集群内的资源监控系统(metrics-server),来获取集群中资源的使用状态。
根据CPU、内存、以及用户自定义的资源指标数据的使用量或连接数为参考依据,来制定一个临界点,一旦超出这个点,HPA就会自动创建出pod副本。
获取metrics server 配置文件
for i in auth-delegator.yaml auth-reader.yaml metrics-apiservice.yaml metrics-server-deployment.yaml metrics-server-service.yaml resource-reader.yaml ;do wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/metrics-server/$i;done
一共6个配置文件
image.png
metrics-server所需要的docker镜像
从metrics-server-deployment.yaml配置文件可以看出,需要使用两个镜像
- k8s.gcr.io/metrics-server-amd64:v0.3.6
- k8s.gcr.io/addon-resizer:1.8.7
如果可以科学上网在每台k8s服务器执行如下两个命令
docker pull k8s.gcr.io/metrics-server-amd64:v0.3.6
docker pull k8s.gcr.io/addon-resizer:1.8.7
如果无法克服网络情况,可以使用国内的镜像仓库拉取镜像然后使用docker load命令加载进去,如果tag标签不一样,需要改为一样
docker load --input xxx.tar
保证docker里面与这两个镜像
image.png
修改文件:metrics-server-deployment.yaml
不同的版本修改的不一样, 我这里使用的是metrics-server-amd64:v0.3.6
vim metrics-server-deployment.yaml
修改如下
image.png修改后的yaml
kind: ConfigMap
metadata:
name: metrics-server-config
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: EnsureExists
data:
NannyConfiguration: |-
apiVersion: nannyconfig/v1alpha1
kind: NannyConfiguration
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server-v0.3.6
namespace: kube-system
labels:
k8s-app: metrics-server
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
version: v0.3.6
spec:
selector:
matchLabels:
k8s-app: metrics-server
version: v0.3.6
template:
metadata:
name: metrics-server
labels:
k8s-app: metrics-server
version: v0.3.6
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
nodeSelector:
kubernetes.io/os: linux
containers:
- name: metrics-server
image: k8s.gcr.io/metrics-server-amd64:v0.3.6
command:
- /metrics-server
- --metric-resolution=30s
- --kubelet-insecure-tls # 不能做TLS加密认证,使用不安全的通信,这里有的博文要加,有的没加也没问题,这里加上
# These are needed for GKE, which doesn't support secure communication yet.
# Remove these lines for non-GKE clusters, and when GKE supports token-based auth.
#- --kubelet-port=10255 # 需要注释
#- --deprecated-kubelet-completely-insecure=true # 需要注释
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
ports:
- containerPort: 443
name: https
protocol: TCP
- name: metrics-server-nanny
image: k8s.gcr.io/addon-resizer:1.8.7
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 5m
memory: 50Mi
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: metrics-server-config-volume
mountPath: /etc/config
command:
# 下面这些{{xxxxx}}需要替换,不替换,启动metrics-server-nanny容器时会报错
- /pod_nanny
- --config-dir=/etc/config
# 设置metrics-server基本运行可用CPU豪核数量,测试设置100m,也可以注释掉
#- --cpu={{ base_metrics_server_cpu }}
- --extra-cpu=0.5m
# #分配给metrics-server基本运行的内存大小, 测试设置 80Mi,根据自己服务器性能设置
#- --memory={{ base_metrics_server_memory }}
- --memory=80Mi
# #每个节点上的metrics-server额外分配内存大小,测试8Mi,根据自己服务器性能设置
#- --extra-memory={{ metrics_server_memory_per_node }}Mi
- --extra-memory=8Mi
- --threshold=5
- --deployment=metrics-server-v0.3.6
- --container=metrics-server
- --poll-period=300000
- --estimator=exponential
# Specifies the smallest cluster (defined in number of nodes)
# resources will be scaled to.
# 设置启动几组Metrics-server,选项说明提示默认是16组. 可以注释掉了
#- --minClusterSize={{ metrics_server_min_cluster_size }}
volumes:
- name: metrics-server-config-volume
configMap:
name: metrics-server-config
修改配置文件resource-reader.yaml
vim resource-reader.yaml
添加如下参数
image.png
修改后的yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ""
resources:
- pods
- nodes
- namespaces
- nodes/stats # nodes/stats和nodes是两个不同的资源. nodes/stats是获取节点监控数据的专用资源
verbs:
- get
- list
- watch
- apiGroups:
- "apps"
resources:
- deployments
verbs:
- get
- list
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
安装Metrics Server
2个配置文件修改完成后,在6个配置文件的目录下执行
kubectl apply -f .
第一次执行会显示create,后面修改后执行会显示如下
image.png验证是否安装成功
kubectl get pod -n kube-system
成功,显示如下
image.png测试获取node信息
kubectl top nodes
image.png
测试获取pod信息
kubectl top pod
image.png
如果显示如下错误,等待一会再次执行
error: metrics not available yet
如果还是不行,通过如果下两个命令查询出报错信息
kubectl logs 后面跟的是通过kubectl get pod -n kube-system 查询出的name
kubectl logs metrics-server-v0.3.6-6f9474fc7d-z4564 -c metrics-server -n kube-system
kubectl logs metrics-server-v0.3.6-6f9474fc7d-z4564 -c metrics-server-nanny -n kube-system
如果出现如下报错,重启pod所在节点重启kubelet
the server is currently unable to handle the request (get nodes.metrics.k8s.io)
image.png
创建pod
这里和之前的那个demo博客不同,我们需要设置pod节点的资源使用率
基础概念
在K8s的资源:
CPU:
我们知道2核2线程的CPU,可被系统识别为4个逻辑CPU,在K8s中对CPU的分配限制是对逻辑CPU做分片限制的。
也就是说分配给容器一个CPU,实际是分配一个逻辑CPU。
而且1个逻辑CPU还可被单独划分子单位,即 1个逻辑CPU,还可被划分为1000个millicore(毫核), 简单说就是1个逻辑CPU,继续逻辑分割为1000个豪核心。
豪核:可简单理解为将CPU的时间片做逻辑分割,每一段时间片就是一个豪核心。
所以:500m 就是500豪核心,即0.5个逻辑CPU.
内存:
K,M,G,T,P,E #通常这些单位是以1000为换算标准的。
Ki, Mi, Gi, Ti, Pi, Ei #这些通常是以1024为换算标准的。
k8s pod 配置之 resources 中 含义
- requests未设置时,默认与limits相同。
- limits未设置时,默认值与集群配置相关。
- 可以使用requests来设置各容器需要的最小资源
- limits用于限制运行时容器占用的资源,用来限制容器的最大CPU、内存的使用率。
- 当容器申请内存超过limits时会被终止,并根据重启策略进行重启。
limit对应资源量的上限, 既最多允许使用这个上限的资源量, 由于cpu是可压缩的, 进程是无法突破上限的, 而memory是不可压缩资源, 当进程试图请求超过limit限制时的memory, 此进程就会被kubernetes杀掉
对于cpu和内存而言, pod的request和limit是指该pod中所有容器的 Requests或Limits的总和。
例如: 某个节点cpu资源充足, 而内存为4G,其中3GB可以运行pod, 而某个pod的memory request为1GB, limit为2GB, 那么这个节点上最多可以运行3个这样的pod
待调度pod的request值总和超过该节点提供的空闲资源, 不会调度到该节点node上;
deployment.yaml
apiVersion: apps/v1 #apiVersion是当前配置格式的版本
kind: Deployment #kind是要创建的资源类型
metadata: #metadata是该资源的元数据,name是必须的元数据项
#指定deployment的名称
name: demo-deployment
labels:
app: ecs-demo #标签
spec:
#期望创建1个实例(1个pod)
replicas: 1
selector: # .spec.selector 必须匹配 .spec.template.metadata.labels,否则它将被API拒绝。如果 .spec.selector 没有被指定, .spec.selector.matchLabels 默认是 .spec.template.metadata.labels
#选择label:app=ecs-demo的pod来创建实例
matchLabels: #metadata定义Pod的元数据,至少要顶一个label,label的key和value可以任意指定
app: ecs-demo
template:
metadata:
labels:
app: ecs-demo
spec:
containers:
- name: ecs-demo
image: wangzhh/login_demo:20200429 # docker imange地址 REPOSITORY:TAG
ports:
- containerPort: 8080 #暴露给service的地址
resources:
requests:
cpu: 500m # podcpu占用最小资源,根据服务器性能设置
memory: 512Mi # pod占用最小内存,根据服务器性能设置
limits:
cpu: 1000m # pod占用cpu大资源,根据服务器性能设置
memory: 1024Mi # pod占用最大内存,根据服务器性能设置
readinessProbe: #就绪探针
httpGet:
port: 8080
path: /
initialDelaySeconds: 50 # initialDelaySeconds这个参数 机器新能不好调大
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
initialDelaySeconds: 50 # initialDelaySeconds这个参数 机器新能不好调大
periodSeconds: 10
在master节点执行命令
kubectl create -f deployment.yaml
创建service
service.yaml
apiVersion: v1 #apiVersion是当前配置格式的版本
kind: Service #kind是要创建的资源类型
metadata: #metadata是该资源的元数据,name是必须的元数据项
name: demo-service
spec:
selector: # selector 指明挑选那些 label 为 run: xx 的 Pod 作为 Service 的后端。
app: ecs-demo
ports: #将Service 的 8080 端口映射到 Pod 的 8080 端口,使用 TCP 协议
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30036 # nodePort,它指定节点上开放的端口值 端口范围只能是 30000-32767,如果不指定这个端口,系统将选择一个随机端口
sessionAffinity: ClientIP # service内部实现session保持
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800 # timeoutSeconds指的是session保持的时间,这个时间默认是10800秒,也就是三个小时
type: NodePort # 暴露service的三种方式 NodePort,LoadBalancer 和 Ingress
在master节点执行命令
kubectl create -f service.yaml
创建HPA
这里我们通过yaml的方式发布hpa,当然也可以使用下面的命令,简单的发布
- 方法1 创建hpa策略 cpu利用率阈值50% 副本数量在1--10之间(不推荐)
kubectl autoscale deployment xxxx --cpu-percent=50 --min=1 --max=10
- 方法2 使用yaml创建发布(推荐)
可以使用的版本
通过命令可以查看到kubectl api-versions
autoscaling/v1 #只支持通过cpu为参考依据,来改变pod副本数
autoscaling/v2beta1 #支持通过cpu、内存、连接数以及用户自定义的资源指标数据为参考依据。
autoscaling/v2beta2 #与v2beta1差不多,小的变动
image.png
一些查询命令
此命令可以查询到系统使用的版本
kubectl explain hpa
image.png
此命令可以指定版本
kubectl explain hpa --api-version=autoscaling/v2beta1
通过yaml配置HPA 实现 CPU、内存指标自动扩缩容
基于cpu和内存指标的HPA yaml脚本
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: demo-hpa-beta1
namespace: default
spec:
minReplicas: 1 ##至少1个副本
maxReplicas: 5 ##最多5个副本
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-deployment # 创建的deploment文件里面的name
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50 ##注意此时是根据使用率,也可以根据使用量:targetAverageValue
- type: Resource
resource:
name: memory
targetAverageUtilization: 50 ##注意此时是根据使用率,也可以根据使用量:targetAverageValue
创建HPA
kubectl apply -f hpa.yaml
image.png
查看是否创建成功
kubectl get hpa
image.png
此命令可查看详细信息,如果没成功可用作报错排查
kubectl describe hpa
image.png
这个时候我们get下pod可以看到只有一个pod
image.png测试
使用压力测试命令调用tomcat,测试是否自动扩容
安装命令
yum install httpd-tools
测试
ab -c 100 -n 5000000 http://10.211.55.9:30036/
- -n :总的请求数
- -c :并发数
- -k 是否开启长连接
再次查看hpa,发现操过上限
image.png
获取pod查看,自动扩容到4个pod
image.png
查看pod资源使用情况,满足预期
image.png
停止压力测试,等待一段时间,发现只有一个pod存在
到此,k8s自动扩缩容完成