天天看點

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

< SOFA:Channel/ >,有趣實用的分布式架構頻道。

回顧視訊以及 PPT 檢視位址見文末。歡迎加入直播互動釘釘群 : 30315793,不錯過每場直播。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

本文根據 SOFAChannel#16 直播分享整理,主題:不得不說的雲原生隔離性。

大家好,我是今天的講師巴德,來自螞蟻金服,主要從事 Kata 容器相關的開發,也是 Kata Containers 項目的維護者之一。今天我和大家分享一下雲原生場景下容器隔離性的需求以及我們如何運用 Kata Containers 來提升容器的隔離性。

從 Kubernetes Pod 說起

在講雲原生隔離性之前,我們先來回顧一下曆史。這張圖是生産環境應用部署形态的變遷過程。從最左邊的實體機上直接部署,到後來的虛拟化興起,大家把應用部署在虛拟機裡,再到 Docker 興起,大家都把應用部署到容器裡面,到現在 Kubernetes 成為主流,大家都把應用部署在 Pod 裡面。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

我們看一下 Kubernetes 的一個基本架構,它本身是一個容器的編排系統,主要角色是管理和排程 Pod 以及相關的資源。今天我們主要關注的就是在節點上部署的 Pod,這也是 Kubernetes 資源排程的基本機關。

Kubernetes 官方對 Pod 的定義是一個應用的邏輯主機,其中包含了一個或者多個應用容器,這些容器在資源上是相對緊密的耦合在一起的。Pod 包含了這些容器共享的網絡和存儲以及如何運作這些容器的聲明。Pod 中的内容總是放置在一起并且一同排程,并在共享的上下文中運作。

這段定義有些抽象,其目的是為了說明 Pod 是可以用不同的隔離技術來實作的。我們先來看一下一個經典的 Pod 實作,基于 Linux namespace 和 cgroups 做抽象的 Pod 實作。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

這個示意圖中,我們在一台主機上運作了兩個 Pod,這兩個 Pod 之間通過主機核心提供的 namespace 和 cgroups 能力來進行隔離。他們之間的所有 namespace 資源都是隔離的。然後在 pod 内部,不同容器之間的 IPC 和網絡 namespace 是共享的,但是他們的 mnt/pid/user/uts namespace 又是互相隔離的。這就是一個經典的基于 Linux namespace 和 cgroups 來做隔離的 Pod 的實作。

對于這種 Pod 的實作,我們可以關注到這兩個 Pod 雖然所有的 namespace 都是隔離的,但是他們共享了同一個核心。

共享核心引入的問題

那麼,我們來看一下 Pod 共享同一個核心可能造成什麼問題。

首先我們關注到的是安全問題。也就是說 Pod 中的容器應用會不會通過共享核心的漏洞逃逸出 Pod 的資源隔離?這裡我們列了兩個近幾年的核心 bug,一個是 CVE-2016-5915,另外一個是 CVE-2017-5123,這兩個 bug 都曾經造成容器應用通過觸發核心 bug 擷取主控端 root 權限并逃逸出 Pod 資源隔離限制。

另外一個點是故障影響。這個好了解,如果一個 Pod 中的容器應用觸發了一個嚴重的核心 bug,造成核心 panic,這時候同一台主控端上的所有 Pod 都會被牽連。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

還有一個我們非常關注的點,是共享核心造成的核心資源競争。同一個主控端上的不同 Pod,實際上是不同的使用者态程序的集合,這些使用者态程序雖然在 namespace 上是互相隔離的,但他們還是會共享很多核心資源,比如排程器、某些核心線程或者對象。這種級别的資源共享會引入很多可以觀測到的性能抖動,對線上業務的影響也很明顯。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

如何避免共享核心造成的這些問題呢?大家最直接的想法就是,把 Kubernetes 裝到虛拟機裡不就可以更好的隔離起來了嗎?如圖所示,這本質上是通過增加一個 VM 間接層來解決隔離性問題。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

看起來問題解決了,不是嗎?這時候我們就需要抛出計算機屆大佬 David Wheeler 的一個名言,“計算機科學中的所有問題都可以通過增加一個間接層來解決,當然,除了間接層過多的問題”。

那麼增加 VM 間接層的方案有什麼問題呢?第一,同一個 VM 内的 Pod 之間還是共享核心的。第二,整個叢集裡出現了虛拟機和 Pod 兩層排程系統。

上帝說,要有光;我們說,要有 Kata

面對這些問題,我們要怎麼做呢?我們要部署 Kata 容器 :)

Kata 容器的一個基本思路是,用虛拟機來作為 Pod 的一種隔離方式。我們把Pod中的多個容器資源,放到同一個虛拟機裡面,利用虛拟機來實作不同 Pod 獨占核心的目的。而 Pod 仍然是 Kubernetes 的基本排程機關,叢集裡也不會有虛拟機和 Pod 兩層排程系統。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

我們簡單介紹一下 Kata Containers 這個項目,這是 Openstack 基金會管理下的開放基礎設施頂級項目。Kata Containers 的 slogen 是 The speed of containers, the security of VMs。其設計是基于虛拟機完美符合 Pod 抽象這個理念,為使用者提供強隔離,易用的容器基礎設施。

Kata Containers:

https://github.com/kata-containers/kata-containers

這是 Kata Containers 項目的發展曆史概要。在 2015 年的五月,一幫國内的創業者(就是我們) 和 Intel 的同學們分别獨立釋出了兩個叫 runV 和 Clear Containers 的虛拟化容器項目,這就是 Kata Containers 的前身。這兩個項目互相有很多交流,在分别獨立發展了兩年半之後,在 2017 年底,合并成了 Kata Containers 項目,并把這個項目捐給 Openstack 基金會管理,這也是 Openstack 基金會的第一個 Pilot 項目,有一些探索轉型的味道。在去年的四月,Kata Containers 被 Openstack 基金會認可為其第二個頂級項目,在這之前的十多年裡,Openstack 基金會都隻有 Openstack 一個頂級項目。

目前 Kata Containers 的穩定版本釋出到了 1.10.0,而且 2.0 也正在緊鑼密鼓地開發中。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

我們再簡單介紹下 Kata Containers 的架構。左邊藍色部分是 Kata Containers 對接的上遊元件,也就是 Kubernetes 通過 CRI 接口通路 CRI daemon,這裡是用 containerd 做展示。 Containerd 通過一個 Shim API  來通路 Kata Containers。右邊的就都是 Kata 的元件了。對每一個 Pod,我們有一個名叫 containerd-shim-kata-v2 的服務程序,這個服務程序會負責基于虛拟機的 Pod 的生命周期管理。最後邊的 Pod Sandbox 就是我們基于虛拟機來實作的一個 Pod 抽象。在裡面我們要運作一個叫 kata-agent 的服務程序,來負責 Pod 内容器的生命周期管理。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

Kata 容器特性大放送

介紹了 Kata 的架構,我們來看一下 Kata 容器有哪些特性。作為一個中立項目,Kata 容器支援了多種體系結構,有 x86、arm、powerpc、s390x 等。Kata 也支援多種運作管理虛拟機的 hypervisor,包括 Qemu、Firecracker、Cloud-hypervisor、ACRN 等。在網絡聯通方面,Kata 支援多種網絡模型。管控平面上,Kata 也支援多個管控通道,包括 Docker、containerd、CRI-O、podman 等。

為了做到 the speed of containers, Kata 的一個重要特點就是面向雲原生的虛拟化。我們接下來重點介紹一下這個方面。

首先就是通過 DAX 和 模拟 nvdimm 裝置,讓同一台主控端上的不同 Pod 之間隻讀共享了同一份 guest 鏡像。這樣 guest 鏡像的記憶體開銷被降到最低。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

其次我們擴充了 QEMU 的本地遷移能力,通過隻讀共享同一份 guest 初始記憶體,實作了一個叫 VM template 的功能。通過 VM tempalte,我們在不破壞虛拟機獨占核心的隔離性的前提下,實作了同一台主控端上的所有 Pod 隻讀共享同一份 guest 核心以及 kata-agent 運作時記憶體。這一方面極大降低了 Kata Containers 由于引入虛拟化造成的記憶體額外開銷,也讓極速啟動新的容器成為可能。我們的測試顯示 VM template 能夠讓我們在 500ms 以内啟動一個 Kata 容器,這個速度完全可以和基于 Linux namespace 的經典容器媲美。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

在我們釋出了 Kata Containers 之後,Redhat 的同學為 Kata 容器特别設計了一個叫做 virtiofs 的 virtio 裝置類型。通過 virtiofs,Kata Containers 能夠更安全、快速、相容地通路主控端上的檔案資源。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

同時,Intel 是一個虛拟化大廠,他們為 Kata Containers 提供了一個面向雲原生的輕量化 VMM,Cloud-hypervisor。這是一個用 Rust 語言重寫的 VMM,基于了開源項目 rust-vmm。而 rust-vmm 也是 Google chromium 的 crosvm 和 AWS Fargete 的 Firecracker 共享的基礎庫。相較于面向桌面的 crosvm 和面向函數計算的 Firecracker,Cloud-hypervisor 更專注于容器場景,是一個為容器而生的輕量化 VMM。

雲原生的 Kata 容器

介紹了 Kata 容器的主要特性,我們再來看一下 Kata 容器是如何融入到 Kubernetes 生态的。

首先,我們的第一屆架構委員會成員,Google 的 Tim Allclair 同學在 Kubernetes 中引入了 runtimeclass 特性。這個特性允許使用者定義 runtimeclass 資源,用來定義 Pod 可以使用的運作時抽象,比如 runc 或者 Kata。然後使用者可以在 Pod spec 裡顯示指定一個 Pod 應該用哪個 runtimeclass 來運作。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

在 runtimeclass 之後,Kubernetes 社群又引入了 Runtime Class 排程,讓節點暴露自己支援的 runtimeclass,進而讓排程器在排程中同時考量 Pod spec runtimeclass 要求和節點的支援能力。

不得不說的雲原生隔離性 | SOFAChannel#16 直播回顧

在這之後,Kata Containers 的另一位架構委員會成員 Eric,又給 Kubernetes 引入了一個叫 PodOverhead 的特性。無論是用 Linux namespace 還是虛拟機來做為 Pod 的實作,我們都不可避免地需要一些額外的資源開銷。在 PodOverhead 特性之前,這部分開銷一直是被遺忘了的,這也造成了 Kubernetes 排程器在做排程決策的時候,實際上并沒有掌握準确的資源資訊。而 PodOverhead 允許使用者在 runtimeclass 資源上,附加一個 Pod 自身開銷的聲明。這樣排程器在排程的時候會算上這部分開銷,并在配置設定 Pod 資源的時候把這些開銷配置設定給 Pod,同時在決策是否淘汰 Pod 的時候也考慮上這些開銷。可見這是一個讓 Kubernetes 排程器作出更好的排程政策的特性。

回顧一下

今天我們介紹了 Kubernetes Pod 的概念和實作,讨論了經典場景下 Pod 抽象共享核心造成的問題,然後我們介紹了 Kata Containers 的架構和特性,以及 Kubernetes 為更好地支援 Kata Containers 引入的特性。

以上就是本期分享的所有内容。下面是一些 Kata Containers 的相關資源連結,歡迎了解試用 Kata,也歡迎大家通過任何一種方式和 Kata 社群建立連接配接。謝謝!

本期視訊回顧以及 PPT 檢視位址

https://tech.antfin.com/community/live/1197

繼續閱讀