雲計算

K8S從懵圈到熟練 – 集群伸縮原理

作者:shengdong

阿里雲K8S集群的一個重要特性,是集群的節點可以動態的增加或減少。有了這個特性,集群才能在計算資源不足的情況下擴容新的節點,同時也可以在資源利用率降低的時候,釋放節點以節省費用。

這篇文章,我們討論阿里雲K8S集群擴容與縮容的實現原理。理解實現原理,在遇到問題的時候,我們就可以高效地排查並定位原因。我們的討論基於當前的1.12.6版本。

節點增加原理

阿里雲K8S集群可以給集群增加節點的方式有,添加已有節點,集群擴容,和自動伸縮。其中,添加已有節點又可分為手動添加已有節點和自動添加已有節點。節點的增加涉及到的組件有,節點準備,彈性伸縮(ESS),管控,Cluster Autoscaler以及調度器。

2.1.png

手動添加已有節點

節點準備,其實就是把一個普通的ECS實例,安裝配置成為一個K8S集群節點的過程。這個過程僅靠一條命令就可以完成。這條命令使用curl下載attach_node.sh腳本,然後以openapi token為參數,在ECS上運行。

curl http:///public/pkg/run/attach//attach_node.sh | bash -s -- --openapi-token

這裡token是一個對的key,而value是當前集群的基本信息。阿里雲K8S集群的管控,在接到手動添加已有節點請求的時候,會生成這個對,並把key作為token返回給用戶。

這個token(key)存在的價值,是其可以讓attach_node.sh腳本,以匿名身份在ECS上索引到集群的基本信息(value),而這些基本信息,對節點準備至關重要。

總體上來說,節點準備就做兩件事情,讀和寫。讀即數據收集,寫即節點配置。

2.2.png

這裡的讀寫過程,絕大部分都很基礎,大家可以通過閱讀腳本來了解細節。唯一需要特別說明的是,kubeadm join把節點註冊到Master的過程。此過程需要新加節點和集群Master之間建立互信。

一邊,新加節點從管控處獲取的bootstrap token(與openapi token不同,此token是value的一部分內容),實際上是管控通過可信的途徑從集群Master上獲取的。新加節點使用這個bootstrap token連接Master,Master則可通過驗證這個bootstrap token來建立對新加節點的信任。

另一邊,新加節點以匿名身份從Master kube-public命名空間中獲取集群cluster-info,cluster-info包括集群CA證書,和使用集群bootstrap token對這個CA做的簽名。新加節點使用從管控處獲取的bootstrap token,對CA生成b新的簽名,然後將此簽名與cluster-info內簽名做對比,如果兩個簽名一致,則說明cluster-info和bootstrap token來自同一集群。新加節點因為信任管控,所以建立對Master的信任。

2.3.png

自動添加已有節點

自動添加已有節點,不需要人為拷貝黏貼腳本到ECS命令行來完成節點準備的過程。管控使用了ECS userdata的特性,把類似以上節點準備的腳本,寫入ECS userdata,然後重啟ECS並更換系統盤。當ECS重啟之後,會自動執行Userdata裡邊的腳本,來完成節點添加的過程。這部分內容,大家其實可以通過查看節點userdata來確認。

!/bin/bash

mkdir -p /var/log/acs

curl http:///public/pkg/run/attach/1.12.6-aliyun.1/attach_node.sh | bash -s -- --docker-version --token --endpoint --cluster-dns > /var/log/acs/init.log

這裡我們看到,attach_node.sh的參數,與前一節的參數有很大的不同。其實這裡的參數,都是前一節value的內容,即管控創建並維護的集群基本信息。自動添加已有節點省略了通過key獲取value的過程。

集群擴容

集群擴容與以上添加已有節點不同,此功能針對需要新購節點的情形。集群擴容的實現,在添加已有節點的基礎上,引入了彈性伸縮ESS組件。ESS組件負責從無到有的過程,而剩下的過程與添加已有節點類似,即依靠ECS userdata腳本來完成節點準備。下圖是管控通過ESS從無到有創建ECS的過程。

2.4.png

自動伸縮

前邊三種方式是需要人為干預的伸縮方式,而自動伸縮的本質不同,是它可以在業務需求量增加的時候,自動創建ECS實例並加入集群。為了實現自動化,這裡引入了另外一個組件Cluster Autoscaler。集群自動伸縮包括兩個獨立的過程。

2.5.png

其中第一個過程,主要用來配置節點的規格屬性,包括設置節點的用戶數據。這個用戶數據和手動添加已有節點的腳本類似,不同的地方在於,其針對自動伸縮這種場景,增加了一些專門的標記。attach_node.sh腳本會根據這些標記,來設置節點的屬性。

!/bin/sh

curl http:///public/pkg/run/attach/1.12.6-aliyun.1/attach_node.sh | bash -s -- --openapi-token --ess true --labels k8s.io/cluster-autoscaler=true,workload_type=cpu,k8s.aliyun.com=true

而第二個過程,是實現自動增加節點的關鍵。這裡引入了一個新的組件Autoscaler,它以Pod的形式運行在K8S集群中。理論上來說,我們可以把這個組件當做一個控制器。因為它的作用與控制器類似,基本上還是監聽Pod狀態,以便在Pod因為節點資源不足而不能被調度的時,去修改ESS的伸縮規則來增加新的節點。

這裡有一個知識點,集群調度器衡量資源是否充足的標準,是“預訂率”,而不是“使用率”。這兩者的差別,類似酒店房價預訂率和實際入住率:完全有可能有人預訂了酒店,但是並沒有實際入住。在開啟自動伸縮功能的時候,我們需要設置縮容閾值,就是“預訂率”的下線。之所以不需要設置擴容閾值。是因為Autoscaler擴容集群,依靠的是Pod的調度狀態:當Pod因為節點資源“預訂率”太高無法被調度的時候,Autoscaler就會擴容集群。

節點減少原理

與增加節點不同,集群減少節點的操作只有一個移除節點的入口。但對於用不同方法加入的節點,其各自移除方式略有不同。

首先,通過添加已有節點加入的節點,需要三步去移除:管控通過ECS API清楚ECS userdata;管控通過K8S API從集群中刪除節點;管控通過ECS InvokeCommand在ECS上執行kubeadm reset命令清理節點。

其次,通過集群擴容加入的節點,則在上邊的基礎上,增加了斷開ESS和ECS關係的操作。此操作由管控調用ESS API完成。

2.6.png

最後,經過Cluster Autoscaler動態增加的節點,則在集群CPU資源“預訂率”降低的時候,由Cluster Autoscaler自動移除釋放。其觸發點是CPU“預訂率”,即上圖寫Metrics的原因。

總結

總體上來說,K8S集群節點的增加與減少,主要涉及四個組件,分別是Cluster Autoscaler,ESS,管控以及節點本身(準備或清理)。根據場景不同,我們需要排查不同的組件。其中Cluster Autoscaler是一個普通的Pod,其日誌的獲取和其他Pod無異;ESS彈性伸縮有其專門的控制檯,我們可以在控制檯排查其伸縮配置、伸縮規則等相關子實例日誌和狀態;而管控的日誌,可以通過查看日誌功能來查看;最後,對於節點的準備與清理,其實就是排查對應的腳本的執行過程。

以上講道理居多,希望對大家排查問題有所幫助。

Leave a Reply

Your email address will not be published. Required fields are marked *