Kubernetes 集群規模雜談

節點數量

早在 Kubernetes 1.2 時候,就已經宣布達到 1000 節點的規模了,在 1.6 版本更達到了 5000 節點的規模。各大廠也都有了各自的超大規模單一集群。然而普羅大眾的情況是如何呢?Sysdig 在 2019 年度容器應用報告中得到的結果是,大於 50 節點規模的集群不足 10%,另外一個佐證是 Mohamed Ahmed 的一篇調查報告中也提供了類似的數據。這種情況的一種解釋是,目前的應用階段還比較早期,處於試探期間;然而從一個側面來說,Sysdig 的調研對象針對的是生產應用,也就是說處於生產應用狀態下的集群,絕大多數都是這種小規模集群。根據對 CNCF Landscape 中 Distribution 分類的產品的抽查,也可以看到隨處可見的 Kubernetes As Service 類似功能的實現,這也證實了小集群協作方案的落地趨勢。相對於少量大集群,多個小集群的差異在於:

隔離程度高

雖然現在存在不少沙箱容器實現,然而最易用的、生態最為成熟的方案還是 Docker為代表的傳統容器方案,傳統容器方案所缺失的隔離能力,通過多租戶多集群方式是一個非常自然的思路。

實現難度低

中國幾個大廠都有自己的大規模 Kubernetes 集群實現方式,然而通常需要對基礎組件大動干戈,甚至不惜使用無法迴流社區的孤島版本,雖然部分大企業的研究院等相關部門已經具備了非常強的研發實力,然而對於通常的 To B 場景來說,這並不是一個合適的選擇。

運管成本高

多個集群很明顯會需要更多的運維和管理人力的投入。

資源利用率低

多個集群都會有自己的 Master 組件、ETCD 集群、網路組件等,這些都會搶佔更多原本屬於工作負載的系統資源,客觀上降低了資源的總體利用率。

節點尺寸

目前很多 Kubernetes 系統都會使用虛擬機來做為節點。那麼虛擬機的資源是多分還是少分呢?下表是一個簡單的對比:

大節點

小節點

備註

節點數量

同樣的資源總量情況下,相對來說小資源節點會得到更多的數量。

運維成本

通常情況下,節點的運維成本是和節點數量正相關的。

容錯能力

較大的節點上通常會集中較多的應用,因此在節點出現故障時,可能會帶來更大的損失。

資源粒度

單節點資源較大,因此其資源粒度也較大。

應用副本數

同一應用的多個副本,如果調度到同一個節點上的話,對於提高其負載能力和健壯性來說並無裨益。

副本規模

毫無疑問,具備更多資源的大節點,能夠運行更大資源需求範圍的容器應用。

系統開銷

每個虛擬機都會有自己的作業系統、網路等基礎開銷,因此相對於少量大節點來說,大量的小節點會消耗更多的資源。

虛擬機分配難度

過大的節點資源需求,如果採用虛擬機分配,就需要有更大規模的物理機提供支援。

除了這些原則性的條目之外,更重要的決策依據就是運行在集群上的應用需求。例如某租戶的集群需要支撐 20 個應用,共 300 個 Pod,按照常見的每節點 30-50 Pod 的分布,就需要 6-10 個運算節點(Node)。以 10 節點算,加入系統保留、冗餘等計算,可能需要 10 * 120G 的虛擬機實例;然而考慮到故障情況——一個節點的故障,最好的結果也是短期內降低 10% 的算力。如果擴張到 40 個 32G 的虛擬機節點,會大幅降低單節點故障的影響——當然也會提高網路的複雜性和效率要求。

應用資源

Java 應用是特別常見的遷移案例,除掉微服務化、網格、分散式等改造要求之外,資源的申請和限制是一個必須要面對的門檻。requests 是個用於調度的定義,Kubernetes 根據這個要求來選擇能夠滿足要求的節點來分配應用;而 limits 則會用於觸發 OOM。

眾所周知的是,Java 的早期版本是無法識別容器內的記憶體限制的,因此如果沒有限制堆記憶體上限,又開啟了 limits,就會被 Kubernetes 殺掉。因此針對容器中運行的情況,需要進行一些啟動參數的設置。

如果允許更新到新版本的 JVM,可以使用新引入的 UseCGroupMemoryLimitForHeap、MaxRAMFraction 參數,讓 JVM 直接繼承容器的定義。

如果無法直接升級,那麼就有必要設置 xmx 和 xms 參數了,這裡有幾個小建議:

  • xmx 和 xms,request 和 limits 建議設成一致,能省掉很多麻煩。
  • tmpfs、filemapping 等都是可能的記憶體大戶。
  • JVM 並不是唯一的記憶體消耗者,一般建議 Limit 大於 XMX 25% 以上。
  • /sys/fs/cgroup/memory/memory.stat 是你的好朋友。

Kubernetes 中的 CPU 和記憶體

Kubernetes 集群中的資源,主要關注的是 CPU 和記憶體兩種。Pod 的定義中會定義對資源需求的聲明,聲明方式分為 Request 和 Limit。

Request 是一個調度參數,可以理解為基本需求:一個 Pod 中的所有容器的 Request 之和,就是 Pod 對資源的最小需求,調度器根據這個最小需求來選擇具備條件的節點,在其上運行被調度的 Pod。

Limit 是一個安全參數,它的值一定大於 Request,顧名思義,它聲明的是上限:

CPU是彈性資源,如果容器使用CPU達到Limit,就無法進一步提高運算能力,可能會導致運算速度無法滿足需求。

  • Memory 是非彈性資源,如果容器使用 Memory 達到 Limit,就會觸發 cgroup 的 OOM 事件,導致容器被殺死。

綜上所述,Memory超限會對業務產生更大傷害,那麼是不是不設限會更安全?答案很顯然是否定的:

  • 不設置 Limit,一旦引發系統 OOM 或者驅逐事件,宏觀來看,都會導致一個不可預知的結果。
  • 不設置 Request,Kubernetes 調度器會失去重要的調度標準,會影響負載分布的準確性。

一般來說如果 Limit 大於 Request(稱為 Burstable),Kubernetes 會根據 Request 將 Pod 調度到滿足 Request 要求的節點上去,然而一旦記憶體消耗從 Request 向著 Limit 增長的過程中出現了節點記憶體不足的情況,仍然會引發驅逐問題,因此對於保障級別高的業務,我們強烈建議將 Limit 設置為和 Request 相等。

副本和節點數量

目前 Kubernetes 的主流網路模型是基於 iptables 的,很顯然 Service、Endpoint 和 Pod 並非越多越好。

而對於應用來說更多的副本數往往意味著更好的容錯能力——同樣損失一個副本,越多總數意味著業務損失越小。

參考資料

  • https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
  • https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/
  • https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/
  • https://dig.sysdig.com/c/pf-2019-container-usage-report?x=u_WFRi&mkt_tok=eyJpIjoiWW1GbVptUmtOakk1T1RVNCIsInQiOiJCUitxTXpSYUpXbVJOUDBUK09sbDh4aDVDNkZURHFXK0UwdUNEbkp6UG43XC9VamJIbm9obzJ6MDdcL3EwYXRHS0dTMVdrQXlJaEZDUFd5WnE0WUpXa1ZNVHZyRFkrYjlTNmhwb3d4cFk0alBSOHBqY09mY0pkaDV1VkZCeCtOaHpnIn0%3D