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的值能夠根據換算進行使用到咱們的生產環境當中

相關文章
相關標籤/搜索