AutoScaling - Vertical Pod AutoScaler
什麼是 Vertical Pod Autoscaler?
Vertical Pod Autoscaler(VPA) 是 Kubernetes 提供的一種資源自動調整機制,主要用於 動態調整 Pod 的 CPU 和記憶體資源,以確保應用程式能夠獲得適當的資源,提升效能並降低不必要的資源浪費。 與 Horizontal Pod Autoscaler(HPA) 不同,VPA 是透過 調整單個 Pod 的資源限制(CPU / Memory Requests & Limits) 來最佳化資源使用。
VPA 的核心功能
- 自動調整 Pod 資源分配
- 根據實際負載,動態調整 CPU 和記憶體的
requests
和limits
,減少過多配置造成的浪費,或避免資源不足導致的效能問題。
- 根據實際負載,動態調整 CPU 和記憶體的
- 避免 OOM(Out of Memory)問題
- 如果 Pod 需要的記憶體超出當前配置,VPA 會根據需求增加
requests
,防止因為記憶體不足而導致 Pod Crash。
- 如果 Pod 需要的記憶體超出當前配置,VPA 會根據需求增加
- 提供資源建議(Recommendation Mode)
- VPA 可以運行在 推薦模式(Recommend Only),提供合適的資源配置建議,而不會自 動調整 Pod 配置,讓使用者自行決定是否採納建議。
- 與 HPA 搭配使用
- 雖然 VPA 和 HPA 主要解決不同層面的資源管理問題,但它們可以搭配使用,例如:VPA 負責調整個別 Pod 的資源請求,而 HPA 負責擴展 Pod 的數量,以確保應用的高可用性和擴展性。
VPA 的運作方式
VPA 由三個主要元件組成:
- Recommender(建議器)
- 負責監控 Pod 的資源使用情況,並根據歷史數據計算出最佳的 CPU/記憶體需求,提供建議值。
- Updater(更新器)
- 負責檢查現有的 Pod 是否需要調整資源分配。若需要,會重新建立新的 Pod(因為 Kubernetes 不允許直接修改 Pod 的
requests
和limits
)。
- 負責檢查現有的 Pod 是否需要調整資源分配。若需要,會重新建立新的 Pod(因為 Kubernetes 不允許直接修改 Pod 的
- 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 | 指定要調整的容器名稱。可以是特定名稱或 "*" (代表所有容器)。 |
minAllowed | VPA 允許的最小 requests 限制,低於此值不會調整。 |
maxAllowed | VPA 允許的最大 requests 限制,超過此值不會調整。 |
controlledResources | 指定要調整的資源類型,可以是 "cpu" 、"memory" ,或 ["cpu", "memory"] 。 |
controlledValues | (選填)可選 "RequestsAndLimits" 或 "RequestsOnly" ,預設為 "RequestsOnly" 。 |
VPA 適用場景
- 機器學習 / 批次處理應用:這些應用對 CPU 和記憶體有較高需求,VPA 能夠確保它們獲得足夠的資源。
- 長時間運行的應用:對於一些長時間運行的應用(如資料庫、後台服務),VPA 能夠根據歷史負載逐步調整資源配置,提升效能。
- 預算受限的應用:當需要節省資源成本時,VPA 可以幫助減少不必要的 CPU/記憶體配置,避免浪費。
VPA 使用限制
- VPA 需要重啟 Pod
- 由於 Kubernetes 不允許動態修改 Pod 的
requests
和limits
,所以 VPA 在調整資源時會刪除舊 Pod 並重新創建新 Pod,可能會導致短暫的停機時間。
- 由於 Kubernetes 不允許動態修改 Pod 的
- 與 HPA 可能衝突
- 如果 HPA 依據 CPU/記憶體來擴展 Pod 數量,而 VPA 同時調整 CPU/記憶體的請求值,可能會產生資源配置衝突,因此通常 HPA 會基於自定義指標(如請求數量)運行,而 VPA 負責 CPU/Memory 的最佳化。
- 無法適用於 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 是否有成功執行
- 首先我們可以觀察 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 autoscaler 或 vertical autoscaler 等 CRD 時,則需要以模組的方式載入。
- 因為安裝需要/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
操作順利完成。
- 登入 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$
- 因為是全新的環境,需要重新安裝 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
- 接著我們載入原本 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
- 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.
- 接著進到這個專案的資料夾之中,要進行安裝。
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$
- 執行./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
- 退出 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
- 首先我們先製作一個 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'
- 接著設定 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 和記憶體
- 通過指令來運行。
kubectl.exe apply -f deployment.yaml,vpa.yaml
---
deployment.apps/hamster created
verticalpodautoscaler.autoscaling.k8s.io/hamster-vpa created
- 查看 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 參數詳解
- Lower Bound(最低建議值)
- 這是 VPA 建議的最小
requests
值,代表 容器至少應該配置這麼多資源,否則可能會有資源不足的風險。 - 如果你的
requests
設定 低於 這個數值,容器可能會遇到資源不足的問題。
- 這是 VPA 建議的最小
- Target(目標建議值)
- 這是 VPA 建議的最佳
requests
值,代表容器在當前負載下應該設定的資源大小,以確保穩定運行。 - 如果你設定
requests
接近這個值,資源利用率將是最優的,不會浪費太多資源,但也不會發生短缺。
- 這是 VPA 建議的最佳
- Uncapped Target(未受限的目標值)
- 這是 VPA 計算出的目標值,但不考慮
maxAllowed
限制。 - 如果
Uncapped Target
大於maxAllowed
,那麼Target
會被 VPA 限制在maxAllowed
內。
- 這是 VPA 計算出的目標值,但不考慮
- Upper Bound(最高建議值)
- 這是 VPA 建議的最大
requests
值,代表容器 最多需要多少資源 才能應對高負載情況。 - 如果
requests
設定超過這個值,可能會造成資源浪費,除非你的應用真的需要這麼多資源。
- 這是 VPA 建議的最大
參數 | 作用 |
---|---|
Lower Bound | 最小建議 requests ,低於這個值可能會有資源不足風險 |
Target | 最佳建議 requests ,設定為這個值可最佳化效能與資源利用率 |
Uncapped Target | 沒有 maxAllowed 限制的理想 requests 值 |
Upper Bound | 最大建議 requests ,超過這個值可能是資源浪費 |
移除 VPA 模組
- 同上面安裝的方法,只是在最後面執行./hack/vpa-down.sh,就可以完全將資源移除。
./hack/vpa-down.sh