本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Hypernetes:為 Kubernetes 帶來安全和多租戶
雖然許多開發人員和安全專業人員認為 Linux 容器是有效的隔離邊界,但許多使用者需要更強的隔離程度,尤其是在多租戶環境中執行的使用者。不幸的是,目前這些使用者被迫將他們的容器執行在虛擬機器中,甚至每個容器一個虛擬機器。
不幸的是,這導致了雲原生部署的許多優勢的喪失:虛擬機器啟動時間慢;每個容器都有記憶體開銷;低利用率導致資源浪費。
在這篇文章中,我們將介紹 HyperContainer,一種基於虛擬機器管理程式的容器,並探討它如何自然地融入 Kubernetes 設計,使M戶能夠直接為他們的客戶提供虛擬化容器,而不是將它們封裝在完整的虛擬機器中。
HyperContainer
HyperContainer 是一種基於虛擬機器管理程式的容器,它允許您使用標準虛擬機器管理程式(KVM、Xen 等)啟動 Docker 映象。作為一個開源專案,HyperContainer 由一個相容 OCI 的執行時實現,名為 runV,以及一個管理守護程式,名為 hyperd。HyperContainer 背後的理念非常簡單:結合虛擬化和容器的最佳優勢。
我們可以將容器視為兩部分(就像 Kubernetes 所做的那樣)。第一部分是容器執行時,HyperContainer 使用虛擬化來實現執行隔離和資源限制,而不是名稱空間和 cgroup。第二部分是應用程式資料,HyperContainer 利用 Docker 映象。因此,在 HyperContainer 中,虛擬化技術使得構建一個具有獨立客機核心的完全隔離沙箱成為可能(因此 top
和 /proc 等工具都可以工作),但從開發人員的角度來看,它是可移植的,並且行為類似於標準容器。
HyperContainer 作為 Pod
HyperContainer 的有趣之處不僅在於它對於多租戶環境(例如公共雲)足夠安全,還在於它如何完美地融入 Kubernetes 的理念。
Kubernetes 中最重要的概念之一是 Pods。Pod 的設計是從實際工作負載中吸取的經驗教訓(Borg 論文第 8.1 節),在許多情況下,人們希望有一個由多個容器組成的原子排程單元(請檢視此示例以獲取更多資訊)。在 Linux 容器的上下文中,Pod 將多個容器包裝和封裝成一個邏輯組。但在 HyperContainer 中,虛擬機器管理程式充當了一個自然的邊界,Pod 被引入作為一流物件。
HyperContainer 將輕量級應用程式容器的 Pod 進行封裝,並在 Pod 級別暴露容器介面。在 Pod 內部,會啟動一個名為 HyperKernel 的極簡 Linux 核心。這個 HyperKernel 是用一個名為 HyperStart 的微型 Init 服務構建的。它將作為 PID 1 程序,建立 Pod,設定 Mount 名稱空間,並從載入的映象中啟動應用程式。
這個模型與 Kubernetes 配合得很好。HyperContainer 與 Kubernetes 的整合,正如我們在標題中所示,構成了 Hypernetes 專案。
Hypernetes
Kubernetes 最好的部分之一是它被設計為支援多種容器執行時,這意味著使用者不會被鎖定在單個供應商。我們很高興地宣佈,我們已經開始與 Kubernetes 團隊合作,將 HyperContainer 整合到 Kubernetes 上游。這種整合包括:
- 容器執行時最佳化和重構
- 新的客戶端-伺服器模式執行時介面
- containerd 整合以支援 runV
OCI 標準和 kubelet 的多執行時架構使得這種整合變得更加容易,儘管 HyperContainer 並非基於 Linux 容器技術棧。
另一方面,為了在多租戶環境中執行 HyperContainers,我們還建立了一個新的網路外掛並修改了一個現有的卷外掛。由於 Hypernetes 將 Pod 作為自己的虛擬機器執行,因此它可以利用您現有的 IaaS 層技術來實現多租戶網路和持久卷。當前的 Hypernetes 實現使用標準的 Openstack 元件。
下面我們將詳細介紹所有這些是如何實現的。
身份和認證
在 Hypernetes 中,我們選擇 Keystone 來管理不同的租戶,並在任何管理操作期間為租戶執行身份識別和認證。由於 Keystone 來自 OpenStack 生態系統,它與我們在 Hypernetes 中使用的網路和儲存外掛無縫協作。
多租戶網路模型
對於多租戶容器叢集,每個租戶都需要與其他租戶進行強網路隔離。在 Hypernetes 中,每個租戶都有自己的網路。與使用 OpenStack 配置新網路(這很複雜)不同,使用 Hypernetes,您只需像下面這樣建立一個 Network 物件。
apiVersion: v1
kind: Network
metadata:
name: net1
spec:
tenantID: 065f210a2ca9442aad898ab129426350
subnets:
subnet1:
cidr: 192.168.0.0/24
gateway: 192.168.0.1
請注意,tenantID 由 Keystone 提供。此 yaml 將自動建立一個帶有預設路由器和子網 192.168.0.0/24 的新 Neutron 網路。
網路控制器將負責使用者建立的任何網路例項的生命週期管理。此網路可以分配給一個或多個名稱空間,屬於同一網路的任何 Pod 都可以透過 IP 地址直接相互訪問。
apiVersion: v1
kind: Namespace
metadata:
name: ns1
spec:
network: net1
如果 Namespace 沒有 Network 規範,它將使用預設的 Kubernetes 網路模型,包括預設的 kube-proxy。因此,如果使用者在帶有相關 Network 的 Namespace 中建立 Pod,Hypernetes 將遵循 Kubernetes Network Plugin Model 為此 Pod 設定 Neutron 網路。這是一個高階示例:
{: HyperContainer 封裝了一個輕量級應用程式容器的 Pod。}
Hypernetes 使用一個名為 kubestack 的獨立 gRPC 處理程式,將 Kubernetes Pod 請求轉換為 Neutron 網路 API。此外,kubestack 還負責處理另一個重要的網路功能:多租戶服務代理。
在多租戶環境中,預設基於 iptables 的 kube-proxy 無法訪問單個 Pod,因為它們被隔離到不同的網路中。相反,Hypernetes 使用每個 HyperContainer 中內建的 HAproxy 作為門戶。此 HAproxy 將代理該 Pod 名稱空間中的所有 Service 例項。Kube-proxy 將透過遵循標準的 OnServiceUpdate 和 OnEndpointsUpdate 過程來負責更新這些後端伺服器,因此使用者不會注意到任何差異。這種方法的一個缺點是 HAproxy 必須監聽某些特定埠,這可能與使用者的容器衝突。這就是為什麼我們計劃在下一次釋出中使用 LVS 替換此代理。
在基於 Neutron 的網路外掛的幫助下,Hypernetes 服務能夠提供一個 OpenStack 負載均衡器,就像 GCE 上的“外部”負載均衡器一樣。當用戶使用外部 IP 建立 Service 時,將建立一個 OpenStack 負載均衡器,並透過上述 kubestack 工作流自動更新端點。
持久儲存
在考慮儲存時,我們實際上正在 Kubernetes 中構建一個感知租戶的持久卷。我們之所以決定不使用 Kubernetes 現有的 Cinder 卷外掛,是因為它的模型在虛擬化情況下不起作用。具體來說:
Cinder 卷外掛要求 OpenStack 作為 Kubernetes 提供程式。
OpenStack 提供程式將找到目標 Pod 正在執行的虛擬機器。
Cinder 卷外掛會將 Cinder 卷掛載到 Kubernetes 主機虛擬機器內的路徑。
kubelet 將此路徑作為卷繫結掛載到目標 Pod 的容器中。
但在 Hypernetes 中,事情變得簡單得多。由於 Pod 的物理邊界,HyperContainer 可以直接將 Cinder 卷作為塊裝置掛載到 Pod 中,就像正常的虛擬機器一樣。這種機制消除了在上述現有 Cinder 卷工作流中查詢 Nova 以找出目標 Pod 虛擬機器所需額外時間。
Hypernetes 中 Cinder 外掛的當前實現基於 Ceph RBD 後端,其工作方式與所有其他 Kubernetes 卷外掛相同,只需記住預先建立 Cinder 卷(由下面的 volumeID 引用)。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: nginx-persistent-storage
mountPath: /var/lib/nginx
volumes:
- name: nginx-persistent-storage
cinder:
volumeID: 651b2a7b-683e-47e1-bdd6-e3c62e8f91c0
fsType: ext4
因此,當用戶提供帶有 Cinder 卷的 Pod yaml 時,Hypernetes 將檢查 kubelet 是否正在使用 Hyper 容器執行時。如果是,Cinder 卷可以直接掛載到 Pod,無需任何額外的路徑對映。然後,卷元資料將作為 HyperContainer 規範的一部分傳遞給 Kubelet RunPod 程序。完成!
感謝 Kubernetes 網路和卷的外掛模型,我們能夠輕鬆地為 HyperContainer 構建我們自己的上述解決方案,儘管它本質上與傳統的 Linux 容器不同。我們還計劃在執行時整合完成後,遵循 CNI 模型和卷外掛標準,將這些解決方案提交給 Kubernetes 上游。
我們相信所有這些開源專案都是容器生態系統的重要組成部分,它們的成長在很大程度上取決於 Kubernetes 團隊的開源精神和技術願景。
結論
這篇文章介紹了一些關於 HyperContainer 和 Hypernetes 專案的技術細節。我們希望人們會對這種新型安全容器及其與 Kubernetes 的整合感興趣。如果您想嘗試 Hypernetes 和 HyperContainer,我們剛剛宣佈了我們新的安全容器雲服務 (Hyper_) 的公開測試版,該服務就是基於這些技術構建的。但即使您在本地執行,我們也相信 Hypernetes 和 HyperContainer 將讓您以更安全的方式執行 Kubernetes。