草庐IT

k8s-HPA动态伸缩

一名年轻的运维工程师 2023-03-28 原文
一、认识HPA 参考: https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/

  • HPA全称是Horizontal Pod Autoscaler,中文意思是POD水平自动伸缩.

  • 可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。

  • 除了 CPU 利用率,内存占用外,也可以基于其他应程序提供的自定义度量指标来执行自动扩缩。

自定义度量参考: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/custom-metrics-api.md

  • Pod 自动扩缩不适用于无法扩缩的对象,比如 DaemonSet。

 

  • Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源决定了控制器的行为。

  • 控制器会周期性的调整副本控制器或 Deployment 中的副本数量,以使得 Pod 的平均 CPU 利用率与用户所设定的目标值匹配。

二、HPA工作机制

Pod 水平自动扩缩器的实现是一个控制回路,由控制器管理器的 --horizontal-pod-autoscaler-sync-period 参数指定周期(默认值为 15 秒)。

每个周期内,控制器管理器根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。 控制器管理器可以从资源度量指标 API(按 Pod 统计的资源用量)和自定义度量指标 API(其他指标)获取度量值。

 

  • 对于按 Pod 统计的资源指标(如 CPU), 控制器从资源指标 API 中获取每一个 HorizontalPodAutoscaler 指定的 Pod 的度量值,如果设置了目标使用率, 控制器获取每个 Pod 中的容器资源使用情况,并计算资源使用率。 如果设置了 target 值,将直接使用原始数据(不再计算百分比)。 接下来,控制器根据平均的资源使用率或原始值计算出扩缩的比例,进而计算出目标副本数。

    需要注意的是,如果 Pod 某些容器不支持资源采集,那么控制器将不会使用该 Pod 的 CPU 使用率。

  • 如果 Pod 使用自定义指示,控制器机制与资源指标类似,区别在于自定义指标只使用 原始值,而不是使用率。

  • 如果 Pod 使用对象指标和外部指标(每个指标描述一个对象信息)。 这个指标将直接根据目标设定值相比较,并生成一个上面提到的扩缩比例。 在 autoscaling/v2beta2 版本 API 中,这个指标也可以根据 Pod 数量平分后再计算。

通常情况下,控制器将从一系列的聚合 API(metrics.k8s.iocustom.metrics.k8s.ioexternal.metrics.k8s.io)中获取度量值。 metrics.k8s.io API 通常由 Metrics 服务器(需要额外启动)提供。

确认安装metrics-server

[root@master1 ~]# kubectl get pods -n kube-system |grep metrics-server metrics-server-869ffc99cd-lz68h 1/1 Running 5 23h [root@master1 ~]# kubectl top nodes NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% 192.168.122.11 357m 4% 895Mi 17% 192.168.122.12 426m 5% 910Mi 28% 192.168.122.13 353m 4% 664Mi 20% 192.168.122.14 251m 3% 408Mi 12% 三、HPA API对象 HPA的API有三个版本

[root@master1 ~]# kubectl api-versions | grep autoscal autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2
APA版本 描述
autoscaling/v1 只支持基于CPU指标的缩放
autoscaling/v2beta1 支持Resource Metrics(资源指标,如pod的CPU)和Custom Metrics(自定义指标)的缩放;
autoscaling/v2beta2 支持Resource Metrics(资源指标,如pod的CPU)和Custom Metrics(自定义指标)和ExternalMetrics(额外指标)的缩放。
四、kubectl对HPA的支持 与其他 API 资源类似,kubectl 以标准方式支持 HPA。

  • 通过 kubectl create 命令创建一个 HPA 对象

  • 通过 kubectl get hpa 命令来获取所有 HPA 对象

  • 通过 kubectl describe hpa 命令来查看 HPA 对象的详细信息

  • 通过 kubectl delete hpa 命令删除对象。

     

此外,还有个简便的命令 kubectl autoscale 来创建 HPA 对象。

例如,命令 kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80 将会为名 为 foo 的 ReplicationSet 创建一个 HPA 对象, 目标 CPU 使用率为 80%,副本数量配置为 2 到 5 之间。

五、HPA演示案例 参考: https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/

 

基于CPU的HPA

1, 构建测试镜像

[root@master1 ~]# vim index.php <?php $x = 0.0001; for ($i = 0; $i <= 1000000; $i++) { $x += sqrt($x); } echo "OK!"; ?> [root@master1 ~]# vim Dockerfile FROM php:5-apache COPY index.php /var/www/html/index.php RUN chmod a+rx index.php [root@master1 ~]# docker build -f Dockerfile -t 192.168.122.18/library/hpa-example:v1 .

2, 上传到harbor

[root@master1 ~]# docker login 192.168.122.18 Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@master1 ~]# docker push 192.168.122.18/library/hpa-example:v1

3, 部署测试deployment

[root@master1 ~]# vim php-apache.yaml apiVersion: apps/v1 kind: Deployment metadata: name: php-apache spec: selector: matchLabels: app: php-apache replicas: 1 template: metadata: labels: app: php-apache spec: containers: - name: php-apache image: 192.168.122.18/library/hpa-example:v1 ports: - containerPort: 80 resources: limits: cpu: 500m requests: cpu: 200m [root@master1 ~]# kubectl apply -f php-apache.yaml deployment.apps/php-apache created

4, 验证得到pod-IP

[root@master1 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READIN ESS GATES php-apache-665fc66c67-cfj6f 1/1 Running 0 25m 10.3.104.15 192.168.122.14 <none> <none> 得到pod-IP为10.3.104.15,此IP下面测试需要用到

5, 创建HPA

[root@master1 ~]# kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10 horizontalpodautoscaler.autoscaling/php-apache autoscaled 说明:

  • --cpu-percent=50表示所有Pod的平均CPU使用率维持在50%,超过就要扩容

  • --min=1 --max=10表示pod数量的范

6, 创建测试pod对其访问

用另一个终端(我这里是master2)使用busybox镜像产生一个测试pod,对10.3.104.15进行压测

[root@master2 ~]# kubectl run busybox -it --image=busybox /bin/sh / # while true; do wget -q -O- http://10.3.104.15; done OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!...... 不断查询hpa状态,大概一分钟后才会看到效果

[root@master1 ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 250%/50% 1 10 1 19m cpu用到250%了 [root@master1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE busybox 1/1 Running 0 3m27s php-apache-665fc66c67-8z6wj 1/1 Running 0 59s php-apache-665fc66c67-cfj6f 1/1 Running 0 26m php-apache-665fc66c67-fn4wg 1/1 Running 0 59s php-apache-665fc66c67-t9wpr 1/1 Running 0 44s php-apache-665fc66c67-zw662 1/1 Running 0 60s 也可以看到pod扩容到了5个 [root@master2 ~]# kubectl run busybox -it --image=busybox /bin/sh / # while true; do wget -q -O- http://10.3.104.15; done OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!^ ctrl+c取消压力测试 要等几分钟甚至更久后,就看到cpu与pod数量都回去了

[root@master1 ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 0%/50% 1 10 5 22m [root@master1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE busybox 1/1 Running 0 28m php-apache-665fc66c67-t9wpr 1/1 Running 0 25m

7, 测试完后删除

[root@master1 ~]# kubectl delete deployments.apps php-apache deployment.apps "php-apache" deleted [root@master1 ~]# kubectl delete pod busybox pod "busybox" deleted [root@master1 ~]# kubectl delete hpa php-apache horizontalpodautoscaler.autoscaling "php-apache" deleted

基于内存的HPA

1, 创建测试deployment

[root@master1 ~]# vim nginx-hpa.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-hpa spec: selector: matchLabels: app: nginx-hpa replicas: 1 template: metadata: labels: app: nginx-hpa spec: containers: - name: nginx image: nginx:1.15-alpine ports: - containerPort: 80 name: http protocol: TCP resources: requests: cpu: 0.01 memory: 25Mi limits: cpu: 0.05 memory: 60Mi [root@master1 ~]# kubectl apply -f nginx-hpa.yaml deployment.apps/nginx-hpa created

2, 创建HPA

[root@master1 ~]# vim mem-hpa.yaml apiVersion: autoscaling/v2beta1 # v2beta1版本 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: maxReplicas: 10 minReplicas: 1 # 1-10个pod范围内扩容与裁剪 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-hpa metrics: - type: Resource resource: name: memory targetAverageUtilization: 50 # 50%内存利用 [root@master1 ~]# kubectl apply -f mem-hpa.yaml horizontalpodautoscaler.autoscaling/nginx-hpa created [root@master1 ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-hpa Deployment/nginx-hpa 12%/50% 1 10 1 60s

3, 对pod进行测试

换一个终端(master2),进入pod后进行dd命令测试

[root@master2 ~]# kubectl exec -it nginx-hpa-74ccf95f7d-454z5 -- /bin/sh / # dd if=/dev/zero of=/tmp/file1

4, 验证

不断查询hpa状态,大概一分钟后才会看到效果

[root@master1 ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-hpa Deployment/nginx-hpa 204%/50% 1 10 5 3m10s [root@master1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-hpa-74ccf95f7d-454z5 1/1 Running 0 6m20s nginx-hpa-74ccf95f7d-8gznw 1/1 Running 0 30s nginx-hpa-74ccf95f7d-bv4hm 1/1 Running 0 30s nginx-hpa-74ccf95f7d-g9276 1/1 Running 0 15s nginx-hpa-74ccf95f7d-xmzqs 1/1 Running 0 30s

5, 裁剪测试

ctrl+c取消后,删除dd的文件

[root@master2 ~]# kubectl exec -it nginx-hpa-74ccf95f7d-454z5 -- /bin/sh / # rm /tmp/file1 -rf 等几分钟甚至更久后,就看到cpu与pod数量都回去了

[root@master1 ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-hpa Deployment/nginx-hpa 12%/50% 1 10 1 28m [root@master1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-hpa-74ccf95f7d-xmzqs 1/1 Running 0 25m

6, 测试完后删除

[root@master1 ~]# kubectl delete deploy nginx-hpa deployment.apps "nginx-hpa" deleted [root@master1 ~]# kubectl delete hpa nginx-hpa horizontalpodautoscaler.autoscaling "nginx-hpa" deleted 写在最后,更多功能可以自己去探索。虽然目前HPA功能还在beta版,但以后肯定会越来越成熟。

有关k8s-HPA动态伸缩的更多相关文章

  1. ruby - 在 Ruby 中动态创建数组 - 2

    有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.

  2. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

  3. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  4. ruby - 在 Ruby 中动态生成多维数组 - 2

    我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]

  5. ruby-on-rails - 使用 gmaps4rails 动态加载谷歌地图标记 - 2

    如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail

  6. ruby - 动态方法链? - 2

    如何在对象上调用方法名称的嵌套哈希?例如,给定以下哈希:hash={:a=>{:b=>{:c=>:d}}}我想创建一个方法,给定上面的散列,执行以下操作:object.send(:a).send(:b).send(:c).send(:d)我的想法是我需要从一个未知的关联中获取一个特定的属性(这个方法不知道,但程序员知道)。我希望能够指定一个方法链来以嵌套哈希的形式检索该属性。例如:hash={:manufacturer=>{:addresses=>{:first=>:postal_code}}}car.execute_method_hash(hash)=>90210

  7. ruby - 如何使用 method_missing 动态声明方法? - 2

    我有一个ruby​​程序,我想接受用户创建的方法,并使用该名称创建一个新方法。我试过这个:defmethod_missing(meth,*args,&block)name=meth.to_sclass我收到以下错误:`define_method':interningemptystring(ArgumentError)in'method_missing'有什么想法吗?谢谢。编辑:我以不同的方式让它工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:defmethod_missing(meth,*args,&block)Adder.class_evaldodefine_method

  8. ruby - 动态扩展现有方法或覆盖 ruby​​ 中的发送方法 - 2

    假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入

  9. ruby - 使用 jbuilder 创建具有动态哈希键的 JSON - 2

    这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经

  10. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

随机推荐