跳至主要内容

AutoScaling - Vertical Pod AutoScaler

什麼是 Vertical Pod Autoscaler?

vertical-pod-autoscaler

Vertical Pod Autoscaler(VPA) 是 Kubernetes 提供的一種資源自動調整機制,主要用於 動態調整 Pod 的 CPU 和記憶體資源,以確保應用程式能夠獲得適當的資源,提升效能並降低不必要的資源浪費。 與 Horizontal Pod Autoscaler(HPA) 不同,VPA 是透過 調整單個 Pod 的資源限制(CPU / Memory Requests & Limits) 來最佳化資源使用。


VPA 的核心功能

  1. 自動調整 Pod 資源分配
    • 根據實際負載,動態調整 CPU 和記憶體的 requestslimits,減少過多配置造成的浪費,或避免資源不足導致的效能問題。
  2. 避免 OOM(Out of Memory)問題
    • 如果 Pod 需要的記憶體超出當前配置,VPA 會根據需求增加 requests,防止因為記憶體不足而導致 Pod Crash。
  3. 提供資源建議(Recommendation Mode)
    • VPA 可以運行在 推薦模式(Recommend Only),提供合適的資源配置建議,而不會自動調整 Pod 配置,讓使用者自行決定是否採納建議。
  4. 與 HPA 搭配使用
    • 雖然 VPA 和 HPA 主要解決不同層面的資源管理問題,但它們可以搭配使用,例如:VPA 負責調整個別 Pod 的資源請求,而 HPA 負責擴展 Pod 的數量,以確保應用的高可用性和擴展性。

VPA 的運作方式

vertical-pod-autoscaler

VPA 由三個主要元件組成:

  1. Recommender(建議器)
    • 負責監控 Pod 的資源使用情況,並根據歷史數據計算出最佳的 CPU/記憶體需求,提供建議值。
  2. Updater(更新器)
    • 負責檢查現有的 Pod 是否需要調整資源分配。若需要,會重新建立新的 Pod(因為 Kubernetes 不允許直接修改 Pod 的 requestslimits)。
  3. Admission Controller(准入控制器)
    • 在 Pod 創建時,自動為其設定適當的資源限制,確保新創建的 Pod 符合 VPA 的建議配置。

VPA 配置範例

這個 VPA 物件會 自動調整 CPU 和記憶體的 Requests

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: hamster-vpa
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: hamster
updatePolicy:
updateMode: 'Auto' # 可選 "Off"、"Initial"、"Recreate" 或 "Auto"
resourcePolicy:
containerPolicies:
- containerName: hamster
minAllowed:
cpu: 50m
memory: 20Mi
maxAllowed:
cpu: 2
memory: 1Gi
controlledResources: ['cpu', 'memory']

VPA 指標類型

spec.updatePolicy.updateMode

updateMode 控制 VPA 如何調整 Pod 的 requests,它有四種模式:

模式行為
"Off"VPA 只提供建議,不會自動調整 Pod。需要手動查詢 VPA 建議值。
"Initial"只會在 Pod 啟動時調整 requests,之後不再更新。適合對變動不大的應用。
"Recreate"調整 requests 需要刪除並重新建立 Pod,因此會有停機時間。適合 無法動態調整 requests 的應用。
"Auto"自動調整 requests,並盡量避免重啟 Pod(適用於支援動態資源變更的應用)。

應用場景

  • "Off" → 只想查看 VPA 的建議值,而不讓它自動調整。
  • "Initial" → 適合批次工作(Batch Jobs),只在啟動時設定合適的 requests
  • "Recreate" → 適合 無法動態變更 requests 的應用,例如某些基於 Java 的應用。
  • "Auto"推薦選擇,適合大部分應用,能動態調整 requests 而不影響運行。

spec.resourcePolicy.containerPolicies

containerPolicies 用來 設定 VPA 允許調整的資源範圍,細分如下:

欄位功能
containerName指定要調整的容器名稱。可以是特定名稱或 "*"(代表所有容器)。
minAllowedVPA 允許的最小 requests 限制,低於此值不會調整。
maxAllowedVPA 允許的最大 requests 限制,超過此值不會調整。
controlledResources指定要調整的資源類型,可以是 "cpu""memory",或 ["cpu", "memory"]
controlledValues(選填)可選 "RequestsAndLimits""RequestsOnly",預設為 "RequestsOnly"

VPA 適用場景

  • 機器學習 / 批次處理應用:這些應用對 CPU 和記憶體有較高需求,VPA 能夠確保它們獲得足夠的資源。
  • 長時間運行的應用:對於一些長時間運行的應用(如資料庫、後台服務),VPA 能夠根據歷史負載逐步調整資源配置,提升效能。
  • 預算受限的應用:當需要節省資源成本時,VPA 可以幫助減少不必要的 CPU/記憶體配置,避免浪費。

VPA 使用限制

  1. VPA 需要重啟 Pod
    • 由於 Kubernetes 不允許動態修改 Pod 的 requestslimits,所以 VPA 在調整資源時會刪除舊 Pod 並重新創建新 Pod,可能會導致短暫的停機時間。
  2. 與 HPA 可能衝突
    • 如果 HPA 依據 CPU/記憶體來擴展 Pod 數量,而 VPA 同時調整 CPU/記憶體的請求值,可能會產生資源配置衝突,因此通常 HPA 會基於自定義指標(如請求數量)運行,而 VPA 負責 CPU/Memory 的最佳化。
  3. 無法適用於 Request 量變化大但資源需求小的應用
    • 例如 Web 伺服器流量高峰時,VPA 可能無法應對突發負載,而 HPA 透過 Pod 水平擴展更適合這種場景。

VPA vs HPA

特性VPA(垂直擴展)HPA(水平擴展)
調整方式增加 / 減少 Pod 的 CPU & 記憶體增加 / 減少 Pod 的數量
適用場景Pod 內部負載變化,但整體數量不需變動需要擴展 Pod 數量來應對流量變化
影響需要重新啟動 Pod無須重啟,可動態擴展
監控指標CPU / Memory 使用率CPU / Memory / 自定義指標
與 HPA 的搭配可以共同使用,但須避免衝突可以與 VPA 配合,針對不同需求調整

實作一個 VPA

確認 Metrics Server 是否有成功執行

  1. 首先我們可以觀察 Node 的狀態,來確認 Metrics Server 是否有正確執行。
kubectl.exe top node
---

NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
docker-desktop 155m 0% 3487Mi 22%

安裝 Custom Resource - VPA

因為官方的內建的 API 只有支援 HPA 而已,如果我們需要用到 cluster autoscalervertical autoscaler 等 CRD 時,則需要以模組的方式載入。

  1. 因為安裝需要/bin/sh,首先我們先安裝 Windows Subsystem for Linux (WSL),登出後需要重新啟動。
wsl --install
---

安裝: Ubuntu
Ubuntu 已安裝。
正在啟動 Ubuntu...
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: calvin
New password:
Retype new password:
passwd: password updated successfully
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro

System information as of Tue Feb 4 20:29:43 CST 2025

System load: 0.44 Processes: 87
Usage of /: 0.1% of 1006.85GB Users logged in: 0
Memory usage: 23% IPv4 address for eth0: 172.22.44.200
Swap usage: 0%


This message is shown once a day. To disable it please create the
/home/calvin/.hushlogin file.
calvin@DESKTOP-PT7UK12:~$
calvin@DESKTOP-PT7UK12:~$ exit
---

logout
操作順利完成。
  1. 登入 WSL 進到 Ubuntu 的環境。
wsl -d Ubuntu
---

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

calvin@DESKTOP-PT7UK12:/mnt/c/Users/calvin$
  1. 因為是全新的環境,需要重新安裝 kubectl,並確認 kubectl 可以執行。
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client
---

Client Version: v1.32.1
Kustomize Version: v5.5.0
  1. 接著我們載入原本 docker desktop 預設的 kube config,這樣我們就能透過 wsl 的 kubectl 去操作本機的 kubernetes,並且確認 nodes 有正確被讀取到。
export KUBECONFIG=/mnt/c/Users/你的Windows帳號/.kube/config
kubectl get nodes
---

NAME STATUS ROLES AGE VERSION
docker-desktop Ready control-plane 111d v1.27.2
  1. cd 到想要安裝的資料夾下,透過官方的 autoscaler repo 來進行 VPA 的安裝,首先我們從 git 上下載 repository。
calvin@DESKTOP-PT7UK12:/mnt/d/kubernetes-from-another-world/ch27$ git clone https://github.com/kubernetes/autoscaler.git
---

Cloning into 'autoscaler'...
remote: Enumerating objects: 217215, done.
remote: Counting objects: 100% (2251/2251), done.
remote: Compressing objects: 100% (1404/1404), done.
remote: Total 217215 (delta 1546), reused 848 (delta 847), pack-reused 214964 (from 3)
Receiving objects: 100% (217215/217215), 244.18 MiB | 1.36 MiB/s, done.
Resolving deltas: 100% (139908/139908), done.
Updating files: 100% (7918/7918), done.
  1. 接著進到這個專案的資料夾之中,要進行安裝。
calvin@DESKTOP-PT7UK12:/mnt/d/kubernetes-from-another-world/ch27$ cd ./autoscaler/vertical-pod-autoscaler/
---

calvin@DESKTOP-PT7UK12:/mnt/d/kubernetes-from-another-world/ch27/autoscaler/vertical-pod-autoscaler$
  1. 執行./hack/vpa-up.sh 安裝,如果沒有任何 Error 就代表成功囉!
calvin@DESKTOP-PT7UK12:/mnt/d/kubernetes-from-another-world/ch27/autoscaler/vertical-pod-autoscaler$ ./hack/vpa-up.sh
---

HEAD is now at 200a292f8 Merge pull request #7774 from jm-franc/vpa-finalize-branch
customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalercheckpoints.autoscaling.k8s.io created
customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalers.autoscaling.k8s.io created
clusterrole.rbac.authorization.k8s.io/system:metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:vpa-actor created
clusterrole.rbac.authorization.k8s.io/system:vpa-status-actor created
clusterrole.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created
clusterrole.rbac.authorization.k8s.io/system:evictioner created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-actor created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-status-actor created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created
clusterrole.rbac.authorization.k8s.io/system:vpa-target-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-target-reader-binding created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-evictioner-binding created
serviceaccount/vpa-admission-controller created
serviceaccount/vpa-recommender created
serviceaccount/vpa-updater created
clusterrole.rbac.authorization.k8s.io/system:vpa-admission-controller created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-admission-controller created
clusterrole.rbac.authorization.k8s.io/system:vpa-status-reader created
clusterrolebinding.rbac.authorization.k8s.io/system:vpa-status-reader-binding created
role.rbac.authorization.k8s.io/system:leader-locking-vpa-updater created
rolebinding.rbac.authorization.k8s.io/system:leader-locking-vpa-updater created
role.rbac.authorization.k8s.io/system:leader-locking-vpa-recommender created
rolebinding.rbac.authorization.k8s.io/system:leader-locking-vpa-recommender created
deployment.apps/vpa-updater created
deployment.apps/vpa-recommender created
Generating certs for the VPA Admission Controller in /tmp/vpa-certs.
Certificate request self-signature ok
subject=CN = vpa-webhook.kube-system.svc
Uploading certs to the cluster.
secret/vpa-tls-certs created
Deleting /tmp/vpa-certs.
deployment.apps/vpa-admission-controller created
service/vpa-webhook created
  1. 退出 WSL 之後,我們可以看到三個重要的 Pod 被正確執行,並且 api-resources 也能看到我們可以使用 VPA 了。
kubectl.exe get pods -n kube-system | Select-String "vpa"
---

vpa-admission-controller-66c599944b-8gxtj 1/1 Running 0 3m26s
vpa-recommender-5bcb9f847-mkx9r 1/1 Running 0 3m26s
vpa-updater-7fbd7cf94b-95r6x 1/1 Running 0 3m26s
kubectl.exe api-resources | Select-String "vpa"
---

verticalpodautoscalercheckpoints vpacheckpoint autoscaling.k8s.io/v1 true VerticalPodAutoscalerCheckpoint
verticalpodautoscalers vpa autoscaling.k8s.io/v1 true VerticalPodAutoscaler

製作一個 VPA

  1. 首先我們先製作一個 deployment,做為後續 VPA 調整的對象。
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamster
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: hamster
template:
metadata:
labels:
app: hamster
spec:
containers:
- name: hamster
image: registry.k8s.io/ubuntu-slim:0.1
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
cpu: '2'
memory: 2Gi
command: ['/bin/sh']
args:
- '-c'
- 'while true; do timeout 0.2s yes > /dev/null; sleep 0.5s; done'
  1. 接著設定 VPA,讓他根據 CPU 和 Memory 的使用量來調整 deployment。
vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler # 指定這是一個 VPA 資源
metadata:
name: hamster-vpa # VPA 資源的名稱
namespace: default # VPA 作用的命名空間
spec:
targetRef: # 目標 Pod(Deployment、StatefulSet、DaemonSet)
apiVersion: apps/v1 # 目標物件的 API 版本
kind: Deployment # 目標物件類型
name: hamster # 目標 Deployment 的名稱
updatePolicy:
updateMode: 'Off'
resourcePolicy: # 設定 VPA 監控與調整的資源範圍
containerPolicies:
- containerName: '*' # "*" 代表影響所有容器(可能無效,建議使用具體容器名稱)
minAllowed: # 設定資源的最小限制,避免 VPA 降得太低
cpu: '100m' # 最低 CPU 限制為 100m(0.1 vCPU)
memory: '50Mi' # 最低記憶體限制為 50Mi(50MB)
maxAllowed: # 設定資源的最大限制,避免 VPA 提升過頭
cpu: '1' # 最高 CPU 限制為 1 核心(1000m)
memory: '500Mi' # 最高記憶體限制為 500Mi(500MB)
controlledResources: ['cpu', 'memory'] # VPA 只調整 CPU 和記憶體
  1. 通過指令來運行。
kubectl.exe apply -f deployment.yaml,vpa.yaml
---

deployment.apps/hamster created
verticalpodautoscaler.autoscaling.k8s.io/hamster-vpa created
  1. 查看 VPA 給出的建議。
kubectl.exe get vpa
---

NAME MODE CPU MEM PROVIDED AGE
hamster-vpa Off 323m 262144k True 44s
# 262144k 約等於 255Mi
kubectl.exe describe vpa hamster-vpa
---

Name: hamster-vpa
Namespace: default
...中間省略...
Status:
Conditions:
Last Transition Time: 2025-02-04T16:20:30Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: hamster
Lower Bound:
Cpu: 100m
Memory: 262144k
Target:
Cpu: 350m
Memory: 262144k
Uncapped Target:
Cpu: 350m
Memory: 262144k
Upper Bound:
Cpu: 1
Memory: 500Mi
Events: <none>

VPA Recommendation 參數詳解

  1. Lower Bound(最低建議值)
    • 這是 VPA 建議的最小 requests,代表 容器至少應該配置這麼多資源,否則可能會有資源不足的風險
    • 如果你的 requests 設定 低於 這個數值,容器可能會遇到資源不足的問題。
  2. Target(目標建議值)
    • 這是 VPA 建議的最佳 requests,代表容器在當前負載下應該設定的資源大小,以確保穩定運行。
    • 如果你設定 requests 接近這個值,資源利用率將是最優的,不會浪費太多資源,但也不會發生短缺。
  3. Uncapped Target(未受限的目標值)
    • 這是 VPA 計算出的目標值,但不考慮 maxAllowed 限制
    • 如果 Uncapped Target 大於 maxAllowed,那麼 Target 會被 VPA 限制在 maxAllowed
  4. Upper Bound(最高建議值)
    • 這是 VPA 建議的最大 requests,代表容器 最多需要多少資源 才能應對高負載情況。
    • 如果 requests 設定超過這個值,可能會造成資源浪費,除非你的應用真的需要這麼多資源
參數作用
Lower Bound最小建議 requests,低於這個值可能會有資源不足風險
Target最佳建議 requests,設定為這個值可最佳化效能與資源利用率
Uncapped Target沒有 maxAllowed 限制的理想 requests
Upper Bound最大建議 requests,超過這個值可能是資源浪費

移除 VPA 模組

  1. 同上面安裝的方法,只是在最後面執行./hack/vpa-down.sh,就可以完全將資源移除。
./hack/vpa-down.sh

總結

  • VPA 透過調整 Pod 的 CPU 和記憶體分配,確保應用獲得適當的資源。
  • 它適合用於資源需求穩定或需要最佳化資源分配的應用。
  • 與 HPA 不同,VPA 不會改變 Pod 數量,而是調整單個 Pod 的 requestslimits
  • 使用 VPA 可能會導致 Pod 重啟,因此需要考慮影響。
  • VPA 和 HPA 可以搭配使用,但需要小心避免衝突。
提示

需要注意的是,若 HPA(Horizontal Pod Autoscaler)使用的指標不是外部資源指標(如 CPU 或 Memory),則與 VPA 的 Auto 模式 可能會產生衝突,導致不可預測的行為。 因此,我更傾向於採用 HPA 搭配 VPA 的 Off 模式,並透過 VPA 提供的建議值來輔助資源分配,確保效能與穩定性。