K8s-HPA控制器-Day 06

1. HPA控制器

1.1 HPA水平伸缩简介

HPA(Horizontal Pod Autoscaler)是一种自动扩展机制,用于根据负载自动调整应用程序的副本数量(流量高峰自动扩容,流量降低自动缩容)。
HPA可根据CPU利用率、内存使用率或自定义指标等指标来自动扩展或收缩应用程序的Pod副本数量,以确保应用程序具有所需的计算资源,并能够适应流量的变化。


HPA一般是用来伸缩deployment或者StatefulSet控制器的,也可以结合其他类型控制器,比如cronjob等。
但是它不适用于无法伸缩的控制器,比如daemonset。


公有云支持node级别的弹性伸缩。

1.2 动态伸缩控制器类型

1.2.1 水平pod自动缩放器(HPA)

基于pod资源利用率横向调整pod副本数量。

1.2.2 垂直pod自动缩放器(VPA:Vertical Pod Autoscaler)

不常用

基于pod资源利用率,调整对单个pod的最大资源限制,不能与HPA同时使用。
它与HPA类似,但是不是水平扩展Pod的数量,而是自动调整每个Pod的资源限制(Resource Limits)和请求(Resource Requests)。

1.2.3 集群伸缩(Cluster Autoscaler,CA)

基于集群中node资源使用情况,动态伸缩node节点,从而保证有CPU和内存资源用于创建pod。

1.3 HPA控制器常用参数介绍

下面所有的参数都是通过kube-controller-manager进行配置的

Horizontal Pod Autoscaling (HPA)控制器,根据预定义好的阈值及pod当前的资源利用率,自动控制在k8s集群中运行的pod数量(自动弹性水平自动伸缩)。


(1)–horizontal-pod-autoscaler-sync-period :HPA控制器同步pod副本数的间隔周期(包含查询metrics的资源使用情况), 默认15s。


(2)–horizontal-pod-autoscaler-downscale-stabilization:缩容间隔周期,默认5分钟(就是pod流量下去后,不会立即进行缩容操作,因为有可能是某写原因导致的流量抖动,可能过一会儿流量又变高, 所以默认会等待5分钟,只有5分钟过后,流量使用没有上升,才会进行缩容操作)。


(3)–horizontal-pod-autoscaler-cpu-initialization-period:初始化延迟时间,在此时间内pod的CPU资源指标将不会生效,默认为5分钟(就是pod刚启动的那会儿,cpu和内存利用率都会比较高,因为在加载各种配置,所以这个时候采集的数据是不准的,因为启动成功后,资源利用率都会下降,所以默认5分钟后才会采集数据)。


(4)–horizontal-pod-autoscaler-initial-readiness-delay:用于设置pod准备时间,在此时间内的pod统统被认为未就绪及不采集数据,默认为30秒(和上面的参数搭配使用的,也就是5分钟+30s,实际要5分30秒后才会开始采集数据,进行扩缩容)。


(5)–horizontal-pod-autoscaler-tolerance :HPA控制器能容忍的数据差异(浮点数,默认为0.1),即新的指标要与当前的阈值差异在0.1或以上, 即要大于1+0.1=1.1,或小于1-0.1=0.9。
比如阈值为CPU利用率50%,当前为80%,那么80/50=1.6 > 1.1则会触发扩容,否则之会缩容。
即触发条件:avg(CurrentPodsConsumption) / Target >1.1 或 <0.9=把N个pod的数据相加后根据pod的数量计算出平均数除以阈值,大于1.1就扩容,小于0.9就缩容。
这种设置方式是为了避免在期望值和实际值之间的微小变化时频繁地进行扩缩容操作,从而达到更加平滑和稳定的扩缩容效果。

1.4 HPA的计算公式

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
期望副本数 = 向上取整函数[当前副本数 * (当前指标 / 期望指标)]

文字解释

期望指标:比如我希望pod的cpu使用率不要超过50%
当前指标:但是因为某些原因,pod实际的cpu使用率处于80%-90%之间(如pod 1 当前实际的cpu使用率为85%,pod 2 当前实际的cpu使用率为75%,pod 3 当前实际的cpu使用率为80%,那么当前3个pod的平均cpu使用率为80%,)
当前指标 / 期望指标:那么我们期望的为50%,实际当前平均指标已经80%,所以就需要80 除以 50 = 1.6
当前副本数:3 * 1.6 = 4.8
ceil函数进行向上取整:ceil[4.8] = 5


通过上述运算得出的结果大于默认的1.1,就会触发扩容操作。

1.5 metrics-server 部署

指标数据需要部署metrics-server,即HPA使用metrics-server作为数据源。

Metrics Server是K8s内置的容器资源指标来源,用来统计cpu和内存指标。
Metrics Server从node节点上的Kubelet收集资源指标,并通过Metrics API在K8s apiserver中公开指标数据,以供Horizontal Pod Autoscaler和Vertical Pod Autoscaler使用,
也可以通过访问kubectl top node/pod 查看指标数据。

1.5.1 metrics-server工作原理

在这里插入图片描述

1.5.1 metrics-server与k8s版本兼容性说明

官网:https://github.com/kubernetes-sigs/metrics-server

在这里插入图片描述

1.5.2 下载yaml

我的k8s版本是1.26.1,所以可以下载0.6.x的。
官网:https://github.com/kubernetes-sigs/metrics-server/releases

https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/components.yaml

在这里插入图片描述

1.5.3 编辑yaml

[root@k8s-harbor01 metrics-server]# grep image: deploy.yaml
        image: registry.k8s.io/metrics-server/metrics-server:v0.6.3 # 官方的镜像可能在国内拉不下来,直接在dockerhub上找到对应版本的替换一下(或者直接上传到自己的镜像仓库)

[root@k8s-harbor01 metrics-server]# sed -i 's#image: registry.k8s.io\/metrics-server\/metrics-server:v0.6.3#image: bitnami\/metrics-server:0.6.3#g' deploy.yaml
[root@k8s-harbor01 metrics-server]# grep image: deploy.yaml
        image: bitnami/metrics-server:0.6.3

1.5.4 部署metrics-server

[root@k8s-harbor01 metrics-server]# kubectl apply -f deploy.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created

[root@k8s-harbor01 metrics-server]# kubectl get po -A  |grep metrics-server
kube-system     metrics-server-8c7f58775-btz6v            1/1     Running   0             3m1s

1.5.5 验证

[root@k8s-harbor01 metrics-server]# kubectl top no
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master01   115m         5%     1055Mi          63%
k8s-master02   98m          4%     1115Mi          66%
k8s-master03   127m         6%     1049Mi          62%
k8s-node01     91m          4%     1291Mi          35%
k8s-node02     114m         5%     1119Mi          30%
k8s-node03     96m          4%     1223Mi          33%

[root@k8s-harbor01 metrics-server]# kubectl top po -n myserver
NAME                     CPU(cores)   MEMORY(bytes)
minio-5cc5fc9498-lmzwh   3m           166Mi
temp-ubuntu              0m           0Mi

[root@k8s-harbor01 metrics-server]# kubectl api-versions |grep metrics
metrics.k8s.io/v1beta1 # 部署好metrics-server后,生成的api接口

1.6 部署HPA

1.6.1 HPA效果图

在这里插入图片描述

1.6.2 创建HPA

1.6.2.1 命令行创建讲解

不推荐直接使用命令创建,因为能传递的配置较少

kubectl autoscale deployment foo --min=2 --max=5 --cpu-percent=80

--min=2: 最小值2
--max=5:最大值5
--cpu-percent=80:cpu利用率百分比

# 如何计算pod cpu百分比?
HPA有个要求,就是在创建资源(如deployment)的时候,必须指定limits值,否则hpa获取不到相关数据。
假设pod limits cpu为1,当前使用了600m,那就是600 / 1000 = 60%。

创建好了hpa后,它会去找resource metrics api获取某一个控制器(如deployment)下pod的指标,所以我们创建hpa的时候,需要指定我们要检查的控制器的类型(如deployment),以及还需要把hpa创建在该控制器相同名称空间下。
1.6.2.2 yaml文件创建讲解
apiVersion: autoscaling/v2beta1 # 不同的apiVersion不同,写法也不同
#apiVersion: autoscaling/v1 
kind: HorizontalPodAutoscaler
metadata:
  namespace: magedu # HPA控制器必须和被采集数据的资源对象在同一个ns,否则无法实现自动水平伸缩
  name: magedu-tomcat-app1-deployment 
  labels:
    app: magedu-tomcat-app1
    version: v2beta1
spec: # 这里的写法是针对metrics-server默认的cpu 内存指标来进行扩缩容操作
  scaleTargetRef: # 定义水平伸缩的目标对象
    apiVersion: apps/v1 # api版本,和被采集数据的资源对象api版本相同
    #apiVersion: extensions/v1beta1 
    kind: Deployment # 目标对象类型
    name: magedu-tomcat-app1-deployment  # deployment的具体名称
  minReplicas: 3 # 最小pod数。一般就是业务低峰期的最小副本数,维持业务日常响应
  maxReplicas: 10 # 最大pod数。业务高峰期最多能有10个pod对外提供服务
  targetCPUUtilizationPercentage: 60 # 目标CPU利用率百分比。触发水平伸缩的标准,这里达到60%就会扩容,低于60%就缩容
  
################## 下面的配置,是hpa调用Prometheus来获取相关metrics数据,进行扩缩容
  #metrics: # 调用metrics数据定义
  #- type: Resource # 类型为Resource
  #  resource: # 定义资源
  #    name: cpu # 资源名称
  #    targetAverageUtilization: 60 # cpu平均利用率
  #- type: Resource
  #  resource:
  #    name: memory
  #    targetAverageValue: 1024Mi # 内存平均利用率
1.6.2.3 创建测试pod
[root@k8s-harbor01 metrics-server]# cat tomcat-app1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: tomcat-app1
  name: tomcat-app1
  namespace: myserver
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tomcat-app1
  template:
    metadata:
      labels:
        app: tomcat-app1
    spec:
      containers:
      - name: tomcat-app1
        image: tsk8s.top/tsk8s/tomcat-app1:v1
        #image: lorel/docker-stress-ng
        #args: ["--vm", "2", "--vm-bytes", "256M"]
        ##command: ["/apps/tomcat/bin/run_tomcat.sh"]
        imagePullPolicy: IfNotPresent
        ##imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources: # 使用hpa必须的字段
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
      imagePullSecrets:
        - name: dockerhub-image-pull-key

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: tomcat-app1
  name: tomcat-app1-nodeport
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat-app1

[root@k8s-harbor01 metrics-server]# kubectl apply -f tomcat-app1.yaml
deployment.apps/tomcat-app1 created
service/tomcat-app1-nodeport created

[root@k8s-harbor01 metrics-server]# kubectl get po -n myserver |grep tomcat
tomcat-app1-59b496dfd8-cfzz9   1/1     Running   0          28s
tomcat-app1-59b496dfd8-mlrpq   1/1     Running   0          28s
1.6.2.4 创建hpa
[root@k8s-harbor01 myserver]# pwd
/root/yaml/deployment/hpa/myserver
[root@k8s-harbor01 myserver]# cat hpa.yaml
#apiVersion: autoscaling/v2beta1
apiVersion: autoscaling/v1 # 不同的api版本写法不同
kind: HorizontalPodAutoscaler
metadata:
  namespace: myserver
  name: hpa
  labels:
    app: tomcat-app1
    version: v2beta1
spec:
  scaleTargetRef: # metrics-server数据源
    apiVersion: apps/v1
    #apiVersion: extensions/v1beta1
    kind: Deployment
    name: tomcat-app1 # deployment控制器名称
  minReplicas: 2
  maxReplicas: 5
  targetCPUUtilizationPercentage: 60

# prometheus数据源
  #metrics:
  #- type: Resource
  #  resource:
  #    name: cpu
  #    targetAverageUtilization: 60
  #- type: Resource
  #  resource:
  #    name: memory

[root@k8s-harbor01 myserver]# kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/hpa created

[root@k8s-harbor01 myserver]# kubectl get hpa -n myserver # 这里需要注意TARGETS下面 0%/60%,如果0%哪里长时间显示是<unknown>,需要检查deployment的yaml有没有设置resources
NAME   REFERENCE                TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa    Deployment/tomcat-app1   0%/60%    2         5         2          48s
1.6.2.5 hpa Replicas 和其他控制器Replicas优先级问题

假设deployment Replicas为2,hpa minReplicas为3,谁的优先级更高?
答:hpa 优先级更高,创建hpa后,会根据相关配置对deployment 副本数进行扩容。

1.7 测试hpa自动扩缩容

1.7.1 测试扩容

1.7.1.1 调整测试pod yaml
[root@k8s-harbor01 metrics-server]# cat tomcat-app1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: tomcat-app1
  name: tomcat-app1
  namespace: myserver
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tomcat-app1
  template:
    metadata:
      labels:
        app: tomcat-app1
    spec:
      containers:
      - name: tomcat-app1
        #image: tsk8s.top/tsk8s/tomcat-app1:v1
        image: lorel/docker-stress-ng # 这是一个压测专用镜像
        args: ["--vm", "2", "--vm-bytes", "256M"] # 创建2个工作进程,每个进程消耗2核cpu,但是limits只配置了1核cpu,所以这里就会触发扩容,但是由于资源消耗一直超过100%,所以会一直扩容到hpa配置的最大副本数
        ##command: ["/apps/tomcat/bin/run_tomcat.sh"]
        imagePullPolicy: IfNotPresent
        ##imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
      imagePullSecrets:
        - name: dockerhub-image-pull-key

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: tomcat-app1
  name: tomcat-app1-nodeport
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat-app1

[root@k8s-harbor01 metrics-server]# kubectl apply -f tomcat-app1.yaml
deployment.apps/tomcat-app1 configured
service/tomcat-app1-nodeport unchanged

[root@k8s-harbor01 metrics-server]# kubectl get po -A |grep tomcat
myserver        tomcat-app1-5456845b74-ghgr8              1/1     Running   0             3s
myserver        tomcat-app1-5456845b74-rv5tj              1/1     Running   0             3s
1.7.1.2 观察扩容情况
[root@k8s-harbor01 metrics-server]# kubectl get po -A -w |grep tomcat # 通过-w参数可以看到扩容过程
myserver        tomcat-app1-5456845b74-ghgr8              1/1     Running   0             39s
myserver        tomcat-app1-5456845b74-rv5tj              1/1     Running   0             39s
myserver        tomcat-app1-5456845b74-xnn4z              0/1     Pending   0             0s
myserver        tomcat-app1-5456845b74-24pkx              0/1     Pending   0             0s
myserver        tomcat-app1-5456845b74-xnn4z              0/1     Pending   0             0s
myserver        tomcat-app1-5456845b74-24pkx              0/1     Pending   0             0s
myserver        tomcat-app1-5456845b74-24pkx              0/1     ContainerCreating   0             0s
myserver        tomcat-app1-5456845b74-xnn4z              0/1     ContainerCreating   0             0s
myserver        tomcat-app1-5456845b74-xnn4z              1/1     Running             0             2s
myserver        tomcat-app1-5456845b74-24pkx              1/1     Running             0             3s
myserver        tomcat-app1-5456845b74-89qd5              0/1     Pending             0             0s
myserver        tomcat-app1-5456845b74-89qd5              0/1     Pending             0             0s
myserver        tomcat-app1-5456845b74-89qd5              0/1     ContainerCreating   0             0s
myserver        tomcat-app1-5456845b74-89qd5              1/1     Running             0             3s
^C
[root@k8s-harbor01 metrics-server]# kubectl get po -A  |grep tomcat
myserver        tomcat-app1-5456845b74-24pkx              1/1     Running   0             92s
myserver        tomcat-app1-5456845b74-89qd5              1/1     Running   0             77s
myserver        tomcat-app1-5456845b74-ghgr8              1/1     Running   0             2m11s
myserver        tomcat-app1-5456845b74-rv5tj              1/1     Running   0             2m11s
myserver        tomcat-app1-5456845b74-xnn4z              1/1     Running   0             92s

[root@k8s-harbor01 metrics-server]# kubectl describe deploy -n myserver  tomcat-app1 # describe也能看到扩容
……省略部分内容
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  2m46s  deployment-controller  Scaled up replica set tomcat-app1-5456845b74 to 2
  Normal  ScalingReplicaSet  2m7s   deployment-controller  Scaled up replica set tomcat-app1-5456845b74 to 4 from 2
  Normal  ScalingReplicaSet  112s   deployment-controller  Scaled up replica set tomcat-app1-5456845b74 to 5 from 4
  
[root@k8s-harbor01 metrics-server]# kubectl top po -n myserver|grep tomcat # 可以看到每个pod消耗的cpu基本都达到了1核
tomcat-app1-5456845b74-24pkx   938m         424Mi
tomcat-app1-5456845b74-89qd5   958m         355Mi
tomcat-app1-5456845b74-ghgr8   942m         430Mi
tomcat-app1-5456845b74-rv5tj   966m         320Mi
tomcat-app1-5456845b74-xnn4z   1001m        286Mi

[root@k8s-harbor01 metrics-server]# kubectl get hpa -n myserver # 可以看到我们期望的cpu使用率是60,但是当前实际已经达到了192
NAME   REFERENCE                TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
hpa    Deployment/tomcat-app1   192%/60%   2         5         5          34m

1.7.2 测试缩容

1.7.2.1 调整测试pod yaml
[root@k8s-harbor01 metrics-server]# cat tomcat-app1.yaml
……省略部分内容
spec:
  replicas: 3 # 修改副本数为3,方便观察缩容
        image: tsk8s.top/tsk8s/tomcat-app1:v1 # 换回这个正常的镜像测试
        #image: lorel/docker-stress-ng
        #args: ["--vm", "2", "--vm-bytes", "256M"]
1.7.2.2 观察缩容情况
[root@k8s-harbor01 metrics-server]# kubectl apply -f tomcat-app1.yaml

[root@k8s-harbor01 metrics-server]# kubectl get po -n myserver|grep tomcat
tomcat-app1-59b496dfd8-2qs7m   1/1     Running   0          10s
tomcat-app1-59b496dfd8-65p29   1/1     Running   0          6s
tomcat-app1-59b496dfd8-d5zt2   1/1     Running   0          10s
tomcat-app1-59b496dfd8-f27dr   1/1     Running   0          10s
tomcat-app1-59b496dfd8-slmkc   1/1     Running   0          8s

[root@k8s-harbor01 metrics-server]# kubectl get hpa -n myserver
NAME   REFERENCE                TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
hpa    Deployment/tomcat-app1   194%/60%   2         5         5          17h

为什么我副本数写的3个,创建出来却是5个?注意看hpa的REPLICAS哪里也是5,主要是因为hpa缩容需要持续观察pod指标一段时间,默认5分钟,只有5分钟持续资源使用都没有超过我们指定值,才会进行缩容

[root@k8s-harbor01 metrics-server]# kubectl get po -n myserver|grep tomcat # 可以看到5分钟的时候,缩容了多余的pod,保留hpa配置的最小副本数
tomcat-app1-59b496dfd8-2qs7m   1/1     Running       0          5m4s
tomcat-app1-59b496dfd8-65p29   1/1     Terminating   0          5m
tomcat-app1-59b496dfd8-d5zt2   1/1     Running       0          5m4s
tomcat-app1-59b496dfd8-f27dr   1/1     Terminating   0          5m4s
tomcat-app1-59b496dfd8-slmkc   1/1     Terminating   0          5m2s

[root@k8s-harbor01 metrics-server]# kubectl get hpa -n myserver
NAME   REFERENCE                TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
hpa    Deployment/tomcat-app1   0%/60%    2         5         2          17h

1.7.3 自动扩缩容过程

在这里插入图片描述

1.8 hpa收集Prometheus数据进行伸缩

github:https://github.com/zhangshijle/prometheus-adapter-hpa-files/blob/main/7.2.sample-httpserver-hpa.yaml

hpa默认情况下是基于metrics-server收集的指标进行扩缩容的,但是它收集的指标都比较简单,一般都是根据cpu内存来进行扩缩容。
结合Prometheus就能指定其他类型的指标,进行伸缩,如网卡速率、接口请求次数、tomcat线程数等。

1.9 HPA可以使用的Metrics API

官网:https://v1-26.docs.kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-apis

(1)对于资源指标,将使用 metrics.k8s.io API,一般由 metrics-server 提供。 它可以作为集群插件启动。


(2)对于自定义指标,将使用 custom.metrics.k8s.io API。 它由其他度量指标方案厂商的“适配器(Adapter)” API 服务器提供。 检查你的指标管道以查看是否有可用的 Kubernetes 指标适配器。


(3)对于外部指标,将使用 external.metrics.k8s.io API。可能由上面的自定义指标适配器提供。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值