本頁說明架構可擴充 GKE 叢集的一般最佳做法。您可以對所有叢集和工作負載套用這些建議,以達到最佳效能。如果您打算大幅擴充叢集,這些建議就特別重要。最佳做法適用於負責佈建基礎架構的管理員,以及準備 Kubernetes 元件和工作負載的開發人員。
什麼是擴充性?
在 Kubernetes 叢集中,擴充性是指叢集保持在其服務等級目標 (SLO) 的前提下繼續成長的能力。Kubernetes 也有自己的一組 SLO
Kubernetes 是一個複雜的系統,其擴充能力取決於多種因素。其中一些因素包括節點集區中的節點類型與數量、節點集區的類型與數量、可用的 Pod 數量、將資源分配給 Pod 的方式,以及 Service 或 Service 後端的數量。
最佳做法:提供空房資訊
選擇地區或區域控制層
由於架構上的差異,地區叢集更適合高可用性。地區叢集在一個區域中的多個運算區域之間有多個控制層,而區域叢集在單一運算區域中有一個控制層。
如果區域叢集升級,控制層 VM 會遭遇停機狀況,在此期間 Kubernetes API 就無法使用,直到升級完成為止。
在區域叢集中,控制層在叢集維護期間仍會保持可用,這些維護工作包括輪替 IP、升級控制層 VM 或調整叢集或節點集區大小等情況。升級區域叢集時,在多個控制層 VM 中,至少有一個一律會在漸進式升級期間執行,因此 Kubernetes API 仍會保持可用。同樣地,單一區域服務中斷並不會導致地區控制層中發生任何停機狀況。
但是,可用性越高的地區叢集越可能需要做出取捨:
對叢集配置進行變更需要更長的時間,因為變更必須在地區叢集中的所有控制層上傳播,而不是在區域叢集中的單一控制層上傳播。
您可能無法像區域叢集那樣頻繁地建立或升級地區叢集。如果無法在其中一個區域建立 VM,無論是遇到容量不足還是其他暫時性的問題,都無法建立或升級叢集。
由於必須做出這些取捨,區域與地區叢集會有不同的用途:
- 如果比較不需要考慮到可用性,請使用區域叢集來快速建立或升級叢集。
- 如果可用性比靈活性更重要,請使用區域叢集。
建立叢集時,請謹慎選取叢集類型,因為建立叢集後即無法變更叢集類型。您必須建立新叢集,然後將流量遷移至該叢集。您可以在叢集之間遷移實際工作環境流量,但要大規模遷移就比較困難。
選擇多區域或單一區域節點集區
為了實現高可用性的目標,Kubernetes 控制層及其節點需要分佈到不同的區域。GKE 提供兩種類型的節點集區:單一可用區和多可用區。
如要部署高可用性應用程式,請在地區中的多個運算區域之間部署工作負載,方法是使用多區域節點集區來跨區域統一分配節點。
如果所有節點都在同一個區域中,且無法連至該區域,您就無法為 Pod 排定時間。使用多區域節點集區時必須做出一定的取捨:
GPU 僅適用於特定區域。可能沒辦法在地區中的所有區域使用。
單一地區內各可用區之間的往返延遲,可能高於單一可用區內資源之間的往返延遲。對大多數工作負載而言,這項差異應該微不足道。
相同地區中的區域間輸出流量價格可在 Compute Engine 定價頁面上找到。
大規模實行最佳做法
基礎架構
Kubernetes 工作負載需要網路、運算和儲存空間。您需要提供足夠的 CPU 與記憶體才能執行 Pod。不過,目前已有越來越多的基礎架構可能會影響 GKE 叢集的效能與擴充性。
叢集網路
虛擬私有雲原生叢集是預設的網路設定,也是設定新 GKE 叢集的建議選擇。虛擬私有雲原生叢集可處理較大的工作負載、容納更多節點,並提供其他優點。
在這個模式中,虛擬私有雲網路的次要範圍包含所有 Pod IP 位址。然後,系統會針對每個節點自己的 Pod IP 位址,為每個節點指派次要配量範圍。這樣一來,虛擬私有雲網路一開始就能瞭解如何將路徑傳送至 Pod,而不用依賴自訂路徑。單一虛擬私有雲網路最多可有 15,000 個 VM。
另一種做法是使用路徑導向叢集,但這種做法已遭淘汰,且最多只能支援 1,500 個節點。路徑導向叢集不適合大型工作負載。這會耗用 VPC 路徑配額,且缺少 VPC 原生網路的其他優點。做法是為每個新節點,在虛擬私有雲網路的路徑表中新增自訂路徑。
叢集大小
節點超過 5,000 個的叢集必須使用 Private Service Connect。Private Service Connect 會以私密方式連結節點和控制層,並提供更優異的安全性與網路效能。
叢集負載平衡
GKE Ingress 和 Cloud Load Balancing 會設定及部署負載平衡器,將 Kubernetes 工作負載公開至叢集外部和公用網際網路。GKE Ingress 和 Service 控制器會代表 GKE 工作負載部署物件,例如轉送規則、網址對應、後端服務、網路端點群組等。這些資源各有配額和限制,這些限制也適用於 GKE。如果任何 Cloud Load Balancing 資源達到配額上限,系統將無法正確部署特定 Ingress 或 Service,且資源事件中會顯示錯誤。
下表說明使用 GKE Ingress 和服務時的調整大小限制:
負載平衡器 | 每個叢集的節點數量上限 |
---|---|
內部直通式網路負載平衡器 |
|
外部直通式網路負載平衡器 | 每個可用區 1000 個節點 |
外部應用程式負載平衡器 |
|
內部應用程式負載平衡器 | 沒有節點限制 |
如要進一步擴大規模,請與 Google Cloud 銷售團隊聯絡,提高這項上限。
DNS
GKE 中的服務探索功能是由 kube-dns 提供,這項集中式資源可為叢集內執行的 Pod 提供 DNS 解析服務。對於非常大的叢集或要求負載高的工作負載,這可能會成為瓶頸。GKE 會根據叢集大小自動調整 kube-dns,以增加容量。如果這個容量仍不足,GKE 會在每個節點上提供 DNS 查詢的本機分散式解析,也就是 NodeLocal DNSCache。這會在每個 GKE 節點上提供本機 DNS 快取,在本機回答查詢、分散負載,並縮短回應時間。
管理虛擬私有雲原生叢集中的 IP 位址
虛擬私有雲原生叢集會使用三個 IP 位址範圍:
- 節點子網路的主要範圍:預設為 /20 (4092 個 IP 位址)。
- Pod 子網路的次要範圍:預設為 /14 (262,144 個 IP 位址)。不過,您可以設定 Pod 子網路。
- 服務子網路的次要範圍:預設為 /20 (4096 個位址)。不過,建立服務子網路後,您就無法變更這個範圍。
詳情請參閱「虛擬私有雲原生叢集的 IP 位址範圍」。
IP 位址限制和建議:
- 節點限制:節點限制取決於每個節點的主要和 Pod IP 位址。節點和 Pod IP 位址範圍中都必須有足夠的位址,才能佈建新節點。根據預設,由於 Pod IP 位址的限制,您只能建立 1024 個節點。
- 每個節點的 Pod 數量上限:根據預設,每個節點的 Pod 數量上限為 110 個。不過,您可以設定較小的 Pod CIDR,以便有效率地使用每個節點的 Pod。
- 擴充超出 RFC 1918 的範圍:如果需要的 IP 位址數量超出 RFC 1918 定義的私人空間,建議使用非 RFC 1918 私人位址或 PUPI,以獲得更多彈性。
- Service 和 Pod 的次要 IP 位址範圍:根據預設,您可以設定 4096 個 Service。不過,您可以選擇服務子網路範圍,設定更多服務。次要範圍建立後就無法修改。建立叢集時,請確保選擇足夠大的範圍以符合預期的成長情況。不過,您之後可以使用不連續的多 Pod CIDR,為 Pod 新增更多 IP 位址。
如要瞭解詳情,請參考下列資源:
設定節點以提高效能
GKE 節點是一般的 Google Cloud 虛擬機器。部分參數 (例如核心數量或磁碟大小) 可能會影響 GKE 叢集的執行方式。
縮短 Pod 初始化時間
您可以透過映像檔串流,在工作負載要求時,從符合條件的容器映像檔串流資料,進而縮短初始化時間。
輸出流量
在 Google Cloud中,分配給執行個體的機器類型和核心數量決定了網路容量。輸出頻寬上限為 1 至 32 Gbps,而預設 e2-medium-2 機器的輸出頻寬上限為 2 Gbps。如要瞭解頻寬限制的詳細資訊,請參閱「共用核心機器類型」。
IOPS 與磁碟總處理量
在 Google Cloud中,永久磁碟的大小決定了磁碟的 IOPS 與總處理量。GKE 通常使用永久磁碟做為開機磁碟,並用來備份 Kubernetes 的永久磁碟區。增加磁碟大小也會同時提高 IOPS 與總處理量,直至達到特定限制為止。
每個永久磁碟的寫入作業都會計入虛擬機器執行個體的累積網路輸出上限。因此,磁碟的 IOPS 效能 (尤其是 SSD) 不但取決於磁碟大小,同時也取決於執行個體中的 vCPU 數量。由於寫入總處理量的網路輸出上限,較低的核心 VM 會有較低的寫入 IOPS 限制。
如果虛擬機器執行個體的 CPU 不足,應用程式將無法達到IOPS 限制。根據一般規則,每 2000 到 2500 IOPS 的預期流量應要有 1 個可用 CPU。
需要高容量或大量磁碟的工作負載,必須考量單一 VM 可連結的 PD 數量限制。如果是一般 VM,上限為 128 個磁碟,總大小為 64 TB;如果是共用核心 VM,上限為 16 個永久磁碟,總大小為 3 TB。 Google Cloud 會強制執行這項限制,而非 Kubernetes。
監控控制層指標
使用可用的控制層指標設定監控資訊主頁。您可以使用控制平面指標觀察叢集健康狀態、叢集設定變更結果 (例如部署額外工作負載或第三方元件),或是在排解問題時使用。
要監控的最重要指標之一是 Kubernetes API 的延遲時間。延遲時間增加表示系統負載過重。請注意,傳輸大量資料的 LIST 呼叫預期會比小型要求延遲時間長得多。
第三方准入 Webhook 回應緩慢,也可能導致 Kubernetes API 延遲時間增加。您可以使用指標測量 Webhook 的延遲時間,偵測這類常見問題。
建議單一資源呼叫 (例如 GET、POST 或 PATCH) 的上限為一秒。建議命名空間範圍和叢集範圍的 LIST 呼叫上限為 30 秒。上限期望值是由開放原始碼 Kubernetes 社群定義的 SLO 所設定。詳情請參閱「API 呼叫延遲 SLI/SLO 詳細資料」。
Kubernetes 開發人員的最佳做法
改用清單和觀看模式,不要使用定期列出模式
Kubernetes 開發人員可能需要建立符合下列需求的元件:
- 您的元件需要定期擷取某些 Kubernetes 物件的清單。
- 您的元件需要在多個執行個體中執行 (如果是 DaemonSet,甚至需要在每個節點上執行)。
即使定期擷取的物件狀態沒有變更,這類元件仍可能在 kube-apiserver 上產生負載尖峰。
最簡單的方法是使用週期性 LIST 呼叫。不過,每次都必須載入所有物件至記憶體、序列化及轉移,因此對呼叫端和伺服器而言,這種做法效率不彰且成本高昂。過度使用 LIST 要求可能會導致控制層過載,或大幅節流這類要求。
您可以在 LIST 呼叫中設定 resourceVersion=0 參數,改善元件。這可讓 kube-apiserver 使用記憶體內物件快取,並減少 Kubernetes API 伺服器與 etcd API 互動的頻率,進而減少任何相關處理作業。
強烈建議您避免重複發出 LIST 呼叫,並改用清單和監看模式。先列出物件,然後使用 Watch API 取得狀態的增量變更。相較於定期呼叫 LIST,這種做法可縮短處理時間並減少流量。如果物件沒有變更,就不會產生額外負載。
如果您使用 Go 語言,請查看實作此模式的 Go 套件:SharedInformer 和 SharedInformerFactory。
限制觀看和清單產生不必要的流量
Kubernetes 會在內部使用監控,傳送物件更新通知。即使手錶所需的資源遠少於定期 LIST 呼叫,在大型叢集中處理手錶仍會佔用大量叢集資源,進而影響叢集效能。如果從多個位置觀察經常變更的物件,就會產生最大的負面影響。舉例來說,您可以觀察在所有節點上執行的元件中,所有 Pod 的資料。如果您在叢集上安裝第三方程式碼或擴充功能,這些項目可能會在幕後建立這類監控。
建議採行下列最佳做法:
- 減少手錶和 LIST 呼叫產生的不必要處理程序和流量。
- 請避免建立監控多個位置 (例如 DaemonSet) 中經常變更物件的監控項。
- (強烈建議) 建立中央控制器,在單一節點上監控及處理必要資料。
- 只監控部分物件,例如每個節點上的 kubelet 只會監控排定在相同節點上的 Pod。
- 請避免部署第三方元件或擴充功能,以免產生大量監看或 LIST 呼叫,影響叢集效能。
使用 DaemonSet 進行滾動式更新,避免流量突然增加
在叢集中建立 DaemonSet 時,系統會立即在每個節點中排程新的 Pod。如果所有這些新 Pod 都連線至同一個網路端點,這些要求就會同時發生,導致目標主機負載過高。為避免發生這種情況,請使用滾動式更新設定 DaemonSet,並限制 maxSurge
Pod。
限制 Kubernetes 物件資訊清單大小
如果您需要高 Pod 處理量才能快速完成的作業 (例如調整大小或更新大型工作負載),請務必將 Pod 資訊清單大小降至最低,最好小於 10 KiB。
Kubernetes 會將資源資訊清單儲存在鍵/值儲存庫資料庫中。每次擷取資源時,系統都會傳送整個資訊清單,包括使用清單和監看模式時。
資訊清單大小有下列限制:
- 每個物件資訊清單的大小上限:約 1.5 MiB。
- 叢集中所有 Kubernetes API 物件的總配額:預先設定的配額大小為 6 GiB。包括變更記錄,其中列出叢集記錄最近 150 秒內所有物件的所有更新。
- 高流量期間的控制層效能:資訊清單越大,API 伺服器的負載就越高。
如果是單一且很少處理的物件,只要資訊清單小於 1.5 MiB,通常就不會有大小問題。不過,如果經常處理大量物件 (例如超大型工作負載中的 Pod),且資訊清單大小超過 10 KiB,可能會導致 API 呼叫延遲時間增加,整體效能下降。尤其是清單和手錶,可能會受到大型資訊清單大小的顯著影響。此外,叢集狀態資料庫的配額也可能出現問題,因為在 API 伺服器流量較高的期間,過去 150 秒內修訂版本的數量可能會快速累積。
如要縮減 Pod 的資訊清單大小,可以利用 Kubernetes ConfigMap 儲存部分設定,特別是叢集中多個 Pod 共用的部分。舉例來說,環境變數通常會由工作負載中的所有 Pod 共用。
請注意,如果 ConfigMap 物件數量眾多、大小龐大,且處理頻率與 Pod 相同,也可能會遇到類似問題。如果擷取部分設定可減少整體流量,這項功能就非常實用。
停用預設服務帳戶的自動掛接功能
如果 Pod 中執行的邏輯不需要存取 Kubernetes API,您應停用服務帳戶的預設自動掛接功能,避免建立相關的 Secret 和監控。
建立 Pod 時,如果未指定服務帳戶,Kubernetes 會自動執行下列動作:
- 將預設服務帳戶指派給 Pod。
- 將服務帳戶憑證掛接為 Pod 的 Secret。
- 針對每個已掛接的 Secret,kubelet 會建立監控機制,觀察每個節點上該 Secret 的變更。
在大型叢集中,這些動作代表數千個不必要的監看項目,可能會對 kube-apiserver 造成重大負擔。
使用 Protocol Buffers 而非 JSON 提出 API 要求
實作高度可擴充的元件時,請使用通訊協定緩衝區,如「Kubernetes API 概念」所述。
Kubernetes REST API 支援 JSON 和通訊協定緩衝區,做為物件的序列化格式。系統預設使用 JSON,但通訊協定緩衝區更有效率,因為這類緩衝區需要的 CPU 密集處理作業較少,且透過網路傳送的資料較少,因此可大規模提升效能。處理 JSON 相關的額外負荷可能會導致列出大型資料時發生逾時。