本篇文章發布至今已超過一年。較舊的文章可能包含過時的內容。請確認本頁面中的資訊自發布以來是否已變得不正確。
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,請查看叢集操作手冊中提供的自動擴展章節 此處。
在我們開始之前,我們需要有一個啟用的 GCE 專案,並啟用 Google Cloud Monitoring、Google Cloud Logging 和 Stackdriver。有關專案建立的更多資訊,請閱讀我們的入門指南。我們還需要下載最新版本的 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 映像檔。該映像檔可以在此處找到。它定義了 index.php 頁面,該頁面執行一些 CPU 密集型計算。
首先,我們將啟動一個執行該映像檔的部署,並將其公開為服務
$ 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 的節點付費。它還可以確保您始終擁有足夠的運算能力來執行您的任務。