本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
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 的那些節點付費。它還確保您始終擁有足夠的計算能力來執行您的任務。