一文帶你掌握Kubernetes VPA(Pod縱向自動擴縮)
簡介
之前的文章我們介紹了HPA(Horizontal Pod Autoscaler)的實現,HPA一般被稱為橫向擴展,與HPA不同的Vertical Pod Autoscaler ( VPA ) 會自動調整 Pod 的 CPU 和內存屬性,被稱為縱向擴展。VPA可以給出服務運行所適合的CPU和內存配置,省去估計服務占用資源的時間,更合理的使用資源。當然,VPA也可根據資源的使用情況“調整”pod的資源。這里的調整我們用了雙引號,因為他的實現機制是重建而不是動態增加。下面是一個實際的例子:假設我的memory limits是100Mi,但是現在已經用到了98Mi,如果再大的話就oom了,此時vpa會在垂直方向上提升你的memory limits的大小。這種vpa比較適合一些資源消耗比較大的應用,例如es,你給大了資源浪費,給小了,又不夠。所以vpa就派上用場了。當然,vpa不像hpa默認集成在k8s里面的,需要你自己去配置的。
VPA 與 HPA
從根本上來說,VPA 和 HPA 之間的區別在于它們的擴展方式。HPA 通過添加或刪除pod進行擴展,從而水平擴展容量。然而,VPA 通過增加或減少現有 Pod 容器內的 CPU 和內存資源來進行擴展,從而垂直擴展容量。下表更詳細地解釋了 Kubernetes VPA 和 HPA 之間的差異。
需要調整容量 | 水平縮放 (HPA) | 垂直縮放 (VPA) |
更多資源 | 添加更多 Pod | 增加現有 pod 容器的 CPU 或內存資源 |
資源較少 | 刪除 Pod | 減少現有 Pod 容器的 CPU 或內存資源 |
工作原理
圖片
VPA 的組成部分
VPA 部署具有三個主要組件:VPA Recommender、VPA Updater和VPA Admission Controller。讓我們看一下每個組件的作用。VPA Recommender:
- 監控資源利用率并計算目標值。
- 查看指標歷史記錄、OOM 事件和 VPA 部署規范并建議公平請求。根據定義的限制請求比例提高/降低限制。
VPA 更新程序:
- 驅逐那些需要新資源限制的 Pod。
- 如果定義了“updateMode: Auto”,則實現推薦器建議的任何內容。
VPA 準入控制器:
- 每當 VPA 更新程序逐出并重新啟動 Pod 時,都會在新 Pod 啟動之前更改 CPU 和內存設置(使用 Webhook)。
- 當 Vertical Pod Autoscaler 設置為“Auto”的 updateMode 時,如果需要更改 Pod 的資源請求,則驅逐 Pod。由于 Kubernetes 的設計,修改正在運行的 pod 的資源請求的唯一方法是重新創建 pod。
Kubernetes VPA 工作模式
圖片
- 用戶配置VPA。
- VPA Recommender 從指標服務器讀取 VPA 配置和資源利用率指標。
- VPA Recommender 提供 Pod 資源推薦。
- VPA Updater 讀取 Pod 資源建議。
- VPA Updater 啟動 Pod 終止。
- 部署意識到 Pod 已終止,并將重新創建 Pod 以匹配其副本配置。
- 當 Pod 處于重新創建過程中時,VPA 準入控制器會獲取 Pod 資源推薦。由于 Kubernetes 不支持動態更改正在運行的 pod 的資源限制,因此 VPA 無法使用新的限制更新現有 pod。它會終止使用過時限制的 pod。當 Pod 的控制器向 Kubernetes API 服務請求替換時,VPA 準入控制器會將更新的資源請求和限制值注入到新 Pod 的規范中。
- 最后,VPA 準入控制器會覆蓋對 Pod 的建議。在我們的示例中,VPA 準入控制器向 Pod 添加了一個“250m”CPU。
最佳實踐
既然你知道了大致原理,讓我們開始動手操作你吧
克隆代碼
# git clone https://github.com/kubernetes/autoscaler.git
由于某些原因拉不到鏡像,改yaml修改優先使用本地鏡像
# cd autoscaler/vertical-pod-autoscaler/deploy
# sed -i 's/Always/IfNotPresent/g' recommender-deployment.yaml
# sed -i 's/Always/IfNotPresent/g' admission-controller-deployment.yaml
# sed -i 's/Always/IfNotPresent/g' updater-deployment.yaml
# 拉取鏡像
# docker pull giantswarm/vpa-admission-controller:0.14.0
# docker pull giantswarm/vpa-recommender:0.14.0
# docker pull giantswarm/vpa-updater:0.14.0
# 修改tag
# docker tag giantswarm/vpa-updater:0.14.0 registry.k8s.io/autoscaling/vpa-updater:0.14.0
# docker tag giantswarm/vpa-recommender:0.14.0 registry.k8s.io/autoscaling/vpa-recommender:0.14.0
# docker tag giantswarm/vpa-admission-controller:0.14.0 registry.k8s.io/autoscaling/vpa-admission-controller:0.14.0
# cd autoscaler/vertical-pod-autoscaler/hack
# 安裝腳本安裝之前保證你的K8S集群的metrics-server已安裝,并且openssl升級到1.1.1或更高版本
# ./vpa-up.sh
等待安裝完成
# kubectl get pods -n kube-system | grep vpa
kube-system vpa-admission-controller-75bffbf8d8-6hxqq 1/1 Running 0 5m9s
kube-system vpa-recommender-748c55b5bf-kqqjc 1/1 Running 0 4m34s
kube-system vpa-updater-679d5dcdd6-lslc7 1/1 Running 0 4m15s
使用VPA,您需要為要自動計算資源需求的每個控制器插入一個Vertical Pod Autoscaler資源。這將是最常見的Deployment。VPA有四種運行模式
- "Auto":VPA 在創建 pod 時分配資源請求,并使用首選更新機制在現有 pod 上更新它們。目前這相當于"Recreate"(見下文)。一旦 pod 請求的免重啟(“就地”)更新可用,它可能會被該"Auto"模式用作首選的更新機制。注意:VPA 的此功能是實驗性的,可能會導致您的應用程序停機,當目前運行的pod的資源達不到VPA的推薦值,就會執行pod驅逐,重新部署新的足夠資源的服務
- "Recreate":VPA 在創建 Pod 時分配資源請求,并在現有 Pod 上更新它們,當請求的資源與新建議有很大差異時(尊重 Pod 中斷預算,如果定義)。這種模式應該很少使用,只有當您需要確保在資源請求發生變化時重新啟動 Pod 時。否則,更喜歡這種"Auto"模式,一旦它們可用,就可以利用重新啟動免費更新。注意:VPA 的此功能是實驗性的,可能會導致您的應用程序停機
- "Initial":VPA 僅在創建 pod 時分配資源請求,以后不會更改它們
- "Off":VPA 不會自動更改 Pod 的資源需求。這些建議是經過計算的,并且可以在 VPA 對象中進行檢查。這種模式僅獲取資源推薦值,但是不更新Pod
創建一個updateMode: Auto 的VPA
# 將updateMode中的requests 改為 CPU:50m,Memory: 50Mi,同時將updateMode修改為Auto
# 創建一個pod和svc
# kubectl get pods -n vpa
NAME READY STATUS RESTARTS AGE
nginx-8454bb78d8-67pth 1/1 Running 0 9s
nginx-8454bb78d8-6efsh 1/1 Running 0 9s
# kubectl get svc -n vpa
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.0.200.5 <none> 80:45425/TCP 15s
# 進行壓測,壓測到一半時,突然連接斷了,說明POD被重新創建了
# ab -c 1000 -n 100000 http://192.168.0.191:45425/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.0.191 (be patient)
apr_socket_recv: Connection reset by peer (104)
Total of 187078 requests completed
# 查看vpa
# kubectl describe vpa nginx-vpa -n vpa | tail -n 20
Conditions:
Last Transition Time: 2023-09-07T15:41:32Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound: #容器的最小估計值
Cpu: 100m
Memory: 262144k
Target: #目標估計是我們用于設置資源請求的估計
Cpu: 350m
Memory: 262144k
Uncapped Target: #無上限目標估計是在沒有minAllowed和maxAllowed限制的情況下產生的目標估計
Cpu: 350m
Memory: 262144k
Upper Bound: #上限是容器的最大建議資源估計
Cpu: 2
Memory: 405160855
Events: <none>
# 查看pod被重新創建了 稍高的配置
# kubectl get pods -n vpa
NAME READY STATUS RESTARTS AGE
nginx-daecsfv8d8-see8h 1/1 Running 0 4m
nginx-daecsfv8d8-fsise 1/1 Running 0 3m
已知的限制
- 每當 VPA 更新 Pod 資源時,都會重新創建 Pod,這會導致重新創建所有正在運行的容器。Pod 可以在不同的節點上重新創建。
- VPA 無法保證它驅逐或刪除以應用建議(在Auto和Recreate模式下配置時)的 pod 將成功重新創建。通過將 VPA 與Cluster Autoscaler結合使用可以部分解決這個問題。
- VPA 不會更新不在控制器下運行的 Pod 的資源。
- 目前,Vertical Pod Autoscaler不應與CPU 或內存上的Horizontal Pod Autoscaler (HPA)一起使用。但是,您可以在自定義和外部指標上將 VPA 與 HPA結合使用。
- VPA 準入控制器是一個準入 Webhook。如果您將其他準入 Webhook 添加到集群中,則分析它們如何交互以及它們是否可能相互沖突非常重要。準入控制器的順序由 API 服務器上的標志定義。
- VPA 會對大多數內存不足事件做出反應,但并非在所有情況下都會做出反應。
- VPA 性能尚未在大型集群中進行測試。
- VPA 建議可能會超出可用資源(例如節點大小、可用大小、可用配額)并導致Pod 處于掛起狀態。通過將 VPA 與Cluster Autoscaler結合使用可以部分解決這個問題。
- 與同一 Pod 匹配的多個 VPA 資源具有未定義的行為。
總結
在本文中,我們使用VPA實現了基于POD對配置進行橫向擴展,合理的使用可以提高對K8S的利用率,實現降本增效。但是目前的VPA也存在一些問題,我個人覺得VPA最大的問題是會對服務進行重建,重建過程中可能會有流量損失,但是好消息是從1.27 版本動態調整容器CPU和內存資源限制,無需重啟應用程序,在可見的將來,會實現動態擴容更加順滑,讓我們一起期待~