gVisor 容器
它的原理,可以用如下所示的示意圖來表示清楚。

gVisor 工作的核心,在於它為應用進程(用戶容器),啟動了一個名叫 Sentry 的進程。 而 Sentry 進程的主要職責,就是提供一個傳統的操作系統內核的能力,即:運行用戶程序,執行系統調用。所以說,Sentry 並不是使用 Go 語言重新實現了一個完整的 Linux 內核,而只是一個對應用進程“冒充”內核的系統組件。
在這種設計思想下,Sentry 其實需要自己實現一個完整的 Linux 內核網絡棧,以便處理應用進程的通信請求。然后,把封裝好的二層幀直接發送給 Kubernetes 設置的 Pod 的 Network Namespace 即可。
而在具體的實現上,gVisor 的 Sentry 進程,其實還分為兩種不同的實現方式。這里的工作原理,可以用下面的示意圖來描述清楚。

Sentry 進程的第一種實現方式
使用 Ptrace 機制來攔截用戶應用的系統調用(System Call),然后把這些系統調用交給 Sentry 來進行處理。
這個過程,對於應用進程來說,是完全透明的。而 Sentry 接下來,則會扮演操作系統的角色,在用戶態執行用戶程序,然后僅在需要的時候,才向宿主機發起 Sentry 自己所需要執行的系統調用。這,就是 gVisor 對用戶應用進程進行強隔離的主要手段。不過, Ptrace 進行系統調用攔截的性能實在是太差,僅能供 Demo 時使用。
Sentry 進程的第二種實現方式
這種方式則更加具有普適性。它的工作原理如下圖所示。

在這種實現里,Sentry 會使用 KVM 來進行系統調用的攔截,這個性能比 Ptrace 就要好很多了。
當然,為了能夠做到這一點,Sentry 進程就必須扮演一個 Guest Kernel 的角色,負責執行用戶程序,發起系統調用。而這些系統調用被 KVM 攔截下來,還是繼續交給 Sentry 進行處理。只不過在這時候,Sentry 就切換成了一個普通的宿主機進程的角色,來向宿主機發起它所需要的系統調用。
可以看到,在這種實現里,Sentry 並不會真的像虛擬機那樣去虛擬出硬件設備、安裝 Guest 操作系統。它只是借助 KVM 進行系統調用的攔截,以及處理地址空間切換等細節
值得一提的是,在 Google 內部,他們也是使用的第二種基於 Hypervisor 的 gVisor 實現。只不過 Google 內部有自己研發的 Hypervisor,所以要比 KVM 實現的性能還要好。但到目前為止,gVisor 的實現依然不是非常完善。
Kata Containers 與 gVisor對比
在性能上,KataContainers 和 KVM 實現的 gVisor 不分伯仲,在啟動速度和占用資源上,基於用戶態內核的 gVisor 還略勝一籌。但是,對於系統調用密集的應用,比如重 I/O 或者重網絡的應用,gVisor 就會因為需要頻繁攔截系統調用而出現性能急劇下降的情況。此外,gVisor 由於要自己使用 Sentry 去模擬一個 Linux 內核,所以它能支持的系統調用是有限的,只是 Linux 系統調用的一個子集。
不過,gVisor 雖然現在沒有任何優勢,但是這種通過在用戶態運行一個操作系統內核,來為應用進程提供強隔離的思路,的確是未來安全容器進一步演化的一個非常有前途的方向。