HorizontalPodAutoscaler 逐步解說
HorizontalPodAutoscaler (簡稱 HPA) 會自動更新工作負載資源(例如 Deployment 或 StatefulSet),目標是自動擴展工作負載以符合需求。
水平擴展 (Horizontal scaling) 意指透過部署更多 Pod,來回應負載增加的情況。這與垂直擴展 (vertical scaling) 不同,以 Kubernetes 而言,垂直擴展指的是為已在執行的工作負載 Pod 分配更多資源 (例如:記憶體或 CPU)。
如果負載降低,且 Pod 數量高於設定的最小值,HorizontalPodAutoscaler 會指示工作負載資源 (Deployment、StatefulSet 或其他類似資源) 縮減規模。
本文將逐步引導您完成啟用 HorizontalPodAutoscaler 的範例,以自動管理範例網頁應用程式的規模。此範例工作負載是執行一些 PHP 程式碼的 Apache httpd。
準備開始前
您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且這些節點未充當控制平面主機的叢集上執行本教學。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用以下 Kubernetes playground 之一
您的 Kubernetes 伺服器版本必須至少為 1.23 或更高版本。若要檢查版本,請輸入kubectl version
。如果您執行的是較舊版本的 Kubernetes,請參閱該版本的說明文件 (請參閱可用的說明文件版本)。若要遵循本逐步解說,您還需要使用已部署並設定 Metrics Server 的叢集。Kubernetes Metrics Server 從叢集中的 kubelet 收集資源指標,並透過 Kubernetes API 公開這些指標,使用 APIService 來新增代表指標讀數的新資源種類。
若要了解如何部署 Metrics Server,請參閱 metrics-server 說明文件。
如果您正在執行 Minikube,請執行以下命令以啟用 metrics-server
minikube addons enable metrics-server
執行並公開 php-apache 伺服器
為了示範 HorizontalPodAutoscaler,您將首先啟動一個 Deployment,該 Deployment 執行使用 hpa-example
映像檔的容器,並使用以下 manifest 將其公開為 Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
若要執行此操作,請執行以下命令
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created
建立 HorizontalPodAutoscaler
現在伺服器正在執行中,使用 kubectl
建立 autoscaler。kubectl autoscale
子命令 (kubectl
的一部分) 可協助您完成此操作。
您很快將執行一個命令,該命令會建立一個 HorizontalPodAutoscaler,以維護 1 到 10 個由 php-apache Deployment 控制的 Pod 副本,而該 Deployment 是您在這些指示的第一步中建立的。
粗略來說,HPA 控制器 將增加和減少副本數 (透過更新 Deployment) 以維持所有 Pod 平均 CPU 使用率為 50%。然後 Deployment 更新 ReplicaSet - 這是 Kubernetes 中所有 Deployment 工作方式的一部分 - 然後 ReplicaSet 會根據其 .spec
的變更新增或移除 Pod。
由於每個 pod 透過 kubectl run
要求 200 毫核心,這表示平均 CPU 使用率為 100 毫核心。有關演算法的更多詳細資訊,請參閱演算法詳細資訊。
建立 HorizontalPodAutoscaler
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
您可以透過執行以下命令來檢查新建立的 HorizontalPodAutoscaler 的目前狀態
# You can use "hpa" or "horizontalpodautoscaler"; either name works OK.
kubectl get hpa
輸出結果類似於
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 18s
(如果您看到其他名稱不同的 HorizontalPodAutoscaler,則表示它們已存在,通常不會有問題)。
請注意,目前的 CPU 消耗量為 0%,因為沒有用戶端向伺服器發送請求 (TARGET
欄位顯示對應 Deployment 控制的所有 Pod 的平均值)。
增加負載
接下來,看看 autoscaler 如何對負載增加做出反應。為此,您將啟動另一個 Pod 作為用戶端。用戶端 Pod 內的容器在無限迴圈中執行,向 php-apache 服務發送查詢。
# Run this in a separate terminal
# so that the load generation continues and you can carry on with the rest of the steps
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
現在執行
# type Ctrl+C to end the watch when you're ready
kubectl get hpa php-apache --watch
大約在一分鐘內,您應該會看到更高的 CPU 負載;例如
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 1 3m
然後,更多副本。例如
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 7 3m
在這裡,CPU 消耗量已增加到請求的 305%。因此,Deployment 已調整大小為 7 個副本
kubectl get deployment php-apache
您應該會看到副本計數與 HorizontalPodAutoscaler 中的數字相符
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 7/7 7 7 19m
注意
副本數量可能需要幾分鐘才能穩定下來。由於負載量未以任何方式控制,因此最終副本數量可能與此範例不同。停止產生負載
若要完成範例,請停止發送負載。
在您建立執行 busybox
映像檔的 Pod 的終端機中,輸入 <Ctrl> + C
以終止負載產生。
然後驗證結果狀態 (大約一分鐘後)
# type Ctrl+C to end the watch when you're ready
kubectl get hpa php-apache --watch
輸出結果類似於
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 11m
Deployment 也顯示已縮減規模
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 27m
一旦 CPU 使用率降至 0%,HPA 會自動將副本數量縮減回 1。
自動調整副本規模可能需要幾分鐘時間。
針對多個指標和自訂指標進行自動擴展
您可以透過使用 autoscaling/v2
API 版本,為自動擴展 php-apache
Deployment 引入其他指標。
首先,以 autoscaling/v2
格式取得 HorizontalPodAutoscaler 的 YAML
kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml
在編輯器中開啟 /tmp/hpa-v2.yaml
檔案,您應該會看到類似以下的 YAML
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
請注意,targetCPUUtilizationPercentage
欄位已替換為名為 metrics
的陣列。CPU 使用率指標是資源指標,因為它表示為 pod 容器上指定的資源百分比。請注意,除了 CPU 之外,您還可以指定其他資源指標。預設情況下,唯一其他支援的資源指標是 memory
(記憶體)。這些資源的名稱在叢集之間不會變更,並且只要 metrics.k8s.io
API 可用,就應該始終可用。
您也可以使用 AverageValue
的 target.type
而非 Utilization
,並設定對應的 target.averageValue
欄位而非 target.averageUtilization
,以直接值而非請求值的百分比來指定資源指標。
metrics:
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 500Mi
還有其他兩種指標類型,這兩種都被視為自訂指標:pod 指標和物件指標。這些指標可能具有叢集特定的名稱,並且需要更進階的叢集監控設定。
這些替代指標類型中的第一種是pod 指標。這些指標描述 Pod,並且在 Pod 之間平均計算,並與目標值進行比較以確定副本計數。它們的工作方式與資源指標非常相似,但它們僅支援 AverageValue
的 target
類型。
Pod 指標使用如下的指標區塊指定
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
第二種替代指標類型是物件指標。這些指標描述相同命名空間中的不同物件,而不是描述 Pod。指標不一定從物件中提取;它們僅描述物件。物件指標支援 Value
和 AverageValue
的 target
類型。使用 Value
時,目標會直接與從 API 傳回的指標進行比較。使用 AverageValue
時,從自訂指標 API 傳回的值會除以 Pod 數量,然後再與目標進行比較。以下範例是 requests-per-second
指標的 YAML 表示法。
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
如果您提供多個此類指標區塊,HorizontalPodAutoscaler 將依序考慮每個指標。HorizontalPodAutoscaler 將計算每個指標的建議副本計數,然後選擇具有最高副本計數的指標。
例如,如果您的監控系統收集有關網路流量的指標,您可以更新上面的定義,使用 kubectl edit
使其看起來像這樣
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
current:
value: 10k
然後,您的 HorizontalPodAutoscaler 將嘗試確保每個 pod 大約消耗其請求 CPU 的 50%,每秒處理 1000 個封包,並且主要路由 Ingress 後面的所有 pod 總共每秒處理 10000 個請求。
針對更特定的指標進行自動擴展
許多指標管線允許您透過名稱或一組稱為標籤的其他描述符來描述指標。對於所有非資源指標類型 (pod、物件和外部,如下所述),您可以指定一個額外的標籤選擇器,該選擇器會傳遞到您的指標管線。例如,如果您收集具有 verb
標籤的指標 http_requests
,您可以指定以下指標區塊僅針對 GET 請求進行擴展
type: Object
object:
metric:
name: http_requests
selector: {matchLabels: {verb: GET}}
此選擇器使用與完整 Kubernetes 標籤選擇器相同的語法。如果名稱和選擇器與多個序列相符,則監控管線會決定如何將多個序列摺疊為單一值。選擇器是附加的,並且無法選擇描述不是目標物件的物件的指標 (在 Pods
類型的情況下為目標 pod,在 Object
類型的情況下為描述的物件)。
針對與 Kubernetes 物件無關的指標進行自動擴展
在 Kubernetes 上運行的應用程式可能需要根據與 Kubernetes 叢集中任何物件沒有明顯關係的指標進行自動擴展,例如描述沒有與 Kubernetes 命名空間直接關聯的託管服務的指標。在 Kubernetes 1.10 及更高版本中,您可以使用外部指標來解決此用例。
使用外部指標需要了解您的監控系統;設定類似於使用自訂指標時所需的設定。外部指標允許您根據監控系統中可用的任何指標自動擴展您的叢集。提供具有 name
和 selector
的 metric
區塊,如上所述,並使用 External
指標類型而不是 Object
。如果 metricSelector
比對多個時間序列,則 HorizontalPodAutoscaler 會使用其值的總和。外部指標同時支援 Value
和 AverageValue
目標類型,其功能與您使用 Object
類型時完全相同。
例如,如果您的應用程式處理來自託管佇列服務的工作,您可以將以下區段新增至您的 HorizontalPodAutoscaler manifest,以指定您每 30 個未完成的工作需要一個工作者。
- type: External
external:
metric:
name: queue_messages_ready
selector:
matchLabels:
queue: "worker_tasks"
target:
type: AverageValue
averageValue: 30
在可能的情況下,最好使用自訂指標目標類型而不是外部指標,因為叢集管理員更容易保護自訂指標 API。外部指標 API 可能允許存取任何指標,因此叢集管理員在公開它時應謹慎。
附錄:Horizontal Pod Autoscaler 狀態條件
當使用 HorizontalPodAutoscaler 的 autoscaling/v2
形式時,您將能夠看到 Kubernetes 在 HorizontalPodAutoscaler 上設定的狀態條件。這些狀態條件指示 HorizontalPodAutoscaler 是否能夠擴展,以及目前是否以任何方式受到限制。
條件會出現在 status.conditions
欄位中。若要查看影響 HorizontalPodAutoscaler 的條件,我們可以使用 kubectl describe hpa
kubectl describe hpa cm-test
Name: cm-test
Namespace: prom
Labels: <none>
Annotations: <none>
CreationTimestamp: Fri, 16 Jun 2017 18:09:22 +0000
Reference: ReplicationController/cm-test
Metrics: ( current / target )
"http_requests" on pods: 66m / 500m
Min replicas: 1
Max replicas: 4
ReplicationController pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale the last scale time was sufficiently old as to warrant a new scale
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests
ScalingLimited False DesiredWithinRange the desired replica count is within the acceptable range
Events:
對於此 HorizontalPodAutoscaler,您可以看到多個處於健康狀態的條件。第一個 AbleToScale
指示 HPA 是否能夠提取和更新規模,以及任何與退避相關的條件是否會阻止擴展。第二個 ScalingActive
指示 HPA 是否已啟用 (即,目標的副本計數不為零) 並且能夠計算所需的規模。當它為 False
時,通常表示提取指標時出現問題。最後,最後一個條件 ScalingLimited
指示所需的規模受到 HorizontalPodAutoscaler 的最大值或最小值的限制。這表示您可能希望提高或降低 HorizontalPodAutoscaler 上的最小或最大副本計數約束。
數量 (Quantities)
HorizontalPodAutoscaler 和指標 API 中的所有指標都使用一種特殊的整數表示法指定,在 Kubernetes 中稱為數量。例如,數量 10500m
在十進制表示法中會寫為 10.5
。指標 API 會在可能的情況下傳回不帶字尾的整數,通常會在其他情況下傳回毫單位的數量。這表示您可能會看到您的指標值在 1
和 1500m
之間波動,或在十進制表示法中寫為 1
和 1.5
之間波動。
其他可能的場景
宣告式地建立 autoscaler
除了使用 kubectl autoscale
命令以命令式方式建立 HorizontalPodAutoscaler 之外,我們可以使用以下 manifest 以宣告式方式建立它
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
然後,透過執行以下命令來建立 autoscaler
kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created