做者 | 王旭 螞蟻金服資深技術專家linux
本文整理自《CNCF x Alibaba 雲原生技術公開課》第 28 講,點擊直達課程頁面。緩存
關注「阿里巴巴雲原生」公衆號,回覆關鍵詞**「入門」**,便可下載從零入門 K8s 系列文章 PPT。安全
Phil Karlton 有一句名言:「計算機科學界只有兩個真正的難題——緩存失效和命名。」網絡
對咱們容器圈而言,我相信「命名」絕對配得上這句話。這毫無疑問是一件讓老開發者沉默、讓新人落淚的事情。僅就係統軟件而言,咱們當今比較通行地稱爲**「Linux 容器技術」**這個概念,它曾經用過的名字還有 Jail, Zone, Virtual Server, Sandbox 等。一樣,在早期虛擬化的技術棧裏也把一類虛擬機叫作容器,畢竟這個詞自己就指代那些用來包容、封裝和隔離的器物。它實在太過常見了,以致於以嚴謹著稱的 Wikipedia,它的詞條叫作「OS-Level Virtualization」(系統級虛擬化) ,從而回避了「什麼是容器」這個問題。架構
在 2013 年,Docker 問世以後,容器這個概念伴隨着不可變基礎設施、雲原生這一系列概念在隨後的幾年間以摧枯拉朽之勢顛覆了基於「軟件包+配置」這種細粒度組合的應用部署,用簡單的聲明式策略和不可變的容器就清爽地定義了軟件棧。應用怎麼部署,在這兒彷佛有點離題了,我在這裏想要強調的是:框架
「雲原生語境下的容器,實質是「應用容器」——是以標準格式封裝的,運行於標準操做系統環境(經常是 Linux ABI)上的應用打包——或運行這一應用打包的程序/技術。」less
這個定義是我下的,但它並非個人我的意志,是基於 OCI 規範這一共識寫出來的。這個規範規定了容器之中應用被放到什麼樣的環境下、如何運行,好比說容器的根文件系統上哪一個可執行文件會被執行,是用什麼用戶執行,須要什麼樣的 CPU,有什麼樣的內存資源、外置存儲,還有什麼樣的共享需求等等。運維
因此說,標準格式的封裝、標準的操做系統環境在一塊兒以應用爲中心就構成了應用容器的打包。微服務
以這個共識爲基礎,就能夠來講說安全容器了。當年,我和個人聯合創始人趙鵬使用「虛擬化容器」這個名字來命名咱們的技術的,不過爲了博人眼球,咱們用了「Secure as VM, Fast as Container」這樣的 Slogan,因而,被容器安全性問題戳中心坎的人們馬上用「Secure Container」或者說「安全容器」來稱呼這種東西了,一發而不可收。雖然在咱們的心裏裏,這個技術是一層額外的隔離,它只是安全中的一環,可是呢,用戶仍是願意用安全容器這個名字來稱呼它。咱們給安全容器下的定義就是:性能
安全容器是一種運行時技術,爲容器應用提供一個完整的操做系統執行環境(經常是 Linux ABI),但將應用的執行與宿主機操做系統隔離開,避免應用直接訪問主機資源,從而能夠在容器主機之間或容器之間提供額外的保護。
這就是咱們的安全容器。
說安全容器的時候,就要提到「間接層」這個詞。它出自於 Linus Torvalds 在 2015 年的 LinuxCon 上提出的:
「安全問題的惟一正解在於容許那些(致使安全問題的)Bug 發生,但經過額外的隔離層來阻擋住它們。」
爲了安全,爲何要引入隔離層呢?其實 Linux 自己這樣的規模是很是大的,沒法從理論上來驗證程序是沒有 Bug 的,因而,一旦合適的 Bug 被利用,安全性風險就變成安全性問題了。安全性的框架和修補並不能確保安全,因此咱們須要進行一些額外的隔離來減小漏洞以及由於這些漏洞形成的被完全攻破的風險。
這就是安全容器的由來。
2017 年 12 月,咱們在 KubeCon 上對外發布了 Kata Containers 的安全容器項目,這個項目有兩個前身:由咱們以前開始的 runV 以及 Intel 的 Clear Container 項目。這兩個項目都是 2015 年 5 月開始開展的,其實是早於 Linus 在 KubeCon 2015 說的那番話的。
它們的思路都很簡單:
如今的問題是虛機不太夠快,阻礙了它在容器環境中的應用,若是能擁有「speed of container」的話,那咱們就可能能夠有一個用虛擬機來作隔離的安全容器技術了。這個也就是 Kata Containers 自己的一個思路,就是用虛擬機來作 Kubernetes 的 PodSandbox。在 Kata 裏面被拿來作 VM 的前後有 qemu, firecracker, ACRN, cloud-hypervisor 等。
下圖就是 Kata Containers 怎麼去和 Kubernetes 集成的,這裏的例子用的是 containerd,固然 CRI-O 也是同樣的。
目前,Kata Containers 一般是在 Kubernetes 中使用。首先 Kubelet 經過 CRI 接口找到 containerd 或者 CRI-O,這個時候好比鏡像這樣的操做通常也是由 containerd 或者 CRI-O 來執行的。根據請求,它會把 runtime 部分的需求變成一個 OCI spec,並交給 OCI runtime 執行。好比說上圖上半部分中的 kata-runtime,或者說下半部分精簡事後的 containerd-shim-kata-v2。具體的過程是這樣的:
能夠看到,在咱們的 PodSandbox 裏面,實際上只有一個 Guest Kernel 跑着一些容器自己的打包和容器應用,並不包含一個完整的操做系統。就是說,這個過程,它用起來並不像是傳統的虛擬機,對於容器來講,它只有容器的引擎,而且經過少用沒必要要的內存、共享能共享的內存來進一步地下降內存的開銷。
與傳統的虛擬機比起來,開銷更小、啓動更輕快,對於大部分的場景來講,它能夠作到「secure as VM」、「fast as container」。同時,在安全性技術之外,相比傳統的虛機,它有更多的彈性,更少了機器的那種物理操做的手感,好比說這裏面說過的包括動態資源的插拔以及使用 virtio-fs 這樣的技術等。它是一個專門爲咱們這種場景、爲像 kata 這樣的場景來作的一個把 host 的基本文件系統的內容(好比說容器的 rootfs )共享給虛擬機的這樣一個技術。
經過其中一些以前爲非易失存儲、非易失內存來作的 DAX 的技術,可以在不一樣的 PodSandbox 之間,也就是不一樣的 Pod 之間、不一樣的容器之間,共享一些能夠共享的只讀的內存部分。這樣能夠在不一樣的 PodSandbox 之間去節省不少的內存。同時全部的 Pod 的管理都是經過 Kubernetes 從外部進行的容器管理,而且從外部來獲取 metrics 和 debug 信息,並無登錄虛擬機這樣一種手感。因此它看起來是一種很是容器化的操做,雖然從底層來看,它仍是一個虛擬機,可是實際上它是一個面向雲原生的虛擬化。
gVisor,咱們又把它叫作進程級的虛擬化,它是和 kata 不同的另一種方式。
在 2018 年的 5 月份,哥本哈根的 KubeCon 上,Google 開源了他們內部開發了 5 年的 gVisor 安全容器做爲對 kata containers 的迴應,代表了他們有一種不一樣的安全容器的解決方案。
若是說 Kata Containers 是經過對現有的隔離技術進行組合和改造來構建容器間的隔離層的話,那麼 gVisor 的設計顯然是更加簡潔的。
如上圖右側所示,它是一個用 Go 語言重寫的運行在用戶態的操做系統內核,這個內核的名字叫作 sentry,它並不依賴於虛擬化和虛擬機技術,相反,它是藉助一個它們內部叫作一個 Platform(平臺)的能力,讓宿主機的操做系統作一個操做,把應用全部的指望對操做系統的操做都轉交給 sentry 來進行,sentry 作處理以後會把其中的一部分交給操做系統來幫它完成,大部分則由本身來完成。
gVisor 是一個純粹的面向應用的隔離層,從一開始就不是一個徹底等同於虛擬機的東西,它就是用來在 Linux 上面跑一個 Linux 程序的。做爲一個隔離層,它的安全性依據在於:
Linux 大概有 300 多個 Syscall,實際上 sentry 最後向操做系統發起的調用只會集中在 60 多個 Syscall 上。這個是源於 gVisor 的開發者們對操做系統的安全作了一些研究,他們發現,大多數對操做系統的成功的攻擊都是來自於不經常使用的系統調用的。
這個很容易理解,由於不經常使用的系統調用,它的實現路徑通常都是比較老的路徑,也就是說這些部分的開發通常不是太積極,只有不多的開發者來維護,那些熱門路徑上的代碼要更安全一些,由於那些代碼被 review 的次數比較多。因此 gVisor 的設計就是讓應用對那些並不經常使用的 Syscall 的訪問根本就到不了操做系統層面,而只在 sentry 裏就把它處理掉。
從 sentry 訪問宿主機的,只使用那些被驗證過的、比較成熟、比較熱的路徑上的系統調用,這樣的話,安全性就會比原來看起來好不少。咱們如今 Syscall 是原來的 1/5,可是被攻擊的可能性是並不到 1/5 的。
在 Unix 系統裏面,大部分東西都是一些文件,因此 open 能夠作太多的事情了,大部分的攻擊都是經過 open 來進行的。gVisor 的開發者就單獨地把 open 放到了一個獨立的進程裏面去實現,這個進程叫作 Gofer。一個獨立的進程其實是更容器被 seccomp、被一些系統的限制、一些 "capbility drop" 來保護。Gofer 能夠作更少的事情,能夠用非 root 去執行,如此一來整個系統的安全性就被進一步地被提升了。
Go 語言自己是一個內存更安全的一個實現,所以整個 gVisor 就更不容易被攻擊,更不容易發生一些內存上的問題。固然,Go 語言在有些地方仍是不夠太系統級的,gVisor 的開發者也坦言,他們爲了作這件事情,也對 Go Runtime 作了不少調整,並把這些東西也反饋回給了 Go 語言的社區。
能夠說 gVisor 的架構很漂亮,有不少開發者跟我坦誠,他們其實很喜歡 gVisor 的架構,以爲這個更簡單、更純粹、更乾淨。固然了,雖然它的架構很漂亮,但從新實現一個內核這件事情也只有 Google 這樣的巨頭能作得出來,相似的可能還有微軟的 WSL 1。並且這個設計是比較超前的,它其實存在一些問題:
因此短期以內,gVisor 這樣的解決方案並不能成爲一個終極的解決方案,不過它能夠適應一些特定的場景,而且它也帶來一些啓示性。我以爲這個啓示性對將來的操做系統、CPU 指令集的發展均可能會有一些做用。並且我相信,在將來,無論是 kata 仍是 gVisor,都會有一個演進,咱們期待着最後會有一個公共的解決方案來統一地解決應用的執行問題。
安全容器的名字雖叫安全,可是它提供的是一個隔離性。它的做用是不止於安全的。
安全容器經過隔離層讓應用的問題——無論是來自於外部的惡意攻擊仍是說意外的錯誤,都不至於影響主機,也不會在不一樣的 Pod 之間相互影響,因此實際上,這個額外的隔離層,它所帶來的影響不僅是安全,還有其它的方面。它對於系統的調度、服務質量,還有應用信息的保護都是有好處的。
咱們說傳統的操做系統容器技術是內核進程管理的一個延伸,容器進程自己是一組相關聯的進程,對於宿主機的調度系統來講,它是徹底可見的,一個 Pod 裏的全部容器或進程,同時也都被宿主機調度和管理。這就意味着,若是你有一個大量容器的環境,宿主機自己內核的負擔就會很重,在不少實際環境中已經能夠觀察到這個負擔帶來的開銷了。
尤爲是如今計算機技術的不斷髮展,一個操做系統會有大量的內存,大量的 CPU,幾百 G 的內存都是能夠見到的。在這個狀況下,若是分配的容器數量不少,調度系統就會有很是沉重的開銷。在採納安全容器以後,在宿主機上就看不到這些完整的信息了,這個隔離層同時承擔了一些對隔離層上面應用的調度,因而在主機上面就只須要調度這些沙箱自己,下降了宿主機的調度開銷,這也就是它爲何會提升調度效率的緣由。
提升調度效率的同時,它會把全部的應用彼此隔離起來,這樣就避免了容器之間、容器和主機之間的干擾,提升了服務質量。從另一個方向來看,咱們作安全容器的初衷是爲了保護宿主機不受到容器內惡意或者有問題的應用的影響,反過來,做爲一個雲來講,咱們有可能會面對有惡意的攻擊,因此也是保護咱們本身。
同時用戶也不肯意讓咱們過多地去訪問用戶的資源,用戶須要使用資源,但它並不須要咱們看到它的數據。安全容器能夠把用戶運行的東西徹底封裝在容器裏,這樣的話可讓主機的運維管理操做並不能訪問到應用的數據,從而把應用的數據保護在沙箱裏,不須要去碰到用戶數據。若是咱們要訪問用戶數據,做爲一個雲的話,那就必須得讓用戶給你受權,這個時候,用戶不肯定你是否是有什麼惡意的操做,若是咱們的沙箱封裝得很好的話,那也就不須要額外的對用戶受權的要求,這對於保護用戶的私密性是更好的。
當咱們把目光看向將來的時候,能夠看到,安全容器不只僅是在作安全隔離,安全容器隔離層的內核相對於宿主機的內核是獨立的,專門對應用服務,從這個角度來講,主機和應用的功能之間其實是一個合理的功能分配與優化。它能夠展示出不少的潛力,將來的安全容器,可能不只僅是隔離性能開銷的下降,同時也是在提升應用的性能。隔離技術會讓雲原生基礎設施更加完美。
本文的主要內容就到此爲止了,這裏爲你們簡單總結一下:
「阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」