kubernetes经过vertica pod autoscaler实现动态垂直缩放

kubernetes经过vertica pod autoscaler实现动态垂直缩放

今天给你们分享一下k8s的垂直缩放这块,生产中你可能对request的值配置不知道如何进行配置,设置的大小也不太清楚,大多数配置request都是本身去估量的去配置request,可能就是以本身项目可能的预期大小去配置,甚至直接和limit配置成同样,但对于request决定了你节点能够跑多少个pod,若是设置的过大,那么有可能你的pod就用不了那么多,也会形成资源的一些浪费,若是不设置,默认就共享宿主机的资源,你又不能评估出你节点还剩多少可利用的资源来使用,设置的过小,服务有可能还会起不来,那么如何更好的合理去利用本身的资源,这就是咱们须要重要考虑的事情html

pod垂直扩容会涉及到request的概念,因此这里我会多啰嗦一下request究竟是怎么回事和docker的cpu shares又有什么关系?node

kubernetes经过vertica pod autoscaler实现动态垂直缩放

垂直容器自动缩放器(VPA)简单说就是使用户无需设置最新的资源限制和对容器中容器的要求。
配置后,它将根据使用状况自动设置请求,从而容许在节点上进行适当的调度,以便为每一个Pod提供适当的资源量。 它还将保持限制和初始容器配置中指定的请求之间的比率。nginx

它既能够根据资源的使用状况来缩减对资源过分使用的Pod的规模,也能够对资源需求不足的向上扩展的Pod的规模进行扩展。
自动缩放是使用称为VerticalPodAutoscaler的自定义资源定义对象配置的。 它容许指定哪些吊舱应垂直自动缩放,以及是否/如何应用资源建议。git

简单来讲是 Kubernetes VPA 能够根据实际负载动态设置 pod resource requests。github

说到资源限制前面说一下request这块究竟是怎么回事?web

在咱们使用kubernetes的过程当中,咱们知道Pod 是最小的原子调度单位。这也就意味着,全部跟调度和资源管理相关的属性都应该是属于 Pod 对象的字段。而这其中最重要的部分,就是 Pod 的 CPU 和内存配置,以下所示:redis

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          requests:
            memory: "64Mi" 
            cpu: "250m"
          limits:
            memory: "128Mi" 
            cpu: "500m"

在 Kubernetes 中,像 CPU 这样的资源被称做“可压缩资源”(compressible resources)。它的典型特色是,当可压缩资源不足时,Pod 只会“饥饿”,但不会退出。而像内存这样的资源,则被称做“不可压缩资源(incompressible resources)。当不可压缩资源不足时,Pod 就会由于 OOM(Out-Of-Memory)被内核杀掉。docker

而因为 Pod 能够由多个 Container 组成,因此 CPU 和内存资源的限额,是要配置在每一个 Container 的定义上的。这样,Pod 总体的资源配置,就由这些 Container 的配置值累加获得。数据库

其中,Kubernetes 里为 CPU 设置的单位是“CPU 的个数”。好比,cpu=1 指的就是,这个 Pod 的 CPU 限额是 1 个 CPU。固然,具体“1 个 CPU”在宿主机上如何解释,是 1 个 CPU 核心,仍是 1 个 vCPU,仍是 1 个 CPU 的超线程(Hyperthread),彻底取决于宿主机的 CPU 实现方式。Kubernetes 只负责保证 Pod 可以使用到“1 个 CPU”的计算能力。centos

此外,Kubernetes 容许你将 CPU 限额设置为分数,好比在咱们的例子里,CPU limits 的值就是 500m。所谓 500m,指的就是 500 millicpu,也就是 0.5 个 CPU 的意思。这样,这个 Pod 就会被分配到 1 个 CPU 一半的计算能力。

固然,你也能够直接把这个配置写成 cpu=0.5。但在实际使用时,我仍是推荐你使用 500m 的写法,毕竟这才是 Kubernetes 内部通用的 CPU 表示方式。

而对于内存资源来讲,它的单位天然就是 bytes。Kubernetes 支持你使用 Ei、Pi、Ti、Gi、Mi、Ki(或者 E、P、T、G、M、K)的方式来做为 bytes 的值。好比,在咱们的例子里,Memory requests 的值就是 64MiB (2 的 26 次方 bytes) 。这里要注意区分 MiB(mebibyte)和 MB(megabyte)的区别。备注:1Mi=10241024;1M=10001000此外,不难看到,Kubernetes 里 Pod 的 CPU 和内存资源,实际上还要分为 limits 和 requests 两种状况,以下所示:

备注:1Mi=1024*1024;1M=1000*1000
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory

这二者的区别其实很是简单:在调度的时候,kube-scheduler 只会按照 requests 的值进行计算。而在真正设置 Cgroups 限制的时候,kubelet 则会按照 limits 的值来进行设置。更确切地说,当你指定了 requests.cpu=250m 以后,至关于将 Cgroups 的 cpu.shares 的值设置为 (250/1000)*1024。
那么咱们来验证一下这个cpu-shares具体的值
测试运行一个pod,这里我给的资源cpu限制是250m

#kubectl describe po nginx-846bc8d9d4-lcrzk |grep -A 2  Requests:
    Requests:
      cpu:        250m
      memory:     64Mi

如今已经交给了cgroups的cpu.shares的值进行配置,如何计算(250/1000)*1024=256
这个256份额值咱们能够经过下面的命令docker inspect 格式化直接获取到,咱们如今在docker所看到的256这个值则是pod咱们进行request设置的值

#docker ps |grep nginx |awk '{print $1}'|head -1 |xargs docker inspect --format '{{.Id}}:CpuShare={{.HostConfig.CpuShares}}'
b164dc1c62f7eb16a28dc0a14a26e0ef764a7517487d97e9d87883034380302a:CpuShare=256

而当你没有设置 requests.cpu 的时候,cpu.shares go模版的显示默认则是 2,可是咱们要知道实际上使用这里默认为1024,每个启动的容器份额为1024
只是显示的是这样表示
能够经过定位到pod的启动容器的具体目录查看

#cd  /sys/fs/cgroup/cpu/docker
#cat 709e4aeaea9331d09980d6f041e4fc0c8ff78c5d7477825852c076ffcc4fb3d5/cpu.shares 
1024

这样,Kubernetes 就经过 cpu.shares 完成了对 CPU 时间的按比例分配。
这里所说的时间分配又说到了cpu分配的优先级,也就是cpu-shares实际上是对cpu使用的一个优先分配的份额,咱们知道cpu是可压缩资源,当分配的时候也决定cpu谁有更快分配CPU的能力,咱们能够经过下面的测试来验证这个cpu-shares

计划我这里运行3个容器,为它们提供100、500和1000个cpu共享。

在后面,咱们将使用实际的Linux基准测试工具使用本身的工做台容器进行这些测试。咱们将特别关注在很是短的运行时运行这些占用CPU的系统,而且仍然能够获得准确的结果。

注意,dd、urandom和md5sum也不是工具,只是用来压测咱们的cpu-shares的分配的时间,谁更有优先去分配到cpu的能力

咱们的CPU压力应用程序:时间dd if=/dev/urandom bs=1M count=2 | md5sum

指标解释:

时间度量运行时间:显示这3个计时器行
dd if=/dev/urandom bs=1M count=2…复制bs=块大小1 MB 进行100次
md5sum……计算md5安全哈希值(给cpu一个负载)
让咱们运行它并调查结果:

docker container run -d --cpu-shares=1024 --name mycpu1024 alpine:3.8 /bin/sh -c 'time dd if=/dev/urandom bs=1M count=100 | md5sum'
docker container run -d --cpu-shares=500 --name mycpu500 alpine:3.8 /bin/sh -c 'time dd if=/dev/urandom bs=1M count=100 | md5sum'
docker container run -d --cpu-shares=100 --name mycpu100 alpine:3.8 /bin/sh -c 'time dd if=/dev/urandom bs=1M count=100 | md5sum'

查看并获取咱们的容器返回的数据日志

#docker logs mycpu1024
100+0 records in
100+0 records out
real    0m 0.96s
user    0m 0.00s
sys     0m 0.60s

#docker logs mycpu500
100+0 records in
100+0 records out
real    0m 0.99s
user    0m 0.00s
sys     0m 0.60s
b06118f07ce61d0e5a1201ad31659137  -

#docker logs mycpu100
100+0 records in
100+0 records out
real    0m 1.00s
user    0m 0.00s
sys     0m 0.60s
0046b35a22a48237cac7a75648e4e056  -

注意,全部容器都使用了相同的sys cpu时间这是能够理解的,由于它们都作了彻底相同的工做。
--cpu-share =100显然须要更长的时间,可是--cpu-share =500只比--cpu-share =1024稍微慢一点,这里我测试显示的和1024几乎同样,这跟测试也存在略微差异
问题是cpu-shares=1024运行很是快,而后退出。
那么咱们能够获得如下结论:
那么--CPU -shares=500和--CPU -shares=100具备对CPU的彻底访问权。

而后--CPU -shares=500个完成,由于它拥有最多的CPU共享。

而后--CPU -shares=1024快速完成,由于它拥有大多数CPU共享

通过这个测试我但愿你明白一个道理,pod进行配置的request资源的限制,其实和docker的cgroup作了一样的操做,只不过docker将对应的pod的值进行计算获得另一个值的形式显示出来,而计算的值则是(250/1000)*1024来计算的,request 的值不是指直接给容器实际分配的资源大小,它仅仅是给调度器看的,调度器会 "观察" 每一个节点能够用于分配的资源有多少,也知道每一个节点已经被分配了多少资源。被分配资源的大小就是节点上全部 Pod 中定义的容器 request 之和,它能够计算出节点剩余多少资源能够被分配(可分配资源减去已分配的 request 之和)。

分配的request的值若是没有限制则具备大多数cpu的共享,能够优先共享cpu资源。

另外我再说一下生产中的一个设置request的最佳实践

在你生产中你配置的资源限制,若是节点剩余可分配资源大小比当前要被调度的 Pod 的 reuqest 还小,那么就不会考虑调度到这个节点,反之,才可能调度。因此,若是不配置 request,那么调度器就不能知道节点大概被分配了多少资源出去,调度器得不到准确信息,也就没法作出合理的调度决策,很容易形成调度不合理,有些节点可能很闲,而有些节点可能很忙,甚至 NotReady。
因此,建议是给全部容器都设置 request,让调度器感知节点有多少资源被分配了,以便作出合理的调度决策,让集群节点的资源可以被合理的分配使用,避免陷入资源分配不均致使一些意外发生。

下面limit这里我也多啰嗦几句,后面回到主题~~
而若是你指定了 limits.cpu=500m 以后,则至关于将 Cgroups 的 cpu.cfs_quota_us 的值设置为 (500/1000)*100ms,而 cpu.cfs_period_us 的值始终是 100ms。这样,Kubernetes 就为你设置了这个容器只能用到 CPU 的 50%。

而对于内存来讲,当你指定了 limits.memory=128Mi 以后,至关于将 Cgroups 的 memory.limit_in_bytes 设置为 128 1024 1024。
咱们能够经过docker 模版查看

#docker ps |grep nginx
45676528fbea        nginx

咱们限制了128Mi则在docker的cgroup这么计算,12810241024获得cgroup的limit限制则是134217728字节

#docker ps --quiet --all |xargs docker inspect --format '{{.Id }}:Memory={{.HostConfig.Memory}}'
45676528fbea55a94b80553a8f1c57396c31aecc674b91eddb61024931ac11c9:Memory=134217728

而须要注意的是,在调度的时候,调度器只会使用 requests.memory=64Mi 来进行判断。
Kubernetes 这种对 CPU 和内存资源限额的设计,实际上参考了 Borg 论文中对“动态资源边界”的定义,既:容器化做业在提交时所设置的资源边界,并不必定是调度系统所必须严格遵照的,这是由于在实际场景中,大多数做业使用到的资源其实远小于它所请求的资源限额。

基于这种假设,Borg 在做业被提交后,会主动减少它的资源限额配置,以便容纳更多的做业、提高资源利用率。而看成业资源使用量增长到必定阈值时,Borg 会经过“快速恢复”过程,还原做业原始的资源限额,防止出现异常状况。而 Kubernetes 的 requests+limits 的作法,其实就是上述思路的一个简化版:用户在提交 Pod 时,能够声明一个相对较小的 requests 值供调度器使用,而 Kubernetes 真正设置给容器 Cgroups 的,则是相对较大的 limits 值。不难看到,这跟 Borg 的思路相通的。

下面回到正题~~~
kubernetes经过vertica pod autoscaler实现动态垂直缩放
当首先考虑垂直自动扩展可能意味着什么时,咱们会认为垂直pod自动扩展器将成为主机或VM垂直扩展的寓言,换句话说,就是增长该计算机上的资源量。若是VM正在使用4GB内存,而且正在使用3.8GB,则为该计算机提供额外的2GB可用空间。

例如,在vSphere世界中,咱们能够为虚拟机设置资源池,这多是有道理的;可是在Kubernetes世界中,这没有任何意义。
毕竟,Kubernetes只是位于主机顶部的调度程序。Kubelet肯定并报告主机已安装的资源量,并使用这些值和运行的工做负载所需的报告资源,调度程序肯定工做负载是否能够容纳在节点上。

那么垂直pod自动缩放在理论上能够采起什么形式?好吧,因为调度程序只有在报告了工做负载的请求和限制的状况下才能够有效地工做,所以设置真实的应用程序使用请求将使调度程序可以确保将可以使用的资源池中的该资源量确保能够在特定节点上用于该应用程序。若是任何一个群集节点上没有足够大的洞能够容纳该应用程序,这可能会阻止工做负载进行调度,可是一样,这保证了咱们能够在群集上运行现有的工做负载而不会压倒可用资源并使节点停机。

尽管VPA和HPA可能会针对相同的工做负载,可是因为VPA仅与CPU和内存资源配合使用,所以咱们不该对水平扩展使用相同的指标。因为VPA和HPA控制器目前尚不相互了解,所以这两个控制器可能会尝试对工做负载应用不兼容的更改。VPA能够做为水平自动缩放的补充,可是咱们必须对HPA使用分配非计算指标。
有了这些,咱们就能够深刻了解VPA的工做原理。

Kubernetes VPA 组成部分:
与HPA控制器不一样,默认状况下,实现垂直容器自动缩放的组件默认状况下未安装在Kube中,所以咱们将须要安装构成VPA架构的组件。有三个控制器可实现垂直吊舱自动缩放:

Recommender:用于根据监控指标结合内置机制给出资源建议值,自动扩展所需的初始任务是获取指标并肯定工做负载的当前使用状况。根据资源的当前和过去指标,推荐器将为每一个容器肯定一组“推荐”的CPU和内存值。

默认状况下,这将是metrics-server。因为metrics-server旨在将度量标准存储在内存中,所以它仅提供最近10分钟的度量标准。为了向推荐者提供其正在监视的服务的运行历史的更普遍的历史记录,你还能够从Prometheus等时间序列数据库中插入历史记录指标。

Updater:用于实时更新 pod resource requests,当检测到应将哪些“正确”请求委托给推荐程序时,更新程序控制器会将每一个部署的当前请求和建议请求与委托的垂直容器自动缩放器对象进行比较。若是部署的相应VPA对象的更新模式设置为“自动”或“从新建立”,则更新程序控制器将有助于建立包含新建议请求的新Pod。它不会使用新的推荐值直接更新Pod,而是指示Kube API应该从集群中退出特定Pod。它将依赖Kube主平面中的其余控制器来完成新容器的建立,并确保容器具备新的所需请求值。

History Storage:用于采集和存储监控数据

Admission Controller: 用于在 pod 建立时修改 resource requests,若是您已经弄清了什么是准入控制器及其用途,则VPA还包括一个变异的准入钩子。若是VPA对象的模式设置为“自动”,“从新建立”或“初始”,则该Webhook将在将Pod接纳到群集时注入由Recommender生成的当前请求值。

先看一下VPA这个对象

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  annotations:
  name: test-vpa
  namespace: dev
spec:
  resourcePolicy:
    containerPolicies:
    - containerName: '*'
      maxAllowed:
        memory: 1Gi
      minAllowed:
        memory: 500Mi
  targetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: test
  updatePolicy:
    updateMode: Recreate

看到这里咱们会发现有一些有趣的事情

经过使用分配器,resourcePolicy,咱们能够分配推荐器容许的最小和最大值,从而为推荐器如何改变Pod的CPU和内存资源提供一些界限。如何限制这些资源的使用状况取决于单个Pod中有多少个容器正在运行。

若是pod只有一个容器,则containerName: ‘*‘可使用设置通配符值。若是要将其应用于带有sidecar的pod,则固然须要基于每一个容器对值进行边界划分。应用通配符值没有意义,由于这将对每一个单个容器应用相同的内存值,并且我敢确定,你的容器中的每一个容器都不须要500-1000MB!
若是推荐者控制器可以提取指标,则它将在大约五分钟的内部时间内生成指标,而后将推荐内容写入VPA对象的状态块。

另外VPA会生成四个不一样的界限
这个值获取到这里并分为4个指标建议
一、 Lower Bound: 也就是最低的下限,容器的最小CPU和内存请求。不建议将其用做请求的基准
二、Target: 目标我理解为也就是平均值,也就是基线建议该容器的基线建议的CPU和内存请求
三、Uncapped Target,建议的CPU和内存请求,但不考虑ContainerResourcePolicy中定义的限制
四、Upper Bound 上限,建议的最大CPU和内存请求。

它的架构是这样的来自官方图片
kubernetes经过vertica pod autoscaler实现动态垂直缩放
vpa的工做流程它是这样的:
Recommender在启动时从History Storage获取历史数据,根据内置机制修改VPA API object资源建议值。Updater监听VPA API object,依据建议值动态修改 pod resource requests。VPA Admission Controller则是用于 pod 建立时修改 pod resource requests。History Storage则是经过Kubernetes Metrics API采集和存储监控数据

如今开始部署vpa,部署可参考个人github
https://github.com/zhaocheng173/vpa

一、如今开始部署vpa,前提保证metics server正常工做 , 部署metrics server 、vpa我已经都上传到github上,部署沟通遇到问题,能够联系我
部署metrics server为了使推荐程序可以接收Pod指标,metrics-server也须要在集群上运行。因为metrics-server旨在将度量标准存储在内存中,所以它仅提供最近10分钟的度量标准。为了向VPA推荐器提供其正在监视的服务的运行历史的更普遍的历史记录,另外你还能够从Prometheus等时间序列数据库中插入历史记录指标。

#kubectl top node 
 NAME   CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
 ma     2245m        28%    2801Mi          36%       
 mb     2453m        30%    2947Mi          18%       
 mc     2356m        58%    2374Mi          30%       
 md     308m         15%    709Mi           40%

二、须要依赖openssl-1.1.1 最佳实践须要安装openssl-1.1.1 查看默认版本的openssl version是 1.0.2k-fips,若是直接安装的话是失败的,它会报一个错误,vpa-admission-controller这个pod会始终处于建立之中,会找不到证书,缘由低版本的openssl没有生成证书的命令,有一个称为vpa-tls-certs,它安装在包含证书捆绑包的准入控制器中

因此咱们须要升级openssl 第一步卸载yum安装的openssl
rpm -e --nodeps openssl

安装组件依赖
yum install libtool perl-core zlib-devel -y

下载1.1.1的openssl,默认个人环境为centos-7.6,centos的部署基本大体相同,下面放了一个下载openssl的地址,可供选择
https://www.openssl.org/docs/man1.1.1/man1/req.html

#cd /usr/local/src
#tar -zxf openssl-1.1.1g-latest.tar.gz

#cd openssl-1.1.1g
#./config
#make
#make test
#make install

#ln -s /usr/local/bin/openssl /usr/bin/openssl

加载共享库libssl.so.1.1时如何解决openssl错误 若是安装成功查看版本若有如下报错 查看openssl version openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
调试 咱们尝试找到名为libssl.so.1.1的文件,以下所示: 咱们能够发现'libcrypto.so.1.1'位于/ usr / local / lib64中,可是openssl尝试在LD_LIBRARY_PATH中找到.so库。

[root@master ~]# ll /usr/local/lib64
  总用量 10480
  drwxr-xr-x 2 root root      39 8月   7 14:23 engines-1.1
  -rw-r--r-- 1 root root 5630906 8月   7 14:23 libcrypto.a
  lrwxrwxrwx 1 root root      16 8月   7 14:23 libcrypto.so -> libcrypto.so.1.1
  -rwxr-xr-x 1 root root 3380224 8月   7 14:23 libcrypto.so.1.1
  -rw-r--r-- 1 root root 1024200 8月   7 14:23 libssl.a
  lrwxrwxrwx 1 root root      13 8月   7 14:23 libssl.so -> libssl.so.1.1
  -rwxr-xr-x 1 root root  685528 8月   7 14:23 libssl.so.1.1
  drwxr-xr-x 2 root root      61 8月   7 14:23 pkgconfig
  [root@master ~]# ll /usr/local/lib64/libssl*
  -rw-r--r-- 1 root root 1024200 8月   7 14:23 /usr/local/lib64/libssl.a
  lrwxrwxrwx 1 root root      13 8月   7 14:23 /usr/local/lib64/libssl.so -> libssl.so.1.1
  -rwxr-xr-x 1 root root  685528 8月   7 14:23 /usr/local/lib64/libssl.so.1.1

所以,解决方案是尝试告诉openssl库在那里。 解决方法 建立到文件的连接

[root@localhost openssl-1.1.g]# ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
 [root@localhost openssl-1.1.g]# ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1

看到openssl的版本为如下,就能够部署了

#openssl version
OpenSSL 1.1.1g  21 Apr 2020

三、开始部署

[root@master hack]# ./vpa-up.sh 这次省略 ........
Generating certs for the VPA Admission Controller in /tmp/vpa-certs.
Generating RSA private key, 2048 bit long modulus (2 primes)
................................+++++
.+++++
e is 65537 (0x010001)
Generating RSA private key, 2048 bit long modulus (2 primes)
.............................................+++++
.............................+++++
e is 65537 (0x010001)
Signature ok
subject=CN = vpa-webhook.kube-system.svc
Getting CA Private Key
Uploading certs to the cluster.
secret/vpa-tls-certs created
Deleting /tmp/vpa-certs.
deployment.apps/vpa-admission-controller created
service/vpa-webhook created

最后效果为成功部署

[root@master hack]# kubectl get po -A
kube-system   vpa-admission-controller-69c96bd8bd-4st7v   1/1     Running     0          39s
kube-system   vpa-recommender-765b6c5f59-rdxk4            1/1     Running     0          45s
kube-system   vpa-updater-86865896cf-z8bxn                1/1     Running     0          50s

如今去检查Vertical Pod Autoscaler是否在您的集群中彻底正常运行的一种简单方法是建立示例部署和相应的VPA配置:

---
apiVersion: "autoscaling.k8s.io/v1beta2"
kind: VerticalPodAutoscaler
metadata:
  name: hamster-vpa
  namespace: kube-system
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: hamster
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 50Mi
        maxAllowed:
          cpu: 1
          memory: 500Mi
        controlledResources: ["cpu", "memory"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hamster
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: hamster
  replicas: 2
  template:
    metadata:
      labels:
        app: hamster
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody
      containers:
        - name: hamster
          image: nginx
          resources:
            requests:
              cpu: 100m
              memory: 50Mi
          command: ["/bin/sh"]
          args:
            - "-c"
            - "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"

kubectl create -f examples/hamster.yaml

Start deploying the Ceph cluster

上面的命令建立了一个包含2个Pod的部署,每一个Pod运行一个请求100m的容器,并尝试使用最高不超于500m的容器。该命令还会建立一个指向部署的VPA配置。VPA将观察Pod的行为,大约5分钟后,它们应使用更高的CPU请求进行更新(请注意,VPA不会在部署中修改模板,但Pod的实际请求会被更新)。

要查看VPA配置和当前推荐的资源请求,能够运行如下命令:

#kubectl get vpa -A
NAMESPACE     NAME          AGE
kube-system   hamster-vpa   15m

如今咱们的在yaml中配置的默认值是如下配置

requests:
              cpu: 100m
              memory: 50Mi

大概等待60s以后pod会重建,vpa会通知pod更新request
这里能够看到再次pod的请求的request的值已经被更新为627m

#kubectl get pod -o=custom-columns=NAME:.metadata.name,PHASE:.status.phase,CPU-REQUEST:.spec.containers\[0\].resources.requests.cpu
NAME                       PHASE     CPU-REQUEST
hamster-7df5c45bbc-jzpg2   Running   627m
hamster-7df5c45bbc-knqfv   Running   627m

#kubectl describe vpa nginx-deployment-basic -n kube-system

另外这个值获取到这里并分为4个指标建议上我们说到过,这个值是实时推荐的,默认重启后推荐的值也是target的值

Recommendation:
    Container Recommendations:
      Container Name:  hamster
      Lower Bound:
        Cpu:     578m
        Memory:  262144k
      Target:
        Cpu:     627m
        Memory:  262144k
      Uncapped Target:
        Cpu:     627m
        Memory:  262144k
      Upper Bound:
        Cpu:     1
        Memory:  262144k

那么这种状况下咱们操做会致使咱们的pod会重启,也会将pod调度到其余的节点,对于不设置任何调度规则的话,这样对于咱们的业务确定会受到影响,即便设置了调度规则,request会重启也会正常影响咱们的业务
全部使用VPA须要注意如下在环境中的事项

VPA不会驱逐没有在副本控制器管理下的Pod。目前对于这类Pod,Auto模式等同于Initial模式。
目前VPA不能和监控CPU和内存度量的Horizontal Pod Autoscaler (HPA)同时运行,除非HPA只监控其余定制化的或者外部的资源度量。
VPA使用admission webhook做为其准入控制器。若是集群中有其余的admission webhook,须要确保它们不会与VPA发生冲突。准入控制器的执行顺序定义在API Server的配置参数中。
VPA会处理绝大多数OOM(Out Of Memory)的事件,但不保证全部的场景下都有效。
VPA的性能尚未在大型集群中测试过。
VPA对Pod资源requests的修改值可能超过实际的资源上限,例如节点资源上限、空闲资源或资源配额,从而形成Pod处于Pending状态没法被调度。同时使用集群自动伸缩(ClusterAutoscaler)能够必定程度上解决这个问题。
多个VPA同时匹配同一个Pod会形成未定义的行为。

VPA在四种模式下运行
"Auto":将使用指定的更新机制在pod启动时和pod处于活动状态时分配请求值。目前,这等效于“从新建立”,由于当前没有用于更新实时Pod上的请求值的“就地”机制

"Recreate":将在容器启动时分配请求值,而且,若是当前推荐值与当前请求值相差很大,则将驱逐该容器并建立一个新的容器。

"Initial":VPA仅在pod建立时分配资源请求,之后不再会更改它们。

"Off":VPA不会自动更改容器的资源要求。将计算建议,并能够在VPA对象中对其进行检查。

咱们其实要作的就是不采用Auto的形式,只经过推荐参考的形式,将历史给出的target做为咱们项目参考的request值

如今运行一个redis的示例,并获取vpa推荐的值

---
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  name: redis-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: redis-master
  updatePolicy:
    updateMode: "Off"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-master
  labels:
    app: redis
spec:
  selector:
    matchLabels:
      app: redis
  replicas: 3
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: master
          image: redis  # or just image: redis
          ports:
            - containerPort: 6379

由于咱们没有设置request因此没有资源的请求进行配置

#kubectl get pod  -o=custom-columns=NAME:.metadata.name,PHASE:.status.phase,CPU-REQUEST:.spec.containers\[0\].resources.requests.cpu |grep -w redis
redis-master-59fcd7f58f-5q88d   Running   <none>
redis-master-59fcd7f58f-htmzj   Running   <none>
redis-master-59fcd7f58f-x8bp6   Running   <none>

因此只会将值发送到vpa,能够describe vpa能够看到target的值

#kubectl describe vpa redis-vpa |awk '/Container Recommendations:/,/Events/{if(i>1)print x;x=$0;i++}'
      Container Name:  master
      Lower Bound:
        Cpu:     25m
        Memory:  262144k
      Target:
        Cpu:     25m
        Memory:  262144k
      Uncapped Target:
        Cpu:     25m
        Memory:  262144k
      Upper Bound:
        Cpu:     329m
        Memory:  262144k

最后咱们就能够根据推荐值来实际配置Deployment中资源的requests。VPA会持续的监控应用资源的使用状况,并提供优化建议。经过将target的值能够根据换算进行使用到咱们的生产环境当中

相关文章
相关标签/搜索