本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 中的自動擴縮

編者按:這篇博文是關於 Kubernetes 1.3 新特性的系列深度文章之一

使用 Kubernetes 的客戶能夠快速響應終端使用者請求,並以比以往更快的速度交付軟體。但是,當您構建的服務比預期更受歡迎,並且計算資源不足時會發生什麼?在 Kubernetes 1.3 中,我們很自豪地宣佈我們有了一個解決方案:自動擴縮。在 Google Compute Engine (GCE) 和 Google Container Engine (GKE)(以及即將推出的 AWS),Kubernetes 將在您需要時立即自動擴縮您的叢集,並在您不需要時將其縮減以節省您的資金。

自動擴縮的優勢

為了更好地理解自動擴縮將提供最大價值的場景,讓我們從一個例子開始。想象一下,您有一個 24/7 的生產服務,其負載隨時間變化,在美國白天非常繁忙,而在夜間相對較低。理想情況下,我們希望叢集中的節點數量和部署中的 Pod 數量能夠動態調整以適應負載,從而滿足終端使用者需求。新的叢集自動擴縮功能與水平 Pod 自動擴縮器可以為您自動處理此問題。

在 GCE 上設定自動擴縮

以下說明適用於 GCE。對於 GKE,請檢視 此處 提供的叢集操作手冊中的自動擴縮部分。

在開始之前,我們需要一個已啟用 Google Cloud Monitoring、Google Cloud Logging 和 Stackdriver 的活躍 GCE 專案。有關專案建立的更多資訊,請閱讀我們的 入門指南。我們還需要下載一個最新版本的 Kubernetes 專案(v1.3.0 或更高版本)。

首先,我們設定一個啟用叢集自動擴縮器的叢集。叢集中的節點數量將從 2 個開始,並自動擴縮到最多 5 個。為此,我們將匯出以下環境變數

export NUM\_NODES=2

export KUBE\_AUTOSCALER\_MIN\_NODES=2

export KUBE\_AUTOSCALER\_MAX\_NODES=5

export KUBE\_ENABLE\_CLUSTER\_AUTOSCALER=true

並透過執行以下命令啟動叢集

./cluster/kube-up.sh

kube-up.sh 指令碼會建立一個叢集以及叢集自動擴縮器外掛。如果存在可以在新節點上排程的待處理 Pod,自動擴縮器將嘗試向叢集新增新節點。

讓我們看看我們的叢集,它應該有兩個節點

$ kubectl get nodes

NAME                           STATUS                     AGE

kubernetes-master              Ready,SchedulingDisabled   2m

kubernetes-minion-group-de5q   Ready                      2m

kubernetes-minion-group-yhdx   Ready                      1m

執行並公開 PHP-Apache 伺服器

為了演示自動擴縮,我們將使用基於 php-apache 伺服器的自定義 Docker 映象。該映象可以在 此處 找到。它定義了執行一些 CPU 密集型計算的 index.php 頁面。

首先,我們將啟動一個執行該映象的部署,並將其公開為服務

$ kubectl run php-apache \   

  --image=gcr.io/google\_containers/hpa-example \

  --requests=cpu=500m,memory=500M --expose --port=80  

service "php-apache" createddeployment "php-apache" created

現在,我們將等待一段時間並驗證部署和服務是否已正確建立並正在執行

$ kubectl get deployment

NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

php-apache   1         1         1            1           49s



$ kubectl get pods  
NAME                          READY     STATUS    RESTARTS   AGE

php-apache-2046965998-z65jn   1/1       Running   0          30s

現在我們可以透過使用服務地址呼叫 wget 來檢查 php-apache 伺服器是否正常工作

$ kubectl run -i --tty service-test --image=busybox /bin/sh  
Hit enter for command prompt  
$ wget -q -O- http://php-apache.default.svc.cluster.local

OK!

啟動水平 Pod 自動擴縮器

部署執行後,我們將為其建立一個水平 Pod 自動擴縮器。要建立它,我們將使用 kubectl autoscale 命令,如下所示

$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

這定義了一個水平 Pod 自動擴縮器,它維護我們在這些說明的第一步中建立的 php-apache 部署所控制的 Pod 的 1 到 10 個副本。粗略地說,水平自動擴縮器將增加和減少副本數量(透過部署),以使所有 Pod 的平均 CPU 利用率保持在 50%(因為每個 Pod 透過 kubectl run 請求 500 毫核,這意味著平均 CPU 使用率為 250 毫核)。有關該演算法的更多詳細資訊,請參見 此處

我們可以透過執行以下命令檢查自動擴縮器的當前狀態

$ kubectl get hpa

NAME         REFERENCE                     TARGET    CURRENT   MINPODS   MAXPODS   AGE

php-apache   Deployment/php-apache/scale   50%       0%        1         20        14s

請注意,由於我們沒有向伺服器傳送任何請求,因此當前 CPU 消耗為 0%(CURRENT 列顯示相應副本控制器控制的所有 Pod 的平均值)。

提高負載

現在,我們將看到我們的自動擴縮器(叢集自動擴縮器和水平 Pod 自動擴縮器)如何響應伺服器增加的負載。我們將啟動兩個對伺服器的無限迴圈查詢(請在不同的終端中執行它們)

$ kubectl run -i --tty load-generator --image=busybox /bin/sh  
Hit enter for command prompt  
$ while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done

我們需要等待片刻(大約一分鐘)以傳播統計資訊。之後,我們將檢查水平 Pod 自動擴縮器的狀態

$ kubectl get hpa

NAME         REFERENCE                     TARGET    CURRENT   MINPODS   MAXPODS   AGE

php-apache   Deployment/php-apache/scale   50%       310%      1         20        2m



$ kubectl get deployment php-apache

NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

php-apache        7         7         7            3           4m

水平 Pod 自動擴縮器已將我們部署中的 Pod 數量增加到 7 個。現在,讓我們檢查一下所有 Pod 是否都在執行

jsz@jsz-desk2:~/k8s-src$ kubectl get pods

php-apache-2046965998-3ewo6        0/1       Pending   0          1m

php-apache-2046965998-8m03k        1/1       Running   0          1m

php-apache-2046965998-ddpgp        1/1       Running   0          5m

php-apache-2046965998-lrik6        1/1       Running   0          1m

php-apache-2046965998-nj465        0/1       Pending   0          1m

php-apache-2046965998-tmwg1        1/1       Running   0          1m

php-apache-2046965998-xkbw1        0/1       Pending   0          1m

如我們所見,一些 Pod 處於待處理狀態。讓我們描述一個待處理的 Pod 以獲取待處理狀態的原因

$ kubectl describe pod php-apache-2046965998-3ewo6

Name: php-apache-2046965998-3ewo6

Namespace: default

...

Events:

  FirstSeen From SubobjectPath Type Reason Message



  1m {default-scheduler } Warning FailedScheduling pod (php-apache-2046965998-3ewo6) failed to fit in any node

fit failure on node (kubernetes-minion-group-yhdx): Insufficient CPU

fit failure on node (kubernetes-minion-group-de5q): Insufficient CPU



  1m {cluster-autoscaler } Normal TriggeredScaleUp pod triggered scale-up, mig: kubernetes-minion-group, sizes (current/new): 2/3

Pod 待處理是因為系統中沒有足夠的 CPU。我們看到有一個與 Pod 相關的 TriggeredScaleUp 事件。這意味著該 Pod 觸發了叢集自動擴縮器的反應,一個新的節點將被新增到叢集中。現在我們將等待反應(大約 3 分鐘)並列出所有節點

$ kubectl get nodes

NAME                           STATUS                     AGE

kubernetes-master              Ready,SchedulingDisabled   9m

kubernetes-minion-group-6z5i   Ready                      43s

kubernetes-minion-group-de5q   Ready                      9m

kubernetes-minion-group-yhdx   Ready                      9m

正如我們所見,叢集自動擴縮器添加了一個新節點 kubernetes-minion-group-6z5i。讓我們驗證所有 Pod 是否都在執行

$ kubectl get pods

NAME                               READY     STATUS    RESTARTS   AGE

php-apache-2046965998-3ewo6        1/1       Running   0          3m

php-apache-2046965998-8m03k        1/1       Running   0          3m

php-apache-2046965998-ddpgp        1/1       Running   0          7m

php-apache-2046965998-lrik6        1/1       Running   0          3m

php-apache-2046965998-nj465        1/1       Running   0          3m

php-apache-2046965998-tmwg1        1/1       Running   0          3m

php-apache-2046965998-xkbw1        1/1       Running   0          3m

節點新增後,所有 php-apache Pod 都在執行!

停止負載

我們將透過停止使用者負載來結束我們的示例。我們將終止傳送請求到伺服器的兩個無限 while 迴圈,並驗證結果狀態

$ kubectl get hpa

NAME         REFERENCE                     TARGET    CURRENT   MINPODS   MAXPODS   AGE

php-apache   Deployment/php-apache/scale   50%       0%        1         10        16m



$ kubectl get deployment php-apache

NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

php-apache        1         1         1            1           14m

如我們所見,在此情況下,CPU 利用率降至 0,副本數量降至 1。

刪除 Pod 後,大多數叢集資源處於未使用狀態。縮減叢集可能比擴容花費更長時間,因為叢集自動擴縮器會確保節點確實不需要,這樣短時間的非活動狀態(由於 Pod 升級等)不會觸發節點刪除(請參閱 叢集自動擴縮器文件)。大約 10-12 分鐘後,您可以驗證叢集中的節點數量是否減少

$ kubectl get nodes

NAME                           STATUS                     AGE

kubernetes-master              Ready,SchedulingDisabled   37m

kubernetes-minion-group-de5q   Ready                      36m

kubernetes-minion-group-yhdx   Ready                      36m

叢集中的節點數量現在又回到了兩個,因為節點 kubernetes-minion-group-6z5i 已被叢集自動擴縮器移除。

其他用例

如我們所示,結合水平 Pod 自動擴縮器和叢集自動擴縮器,可以非常容易地根據負載動態調整 Pod 的數量。

然而,當叢集負載出現不規律時,單獨使用叢集自動擴縮器也可能非常有幫助。例如,與開發或持續整合測試相關的叢集在週末或夜間可能需求較少。批處理叢集可能有一段時間所有作業都已完成,新作業將在幾個小時後才開始。擁有無所事事的機器是一種金錢浪費。

在所有這些情況下,叢集自動擴縮器都可以減少未使用的節點數量,並帶來相當可觀的節省,因為您只需為您實際需要執行 Pod 的那些節點付費。它還確保您始終擁有足夠的計算能力來執行您的任務。