多租戶
本頁面概述了叢集多租戶的可用配置選項和最佳實踐。
共享叢集可以節省成本並簡化管理。但是,共享叢集也帶來了諸如安全性、公平性和管理**“吵鬧的鄰居”**等挑戰。
叢集可以透過多種方式共享。在某些情況下,不同的應用程式可能在同一個叢集中執行。在其他情況下,同一個應用程式的多個例項可能在同一個叢集中執行,每個終端使用者一個例項。所有這些型別的共享通常都用一個總稱來描述:**多租戶**。
雖然 Kubernetes 沒有一流的終端使用者或租戶概念,但它提供了多種功能來幫助管理不同的租戶需求。這些將在下面討論。
用例
確定如何共享叢集的第一步是瞭解你的用例,以便評估可用的模式和工具。通常,Kubernetes 叢集中的多租戶分為兩大類,儘管也可能存在許多變體和混合模式。
多個團隊
多租戶的一種常見形式是在組織內多個團隊之間共享一個叢集,每個團隊都可能操作一個或多個工作負載。這些工作負載通常需要在彼此之間以及與位於相同或不同叢集上的其他工作負載之間進行通訊。
在這種情況下,團隊成員通常透過 `kubectl` 等工具直接訪問 Kubernetes 資源,或者透過 GitOps 控制器或其他型別的釋出自動化工具間接訪問。不同團隊成員之間通常存在一定程度的信任,但 Kubernetes 策略(如 RBAC、配額和網路策略)對於安全公平地共享叢集至關重要。
多個客戶
多租戶的另一種主要形式通常涉及軟體即服務(SaaS)供應商為其客戶執行工作負載的多個例項。這種商業模式與這種部署風格密切相關,許多人稱之為“SaaS 租戶”。然而,一個更好的術語可能是“多客戶租戶”,因為 SaaS 供應商也可能使用其他部署模型,並且這種部署模型也可以在 SaaS 之外使用。
在這種情況下,客戶無法訪問叢集;Kubernetes 在他們的視角下是不可見的,僅由供應商用於管理工作負載。成本最佳化通常是一個關鍵問題,Kubernetes 策略用於確保工作負載之間高度隔離。
術語
租戶
在討論 Kubernetes 中的多租戶時,“租戶”沒有單一的定義。相反,租戶的定義將根據討論的是多團隊還是多客戶租戶而異。
在多團隊使用中,租戶通常是一個團隊,每個團隊通常部署少量工作負載,其規模隨服務的複雜性而定。然而,“團隊”的定義本身可能模糊,因為團隊可能被組織成更高級別的部門或細分為更小的團隊。
相比之下,如果每個團隊為每個新客戶部署專用工作負載,他們使用的是多客戶租戶模型。在這種情況下,“租戶”僅僅是一組共享單個工作負載的使用者。這可能是一個完整的公司,也可能只是該公司的一個團隊。
在許多情況下,同一個組織在不同上下文中使用“租戶”的兩種定義。例如,平臺團隊可能向多個內部“客戶”提供安全工具和資料庫等共享服務,SaaS 供應商也可能擁有多個團隊共享一個開發叢集。最後,混合架構也是可能的,例如 SaaS 提供商將每個客戶的工作負載用於敏感資料,並結合多租戶共享服務。

顯示共存租戶模型的叢集
隔離
有幾種方法可以使用 Kubernetes 設計和構建多租戶解決方案。每種方法都有其自身的一系列權衡,影響隔離級別、實現工作量、操作複雜性和服務成本。
Kubernetes 叢集由執行 Kubernetes 軟體的**控制平面**和由執行租戶工作負載的節點組成**資料平面**。租戶隔離可以根據組織要求應用於控制平面和資料平面。
所提供的隔離級別有時用“硬”多租戶(意味著強隔離)和“軟”多租戶(意味著弱隔離)等術語來描述。特別是,“硬”多租戶通常用於描述租戶之間互不信任的情況,通常從安全和資源共享的角度(例如,防範資料洩露或 DDoS 等攻擊)。由於資料平面通常具有更大的攻擊面,“硬”多租戶通常需要額外注意隔離資料平面,儘管控制平面隔離也仍然至關重要。
然而,“硬”和“軟”這兩個術語常常令人困惑,因為沒有適用於所有使用者的單一固定定義。相反,“硬度”或“軟度”最好理解為一個廣闊的範圍,有許多不同的技術可以根據你的需求在叢集中維護不同型別的隔離。
在更極端的情況下,完全放棄任何叢集級共享,併為每個租戶分配其專用叢集,甚至可能在虛擬機器不被視為足夠安全邊界的情況下,在專用硬體上執行,這可能更容易或有必要。對於託管的 Kubernetes 叢集,這可能更容易實現,因為建立和操作叢集的開銷至少部分由雲提供商承擔。必須權衡更強的租戶隔離的收益與管理多個叢集的成本和複雜性。多叢集 SIG 負責處理這些型別的用例。
本頁面的其餘部分重點介紹用於共享 Kubernetes 叢集的隔離技術。但是,即使你正在考慮專用叢集,審查這些建議也可能很有價值,因為如果你的需求或能力發生變化,它將為你提供將來轉向共享叢集的靈活性。
控制平面隔離
控制平面隔離確保不同的租戶不能訪問或影響彼此的 Kubernetes API 資源。
名稱空間
在 Kubernetes 中,名稱空間提供了一種機制,用於在單個叢集中隔離 API 資源組。這種隔離具有兩個關鍵維度:
名稱空間內的物件名稱可以與其他名稱空間中的名稱重疊,類似於資料夾中的檔案。這允許租戶命名他們的資源,而無需考慮其他租戶正在做什麼。
許多 Kubernetes 安全策略都限定在名稱空間範圍內。例如,RBAC 角色和網路策略是名稱空間範圍的資源。使用 RBAC,使用者和服務賬號可以被限制在名稱空間內。
在多租戶環境中,名稱空間有助於將租戶的工作負載分段為邏輯上獨立的管理單元。事實上,一種常見的做法是將每個工作負載隔離到其自己的名稱空間中,即使多個工作負載由同一個租戶操作。這確保每個工作負載都有其自己的身份,並且可以配置適當的安全策略。
名稱空間隔離模型需要配置其他幾個 Kubernetes 資源、網路外掛,並遵循安全最佳實踐,以正確隔離租戶工作負載。這些考慮將在下面討論。
訪問控制
控制平面最重要的一種隔離型別是授權。如果團隊或其工作負載可以訪問或修改彼此的 API 資源,他們就可以更改或停用所有其他型別的策略,從而抵消這些策略可能提供的任何保護。因此,至關重要的是要確保每個租戶僅擁有其所需名稱空間的適當訪問許可權,不多不少。這被稱為“最小許可權原則”。
基於角色的訪問控制(RBAC)通常用於在 Kubernetes 控制平面中強制執行授權,適用於使用者和工作負載(服務賬號)。角色和角色繫結是 Kubernetes 物件,它們在名稱空間級別用於在應用程式中強制執行訪問控制;類似的物件也用於授權訪問叢集級物件,儘管這些物件對於多租戶叢集不太有用。
在多團隊環境中,必須使用 RBAC 限制租戶對適當名稱空間的訪問,並確保叢集範圍的資源只能由叢集管理員等特權使用者訪問或修改。
如果一個策略最終授予使用者超出其所需許可權,這很可能表明包含受影響資源的名稱空間應該被重構為更細粒度的名稱空間。名稱空間管理工具可以透過對不同名稱空間應用通用的 RBAC 策略來簡化這些更細粒度名稱空間的管理,同時在必要時仍然允許細粒度策略。
配額
Kubernetes 工作負載會消耗節點資源,例如 CPU 和記憶體。在多租戶環境中,你可以使用資源配額來管理租戶工作負載的資源使用。對於多個團隊的用例,其中租戶可以訪問 Kubernetes API,你可以使用資源配額來限制租戶可以建立的 API 資源數量(例如:Pod 數量或 ConfigMap 數量)。對物件數量的限制確保了公平性,旨在避免“吵鬧的鄰居”問題影響共享控制平面的其他租戶。
資源配額是名稱空間級別的物件。透過將租戶對映到名稱空間,叢集管理員可以使用配額來確保租戶不能壟斷叢集資源或使其控制平面過載。名稱空間管理工具簡化了配額的管理。此外,雖然 Kubernetes 配額僅適用於單個名稱空間,但某些名稱空間管理工具允許名稱空間組共享配額,從而使管理員能夠以比內建配額更少的精力獲得更大的靈活性。
配額可防止單個租戶消耗超出其分配份額的資源,從而最大限度地減少“吵鬧的鄰居”問題,即一個租戶對其他租戶工作負載的效能產生負面影響。
當你在名稱空間上應用配額時,Kubernetes 要求你還為每個容器指定資源請求和限制。限制是容器可以消耗的資源量的上限。嘗試消耗超出配置限制的資源的容器將根據資源型別被限流或終止。當資源請求設定低於限制時,每個容器都保證獲得請求量,但工作負載之間仍可能存在一些潛在影響。
配額無法防止所有型別的資源共享,例如網路流量。節點隔離(下文描述)可能是解決此問題的更好方案。
資料平面隔離
資料平面隔離確保不同租戶的 Pod 和工作負載充分隔離。
網路隔離
預設情況下,Kubernetes 叢集中的所有 Pod 都允許相互通訊,並且所有網路流量都是未加密的。這可能導致安全漏洞,即流量意外或惡意傳送到非預期目的地,或被受損節點上的工作負載攔截。
Pod 間的通訊可以使用網路策略進行控制,該策略使用名稱空間標籤或 IP 地址範圍限制 Pod 間的通訊。在需要租戶間嚴格網路隔離的多租戶環境中,建議首先使用拒絕 Pod 間通訊的預設策略,並另外新增一條規則允許所有 Pod 查詢 DNS 伺服器進行名稱解析。有了這樣的預設策略,你就可以開始新增更寬鬆的規則,允許名稱空間內的通訊。此外,在網路策略定義中,如果需要在名稱空間之間允許流量,建議不要使用空標籤選擇器 '{}' 作為 namespaceSelector 欄位。該方案可以根據需要進一步完善。請注意,這僅適用於單個控制平面內的 Pod;屬於不同虛擬控制平面的 Pod 無法透過 Kubernetes 網路相互通訊。
名稱空間管理工具可以簡化預設或通用網路策略的建立。此外,其中一些工具允許你在整個叢集中強制執行一致的名稱空間標籤集,確保它們是你策略的可靠基礎。
警告
網路策略需要支援網路策略實現的CNI 外掛。否則,NetworkPolicy 資源將被忽略。更高階的網路隔離可以透過服務網格提供,除了名稱空間之外,服務網格還提供基於工作負載身份的 OSI 第 7 層策略。這些更高級別的策略可以更容易地管理基於名稱空間的多租戶,特別是當多個名稱空間專用於單個租戶時。它們通常還透過雙向 TLS 提供加密,即使在節點受損的情況下也能保護你的資料,並可在專用或虛擬叢集之間工作。然而,它們在管理上可能要複雜得多,並且可能不適用於所有使用者。
儲存隔離
Kubernetes 提供了多種卷型別,可用作工作負載的持久儲存。為了安全和資料隔離,建議使用動態卷配置,並應避免使用依賴節點資源的卷型別。
StorageClass 允許你根據服務質量級別、備份策略或叢集管理員確定的自定義策略,描述叢集提供的自定義儲存“類”。
Pod 可以使用 PersistentVolumeClaim 請求儲存。PersistentVolumeClaim 是一個名稱空間資源,它允許隔離儲存系統的部分並將它們專用於共享 Kubernetes 叢集中的租戶。但是,重要的是要注意 PersistentVolume 是一個叢集範圍的資源,並且其生命週期獨立於工作負載和名稱空間。
例如,你可以為每個租戶配置單獨的 StorageClass,並以此來加強隔離。如果 StorageClass 是共享的,則應設定回收策略為 Delete
,以確保 PersistentVolume 不能在不同名稱空間之間重複使用。
沙箱容器
Kubernetes Pod 由一個或多個在工作節點上執行的容器組成。容器利用作業系統級虛擬化,因此提供的隔離邊界比利用基於硬體虛擬化的虛擬機器弱。
在共享環境中,應用程式和系統層中未打補丁的漏洞可能被攻擊者利用,導致容器逃逸和遠端程式碼執行,從而獲得對主機資源的訪問許可權。在某些應用程式中,例如內容管理系統 (CMS),客戶可能被允許上傳和執行不受信任的指令碼或程式碼。在這兩種情況下,都希望有進一步隔離和保護工作負載的強隔離機制。
沙箱提供了一種隔離在共享叢集中執行的工作負載的方法。它通常涉及在單獨的執行環境(例如虛擬機器或使用者空間核心)中執行每個 Pod。當你執行不受信任的程式碼(其中工作負載被假定為惡意)時,通常建議使用沙箱。這種隔離之所以必要,部分原因是容器是在共享核心上執行的程序;它們從底層主機掛載 `/sys` 和 `/proc` 等檔案系統,使其不如在擁有自己核心的虛擬機器上執行的應用程式安全。雖然可以使用 seccomp、AppArmor 和 SELinux 等控制元件來加強容器的安全性,但很難對在共享叢集中執行的所有工作負載應用一套通用的規則。在沙箱環境中執行工作負載有助於保護主機免受容器逃逸,即攻擊者利用漏洞獲取對主機系統以及在該主機上執行的所有程序/檔案的訪問許可權。
虛擬機器和使用者空間核心是兩種流行的沙箱方法。
節點隔離
節點隔離是另一種可用於將租戶工作負載彼此隔離的技術。透過節點隔離,一組節點專用於執行特定租戶的 Pod,並且禁止租戶 Pod 的混合。這種配置減少了“吵鬧的鄰居”問題,因為節點上執行的所有 Pod 都將屬於單個租戶。節點隔離洩露資訊的風險略低,因為設法逃逸出容器的攻擊者將只能訪問該節點上掛載的容器和卷。
儘管來自不同租戶的工作負載在不同的節點上執行,但重要的是要注意 kubelet 和(除非使用虛擬控制平面)API 服務仍然是共享服務。熟練的攻擊者可能會利用分配給 kubelet 或在節點上執行的其他 Pod 的許可權,在叢集內部橫向移動並訪問在其他節點上執行的租戶工作負載。如果這是一個主要問題,請考慮實施補償控制,例如 seccomp、AppArmor 或 SELinux,或探索使用沙箱容器或為每個租戶建立單獨的叢集。
從計費角度來看,節點隔離比沙盒容器更容易理解,因為你可以按節點而不是按 Pod 收費。它還具有更少的相容性問題和效能問題,並且可能比沙盒容器更容易實現。例如,可以為每個租戶的節點配置汙點,以便只有具有相應容忍度的 Pod 才能在其上執行。然後,可以使用一個變更 Webhook 自動向部署到租戶名稱空間的 Pod 新增容忍度和節點親和性,以便它們在為該租戶指定的特定節點集上執行。
節點隔離可以使用Pod 節點選擇器實現。
其他注意事項
本節討論與多租戶相關的其他 Kubernetes 構造和模式。
API 優先順序和公平性
API 優先順序和公平性是 Kubernetes 的一個功能,允許你為叢集中執行的某些 Pod 分配優先順序。當應用程式呼叫 Kubernetes API 時,API 伺服器會評估分配給 Pod 的優先順序。優先順序較高的 Pod 的呼叫將在優先順序較低的 Pod 之前完成。當爭用很高時,優先順序較低的呼叫可能會排隊,直到伺服器不那麼繁忙,或者你可以拒絕這些請求。
在 SaaS 環境中,使用 API 優先順序和公平性不會很常見,除非你允許客戶執行與 Kubernetes API 互動的應用程式,例如控制器。
服務質量(QoS)
當你執行 SaaS 應用程式時,你可能希望能夠為不同的租戶提供不同服務質量 (QoS) 等級的服務。例如,你可能擁有免費增值服務,其效能保證和功能較少,而收費服務層則具有特定的效能保證。幸運的是,有一些 Kubernetes 構造可以幫助你在共享叢集中實現這一點,包括網路 QoS、儲存類以及 Pod 優先順序和搶佔。這些方法的目的是為租戶提供他們所支付的服務質量。讓我們從網路 QoS 開始。
通常,節點上的所有 Pod 共享一個網路介面。如果沒有網路 QoS,一些 Pod 可能會以犧牲其他 Pod 為代價,不公平地佔用可用頻寬的份額。Kubernetes 頻寬外掛為網路建立了一個擴充套件資源,允許你使用 Kubernetes 資源構造(即請求/限制)透過 Linux tc 佇列對 Pod 應用速率限制。請注意,根據網路外掛文件,該外掛被認為是實驗性的,在生產環境中使用之前應進行徹底測試。
對於儲存 QoS,你可能希望建立具有不同效能特徵的不同儲存類或配置檔案。每個儲存配置檔案都可以與針對不同工作負載(如 IO、冗餘或吞吐量)最佳化的不同服務層相關聯。可能需要額外的邏輯來允許租戶將適當的儲存配置檔案與其工作負載相關聯。
最後是Pod 優先順序和搶佔,你可以為 Pod 分配優先順序值。當排程 Pod 時,如果資源不足以排程分配了更高優先順序的 Pod,排程器將嘗試驅逐優先順序較低的 Pod。如果你的用例中租戶在共享叢集中具有不同的服務層級(例如免費和付費),你可能希望使用此功能為某些層級賦予更高的優先順序。
DNS
Kubernetes 叢集包含一個域名系統 (DNS) 服務,用於為所有 Service 和 Pod 提供名稱到 IP 地址的轉換。
在多租戶環境中,如果租戶可以訪問 Pod 和其他 Kubernetes 資源,或者需要更強的隔離,可能需要阻止 Pod 查詢其他名稱空間中的服務。你可以透過配置 DNS 服務的安全規則來限制跨名稱空間 DNS 查詢。例如,CoreDNS(Kubernetes 的預設 DNS 服務)可以利用 Kubernetes 元資料將查詢限制在名稱空間內的 Pod 和 Service。有關更多資訊,請閱讀 CoreDNS 文件中配置此功能的示例。
當使用每個租戶一個虛擬控制平面模型時,必須為每個租戶配置一個 DNS 服務,或者必須使用多租戶 DNS 服務。這是一個定製版 CoreDNS 的示例,它支援多個租戶。
運算子
Operator 是管理應用程式的 Kubernetes 控制器。Operator 可以簡化應用程式多個例項(如資料庫服務)的管理,這使其成為多消費者(SaaS)多租戶用例中的常見構建塊。
在多租戶環境中使用 Operator 應遵循更嚴格的準則。具體而言,Operator 應該:
- 支援在不同的租戶名稱空間中建立資源,而不僅僅是在 Operator 部署的名稱空間中。
- 確保 Pod 配置了資源請求和限制,以確保排程和公平性。
- 支援為資料平面隔離技術(如節點隔離和沙箱容器)配置 Pod。
實現
共享 Kubernetes 叢集以實現多租戶主要有兩種方式:使用名稱空間(即每個租戶一個名稱空間)或虛擬化控制平面(即每個租戶一個虛擬控制平面)。
在這兩種情況下,還建議進行資料平面隔離以及管理其他注意事項,例如 API 優先順序和公平性。
名稱空間隔離得到了 Kubernetes 的良好支援,資源成本可以忽略不計,並提供了允許租戶適當互動的機制,例如允許服務到服務通訊。然而,它可能難以配置,並且不適用於無法進行名稱空間管理的 Kubernetes 資源,例如自定義資源定義、儲存類和 Webhook。
控制平面虛擬化允許隔離非名稱空間資源,代價是資源使用量略高,跨租戶共享更困難。當名稱空間隔離不足但又不想使用專用叢集時,它是一個不錯的選擇,因為專用叢集維護成本高昂(尤其是在本地)或開銷更高且缺乏資源共享。然而,即使在虛擬化控制平面內,你很可能也會透過使用名稱空間獲得收益。
這兩個選項將在以下部分中更詳細地討論。
每個租戶一個名稱空間
如前所述,即使你正在使用專用叢集或虛擬化控制平面,也應考慮將每個工作負載隔離到其自己的名稱空間中。這確保每個工作負載僅能訪問自己的資源(例如 ConfigMap 和 Secret),並允許你為每個工作負載定製專用安全策略。此外,最佳實踐是為每個名稱空間提供在整個叢集中(即,即使它們在單獨的叢集中)唯一的名稱,因為這使你可以在將來靈活地在專用叢集和共享叢集之間切換,或使用服務網格等多叢集工具。
反之,在租戶級別(而不僅僅是工作負載級別)分配名稱空間也有優勢,因為通常存在適用於單個租戶擁有的所有工作負載的策略。然而,這會帶來自身的問題。首先,這使得為單個工作負載定製策略變得困難甚至不可能;其次,要確定一個單一的“租戶”級別來分配名稱空間可能具有挑戰性。例如,一個組織可能有部門、團隊和子團隊——應該為哪個層級分配名稱空間?
一種可能的方法是將名稱空間組織成層次結構,並在它們之間共享某些策略和資源。這可能包括管理名稱空間標籤、名稱空間生命週期、委派訪問以及跨相關名稱空間的共享資源配額。這些功能在多團隊和多客戶場景中都很有用。
每個租戶一個虛擬控制平面
控制平面隔離的另一種形式是使用 Kubernetes 擴充套件為每個租戶提供一個虛擬控制平面,從而實現叢集範圍 API 資源的細分。此模型可與資料平面隔離技術結合使用,以安全地管理跨租戶的工作節點。
基於虛擬控制平面的多租戶模型透過為每個租戶提供專用的控制平面元件,從而擴充套件了基於名稱空間的多租戶,並完全控制叢集範圍的資源和附加服務。工作節點在所有租戶之間共享,並由通常租戶無法訪問的 Kubernetes 叢集管理。這個叢集通常被稱為**超級叢集**(或有時稱為**主機叢集**)。由於租戶的控制平面不直接與底層計算資源關聯,因此被稱為**虛擬控制平面**。
虛擬控制平面通常由 Kubernetes API 伺服器、控制器管理器和 etcd 資料儲存組成。它透過元資料同步控制器與超級叢集互動,該控制器協調租戶控制平面和超級叢集控制平面之間的更改。
透過為每個租戶使用專用的控制平面,解決了由於所有租戶共享一個 API 伺服器而產生的大部分隔離問題。示例包括控制平面中的“吵鬧的鄰居”、策略配置錯誤無法控制的爆炸半徑,以及 Webhook 和 CRD 等叢集範圍物件之間的衝突。因此,虛擬控制平面模型特別適用於每個租戶需要訪問 Kubernetes API 伺服器並期望完全叢集可管理性的情況。
改進的隔離是以執行和維護每個租戶獨立的虛擬控制平面為代價的。此外,每個租戶的控制平面並不能解決資料平面中的隔離問題,例如節點級別的“吵鬧的鄰居”或安全威脅。這些問題仍然必須單獨解決。