本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Hypernetes:為 Kubernetes 帶來安全性和多租戶
雖然許多開發人員和安全專業人員都認可 Linux 容器作為有效的邊界,但許多使用者需要更強大的隔離程度,特別是對於那些在多租戶環境中運行的使用者。遺憾的是,如今,這些使用者被迫在虛擬機器內運行他們的容器,甚至是每個容器一個 VM。
不幸的是,這導致雲原生部署的許多優勢喪失:VM 的啟動時間緩慢;每個容器的記憶體負擔;低利用率導致資源浪費。
在這篇文章中,我們將介紹 HyperContainer,一種基於 Hypervisor 的容器,並了解它如何自然地融入 Kubernetes 設計,並使使用者能夠直接使用虛擬化容器為其客戶提供服務,而不是將它們包裹在功能完整的 VM 中。
HyperContainer
HyperContainer 是一種基於 Hypervisor 的容器,可讓您使用標準 Hypervisor(KVM、Xen 等)啟動 Docker 映像。作為一個開源專案,HyperContainer 由一個 OCI 相容的運行時實作(名為 runV)和一個名為 hyperd 的管理守護程式組成。HyperContainer 背後的想法非常簡單:結合虛擬化和容器兩者的優點。
我們可以將容器視為兩個部分(Kubernetes 也是這樣做的)。第一部分是容器運行時,HyperContainer 使用虛擬化來實現執行隔離和資源限制,而不是命名空間和 cgroup。第二部分是應用程式資料,HyperContainer 在其中利用 Docker 映像。因此,在 HyperContainer 中,虛擬化技術使得構建具有獨立客體核心的完全隔離沙箱成為可能(因此像 top
和 /proc 這樣的功能都可以正常運作),但從開發人員的角度來看,它是可移植的,並且行為類似於標準容器。
作為 Pod 的 HyperContainer
HyperContainer 有趣的部分不僅在於它對於多租戶環境(例如公有雲)來說足夠安全,還在於它與 Kubernetes 哲學的契合程度。
Pod 是 Kubernetes 中最重要的概念之一。Pod 的設計是從真實世界的工作負載中吸取的教訓(Borg 論文第 8.1 節),在許多情況下,人們希望有一個由多個容器組成的原子調度單元(請查看此 範例 以獲取更多資訊)。在 Linux 容器的上下文中,Pod 將多個容器包裝和封裝到一個邏輯組中。但在 HyperContainer 中,Hypervisor 充當自然邊界,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 容器技術堆疊。
另一方面,為了在多租戶環境中運行 HyperContainer,我們還建立了一個新的網路外掛程式,並修改了一個現有的磁碟區外掛程式。由於 Hypernetes 將 Pod 作為其自己的 VM 運行,因此它可以利用您現有的 IaaS 層技術來實現多租戶網路和持久性磁碟區。目前的 Hypernetes 實作使用標準 Openstack 组件。
下面我們將詳細介紹以上所有這些是如何實作的。
身分驗證和授權
在 Hypernetes 中,我們選擇 Keystone 來管理不同的租戶,並在任何管理操作期間執行租戶的身分驗證和授權。由於 Keystone 來自 OpenStack 生態系統,因此它可以與我們在 Hypernetes 中使用的網路和儲存外掛程式無縫協作。
多租戶網路模型
對於多租戶容器叢集,每個租戶都需要與其他租戶進行強大的網路隔離。在 Hypernetes 中,每個租戶都有自己的網路。使用 Hypernetes,您只需建立一個如下所示的 Network 物件,而無需使用 OpenStack 配置新網路(這很複雜)。
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 將自動建立一個新的 Neutron 網路,其中包含預設路由器和子網路 192.168.0.0/24。
網路控制器將負責使用者建立的任何 Network 實例的生命週期管理。此網路可以分配給一個或多個命名空間,並且屬於同一網路的任何 Pod 都可以透過 IP 位址直接相互訪問。
apiVersion: v1
kind: Namespace
metadata:
name: ns1
spec:
network: net1
如果命名空間沒有 Network 規範,它將改為使用預設 Kubernetes 網路模型,包括預設 kube-proxy。因此,如果使用者在具有關聯網路的命名空間中建立 Pod,Hypernetes 將遵循 Kubernetes 網路外掛程式模型 來為此 Pod 設定 Neutron 網路。以下是一個高階範例
{: HyperContainer 包裝了一個輕量級應用程式容器的 Pod。.big-img}
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 Service 能夠提供 OpenStack 負載平衡器,就像「外部」負載平衡器在 GCE 上所做的那樣。當使用者建立具有外部 IP 的 Service 時,將建立 OpenStack 負載平衡器,並且端點將透過上述 kubestack 工作流程自動更新。
持久性儲存
在考慮儲存時,我們實際上是在 Kubernetes 中建構一個租戶感知的持久性磁碟區。我們決定不使用 Kubernetes 現有的 Cinder 磁碟區外掛程式的原因是其模型在虛擬化案例中不起作用。具體來說
Cinder 磁碟區外掛程式需要 OpenStack 作為 Kubernetes 提供者。
OpenStack 提供者將找到目標 Pod 正在哪個 VM 上運行
Cinder 磁碟區外掛程式將 Cinder 磁碟區掛載到 Kubernetes 主機 VM 內的路徑。
kubelet 將此路徑作為磁碟區綁定掛載到目標 Pod 的容器中。
但在 Hypernetes 中,事情變得簡單得多。由於 Pod 的物理邊界,HyperContainer 可以像普通 VM 一樣將 Cinder 磁碟區直接作為塊設備掛載到 Pod 中。這種機制消除了在現有的 Cinder 磁碟區工作流程中查詢 Nova 以找出目標 Pod 的 VM 的額外時間(如上所列)。
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_) 的公開 Beta 版,該服務建立在這些技術之上。但即使您是在地端運行,我們也相信 Hypernetes 和 HyperContainer 將讓您以更安全的方式運行 Kubernetes。