0%

Kubernetes (五) - 實現 Pod 的 AutoScaling

Horizontal Pod Autoscaler

在實務應用上,最常碰到的就是資源不足的問題,而這個問題常常歸因於每個應用在每個時間點的流量都不會固定,但是每個應用分配到的資源卻是固定的。既然流量不同,也就代表所需的資源是不固定的,因此 Kubernetes 提供了自動水平擴展的功能來解決這個問題。

Horizontal Pod Autoscaler

Kubernetes 提供的自動水平擴展稱為 Horizontal Pod Autoscaler,自動水平擴展的好處是不需要一次給某個應用很多的資源以增加資源使用的彈性,當應用所擁有的資源被使用到了指定的門檻時就會自動再生成一個相同的應用來幫忙分擔資源使用,在 Kubernetes 就是再生成一個一樣的 Pod。而當應用使用的資源低於指定的門檻時,如果有太多的 Pod 就會將這些 Pod 關閉以減少資源的占用。

運作原理

Horizontal Pod Autoscaler Overall

上面這張圖是 Horizontal Pod Autoscaler 的運作方式,首先看到 Node 裡面的 cAdvisor,cAdvisor 可以對 Node 上的資源及容器進行即時的監控。而 cAdvisor 已經內建在 Kubernetes 裡並且會在 Kubelet 啟動時同步被啟動。

接著再看到 Metrics Server,Metrics Server 負責用來收集 Cluster 內所有資源的使用狀況,所以他會透過每個 Node 的 Kubelet 來向 cAdvisor 取得資源使用的訊息。這裡順帶提一下,舊版使用 heapster 來收集資源使用狀況,但在 Kubernetes 1.11 以後已經廢除而改用 Metrics Server。

最後再看到 Horizontal Pod Autoscaler,Horizontal Pod Autoscaler 預設每 15 秒會向 Metrics Server 要求提供資源使用的 Metric,再與設定的資源使用上限進行比對,如果達到擴展的門檻則進行水平擴展。

建立 HorizontalPodAutoscaler

下面是 HorizontalPodAutoscaler 的基本格式 :

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: <name>
spec:
scaleTargetRef:
apiVersion: apps/v1beta2
kind: Deployment
name: <deployment name>
minReplicas: <min replica number>
maxReplicas: <max replica number>
targetCPUUtilizationPercentage: <utilization percentage>
  • scaleTargetRef
    指定要 Autoscaling 的對象。

  • minReplicas、maxReplicas
    指定最少要有幾個 Pod 和最多可以擴展到多少個 Pod。

  • targetCPUUtilizationPercentage
    指定 CPU 使用率的目標百分比,當超過指定的目標就會開始自動擴展。

另外一種格式如下,可以看到 targetCPUUtilizationPercentage 被取代成了 metrics,因為 CPU 使用率就是一個資源度量指標(resource metric)。除了指定 CPU 使用率外,還可以指定 Memory 的使用量。這裡要特別注意的是 如果指定了多個指標則都必須符合才會觸發自動水平擴展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: autoscaling/v2beta2 
kind: HorizontalPodAutoscaler
metadata:
name: <name>
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: <deployment name>
minReplicas: <min replica number>
maxReplicas: <max replica number>
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageValue: <utilization percentage>
- type: Resource
resource:
name: memory
target:
type: Utilization
averageValue: <utilization value>

另外也可以使用 kubectl autoscale 指令來直接建立,如下 :

1
2
3
4
kubectl autoscale deployment <deployment name> \
--cpu-percent=<percent> \
--min=<value> \
--max=<value>

範例

我們使用 Kubernetes 官網 的 demo 作為範例,這個範例使用的是 Kubernetes 官方自己建立好的 docker image,啟動之後如果收到 Request 就會開始進行大量的運算來增加 CPU 的負載量,如下 :

1
2
3
4
5
6
7
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>

首先要先建立 php-apache.yml,這個 yaml 檔會建立一個 Deployment 和 Service。這裡可以看到 spec.resources.request 代表啟動時這個 Pod 要求要配置 200m 的 CPU 給他,200m 代表 200 milicpu(milicore),也就是要一個 CPU 20% 的資源。而如果 Node 是多核心,則代表這個 Pod 要求每個核心都配 20% 的資源給他。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.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

啟動 Deployment 和 Service。

1
2
3
 kubectl get deploy php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 2m34s

接著建立 php-apache-hpa.yml,這個 yaml 檔會建立一個 HorizontalPodAutoscaler。當 CPU 使用率超過了 50% 就會觸發水平擴展,並且最多會擴展到 10 個 Pod。

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1beta2
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 50

啟動前我們要先啟動 minikube 的 metrics-server。

1
2
$ minikube addons enable metrics-server
🌟 The 'metrics-server' addon is enabled

啟動 HorizontalPodAutoscaler。

1
2
$ kubectl create -f php-apache-hpa.yml
horizontalpodautoscaler.autoscaling/php-apache-hpa created

查看剛剛建立起來的 HorizontalPodAutoscaler。

1
2
3
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache <unknown>/50% 1 10 1 69s

增加 CPU 負載量

建好 HorizontalPodAutoscaler 後,我們就來進行測試。首先先另外啟動一個 Container,並且在 Container 內以無窮迴圈的方式不斷的向 php-apache 發送 Request。

1
2
3
4
5
kubectl run -it --rm load-generator --image=busybox /bin/sh

Hit enter for command prompt

while true; do wget -q -O- http://php-apache; done

接著稍等一下,再次取得 HorizontalPodAutoscaler 就會看到 CPU 使用率已經開始上升,如下這個範例已經飆升到了 252%。

1
2
3
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 252%/50% 1 10 6 4m5s

此時再回來看 Deployment 的運行狀況,可以發現 Pod 數量已經擴展到 6 個了。

1
2
3
$ kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 6/6 6 6 6m30s

降低 CPU 負載量

先使用 Ctrl+C 停止 busybox Container 的無窮迴圈 Request。

過了大約幾分鐘再回來看 HorizontalPodAutoscaler 會發現 CPU 使用率已經降下來了。

1
2
3
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 0%/50% 1 10 7 12m

這時再回來看 Deployment 的運行狀況,可以發現 Pod 數量也已經降回來了。

1
2
3
$ kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 14m

Overview

最後我們用 minikube dashboard 來看一下自動水平擴展的過程。

首先先看到 CPU 的使用率,可以看到在開始向 php-apache 發送 Request 之後,CPU 使用率就開始不斷向上飆升,停止發送 Request 後下降到了 0。

CPU Usage

接著再看到 Deployment 的事件,可以看到詳細的列出了 Pod 從 1 個變成 4 個、6 個、7個,最後降回了 1 個。

Deployment Event

Summary

自動的進行水平擴展也是 Kubernetes 會非常熱門的其中一個原因,可以不再需要手動的增減伺服器部署應用。

此外,現在的系統漸漸都開始朝向雲端來建置,雲端會以伺服器和流量的使用量來進行計費,當用戶流量沒有那麼大時就可以自動的減少應用的部署和伺服器的使用,這樣可以省下非常多的費用。

參考

[1] 實現 Horizontal Pod Autoscaling - HPA
[2] Kubernetes 彈性伸缩全場景解析(三) - HPA 實際手册
[3] Horizontal Pod Autoscaler Walkthrough
[4] Kubernetes監控:Metrics Server部署方法
[5] Grafana 在 Kubernetes 中的使用