「網紅」 WebAssembly 與 K8s 如何實現雙劍合璧?

1.png

做者 | 易立  阿里巴巴資深技術專家前端

導讀:WebAssembly 技術已經走出瀏覽器,讓計算無處不在。本文利用 containerd 的擴展機制,能夠爲 WebAssembly 應用提供與其餘容器應用一致的、抽象的、應用分發、交付和運維模型,能夠在 Kubernetes 集羣中進行統一調度和管理。node

無處不在的 WebAssembly

若是評選 2019 年編程技術的「網紅」,不管是前端圈仍是後端圈,WebAssembly (WASM) 都絕對可以高票入選。然而,若是評選最被「低估」的技術,我以爲 WebAssembly 也能夠輕鬆入圍。linux

借用伏爾泰曾評價神聖羅馬帝國的句式 「既不神聖,也不羅馬,更非帝國」,咱們也能夠說WebAssembly 「既不限於 Web,更不是 Assembly(彙編語言)」。nginx

在 2019 年 12 月,萬維網聯盟 (World Wide Web Consortium  - W3C) 宣佈 WebAssembly 核心規範正式成爲 Web 標準,  這使得 WebAssembly 成爲互聯網上與 HTML, CSS, and JavaScript 並列的第四種官方語言,能夠原生的運行在瀏覽器上。而更加劇要的是,WebAssembly 做爲一個安全的、可移植、高效率的虛擬機沙箱,能夠在 Internet 的任何地方、任何平臺(不一樣操做系統,不一樣 CPU 體系架構下)安全運行應用。WebAssembly 已獲得了全部主流瀏覽器廠商的普遍支持(Google Chrome, Microsoft Edge, Apple Safari, Mozilla Firefox 等),然而它的影響已經遠超 Web。git

WebAssembly 的設計初衷之一是爲了解決 JavaScript 的性能問題,使得 Web 網頁應用有接近本機原生應用的性能。做爲一個通用、開放、高效的底層虛擬機抽象,衆多編程語言(如 C/C++, Rust 等)能夠將現有應用編譯成爲 WASM 的目標代碼,運行在瀏覽器中 。這讓應用開發技術與運行時技術解耦,極大促進了代碼複用。github

Mozilla 在 2019 年 3 月推出了 WebAssembly System Interface(WASI),來標準化 WebAssembly 應用與系統資源的交互抽象,好比文件系統訪問,內存管理,網絡鏈接等,相似 POSIX 這樣的標準 API。WASI 規範大大拓展了 WASM 應用的場景,可讓其能夠超越瀏覽器環境,做爲一個獨立的虛擬機運行各類類型的應用。同時,平臺開發商能夠針對具體的操做系統和運行環境提供 WASI 接口不一樣的實現,能夠在不一樣設備和操做系統上運行跨平臺的 WebAssembly 應用。這可讓應用執行與具體平臺環境實現解耦。這一切使得「Build Once, Run Anywhere」的理想逐漸造成現實。WASI 的示意圖以下所示。2019 年 11 月,爲了進一步推進模塊化 WebAssembly 生態系統,Mozilla、Fastly、英特爾和紅帽公司攜手成立了字節碼聯盟(Bytecode Alliance),共同領導 WASI 標準、 WebAssembly 運行時、語言工具等工做。web

2.png

圖片來源:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/docker

WASM 與容器相愛相殺

WebAssembly 是否會取代容器?

正由於 WebAssembly 所具有的的安全、可移植、高效率,輕量化的特色,很是適於應用安全沙箱場景。WASM 獲得了容器、函數計算、IoT / 邊緣計算等社區的普遍關注。Docker 創始人 Solomon Hykes 在 WASI 發佈之際的一句 Twitter,更是成爲了去年容器和 WebAssembly 社區引用頻率最高的一句話之一。編程

3.png

Fastly, Cloudflare 等 CDN 廠商基於 WebAssembly 技術實現了更加輕量化的應用安全沙箱,能夠在一個進程內部運行多個獨立的用戶應用。阿里雲 CDN 團隊 EdgeRoutine 也實現了相似技術。與容器技術相比,WASM 能夠實現毫秒級冷啓動時間和極低的資源消耗。json

4.png

原圖:https://blog.cloudflare.com/cloud-computing-without-containers/

固然,世界上沒有完美的技術。任何沙箱技術不可能同時知足執行效率、安全隔離性和通用性這三個維度的要求。WASM 在安全隔離和通用性等方面與 Docker Container 等存在差距。雖然如此,咱們仍是看到了 WebAssembly 技術巨大的潛力。

WebAssembly 容器

個人理解是 WebAssmebly 能夠成爲一種容器類型,相似 Linux Container 或者 Windows Container 同樣。成爲一個跨平臺的標準應用分發方式和運行時環境。

應用分發

Docker 容器的一個重要貢獻是其標準化了容器化應用打包規範 Docker Image,並且它已經成爲開放容器計劃 (Open Container Initiative - OCI) 的鏡像格式標準。Docker 鏡像提供了自包含、自描述的鏡像格式。它能夠將應用以及其依賴的環境信息打包在一塊兒,從而實現應用與運行環境解耦,讓容器應用能夠輕鬆運行在從本地開發環境到雲端生產環境的不一樣場景中。而且社區圍繞 Docker 鏡像構建了繁榮的工具鏈生態,如 Docker Hub 能夠進行應用分發和 CI / CD 協同,Nortary / TUF 項目能夠保障應用可信地分發、交付。

對與 WebAssembly,目前社區提供了相似 NPM 的包管理實現 WAPM,能夠較好地支持應用的分發。 爲 WebAssembly 應用構建 Docker 鏡像,能夠實現共贏的局面。

  • WebAssembly 開發者能夠徹底複用 Docker/OCI 鏡像規範和工具鏈,進一步簡化應用分發和交付。好比,咱們能夠將 Nginx 的 WASM 鏡像做爲基礎鏡像,基於這個鏡像能夠構建包含不一樣 Web 內容的應用鏡像;咱們能夠利用 tag 對應用版本進行追蹤;利用 Docker Registry 進行應用分發;在這個過程咱們還能夠進一步利用數字簽名來保障安全的軟件供應鏈;
  • Docker 鏡像規範支持 Multi-Arch 鏡像,能夠簡化不一樣 CPU 體系架構(如 x86, ARM, RISC-V 等)的應用鏡像的構建與分發。而 WebAssembly 天生具有可移植性,大大簡化了跨平臺 Docker 應用鏡像的構建和分發。參考:利用 Docker 加速 ARM 容器應用開發和測試流程

我提供了一個技術原型示例項目,你們能夠參考其中的例子來構建 WASM 容器鏡像。因爲 WebAssembly 應用採用緊湊的二進制格式,並且沒有任何操做系統依賴,WASM 應用能夠構建出很是小的容器鏡像。你們能夠自行感覺一下:

$ sudo ctr image ls
REF                                                           TYPE                                                 DIGEST                                                                  SIZE      PLATFORMS   LABELS
docker.io/denverdino/c-http-server-wasm:latest                application/vnd.docker.distribution.manifest.v2+json sha256:2efa759f46f901cda2e6a9b4228c423b17a960c06e957964e72c21dc5b42408f 29.2 KiB  linux/amd64 -
docker.io/denverdino/hellowasm:latest                         application/vnd.docker.distribution.manifest.v2+json sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132 8.2 KiB   linux/amd64 -
docker.io/denverdino/nginxwasm:latest                         application/vnd.docker.distribution.manifest.v2+json sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998 582.7 KiB linux/amd64 -

安全隔離

WebAssembly 的最初設計目標是讓應用能夠安全運行在瀏覽器中。WASM 虛擬機提供的沙箱和內存隔離機制,能夠有效減小安全攻擊面。而當 WebAssembly 走出瀏覽器,面向更加通用的場景。WASM 也面對更加複雜的安全挑戰。

WASI 提供了基於能力的安全模型。WASI 應用遵循最小權限原則,應用只能訪問其執行所需的確切資源。傳統上,若是應用須要打開文件,它會帶路徑名字符串調用系統操做 open。而後系統調用會檢查應用是否具備訪問該文件的相關權限,好比 Linux 實現了基於用戶/組的權限模型。這樣隱式的安全模型,依賴於正確的安全管理配置,好比一旦特權用戶執行了一個惡意應用,它就能夠訪問系統中任意的資源。而對於 WASI 應用而言,若是它須要須要訪問指定文件等系統資源,須要從外部顯式傳入加有權限的文件描述符引用,而不能訪問任何其餘未受權資源。這中依賴注入的方式能夠避免傳統安全模型的潛在風險。

一個示意圖以下:

5.png

原圖:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/

咱們能夠看到 WASI 的安全模型與傳統操做系統安全模型很是不一樣,並且還在持續演進中。好比字節碼聯盟提出了 nanoprocess 來解決應用模塊間的安全協同和信任傳遞。

WebAssembly/WASI 的安全模型依然存在不足,好比:

  • 資源隔離

對於內存資源,WebAssembly 實現了線性內存模型。WebAssembly 應用只能利用索引訪問傳入的一段邏輯線性內存。而 WASM 虛擬機負責肯定內存的實際物理地址,WASM 應用沒法獲知內存的真實地址,也沒法經過越界訪問等方式發動攻擊。因此理論上,能夠對 WASM 應用進行資源容量限制。可是目前部分 WASM 虛擬機還沒法對內存進行精確的隔離限制。

對於 CPU 資源,部分的 WASM 虛擬機實現能夠對應用使用的 CPU 資源進行計量,可是大多沒法實現精確的配額限制、優先級和搶佔式調度。

I/O 資源,好比 IOPS 等,WASM 目前徹底沒有相關的隔離能力。

  • 網絡安全

WASI 的 Capability 模型對於文件系統訪問相對比較容易保護。可是這個靜態的安全模型沒法適用於動態的網絡應用場景。在微服務架構中,應用常常經過 Service Registry 進行服務發現,爲服務的調用者和提供者實現動態的調用綁定。這個語義是沒法用靜態的 capability 模型描述和注入的。這也致使了 WASI 的網絡部分 API 還處於討論之中。現有的 WASI 網絡安全模型,以及相關討論

Linux 操做系統和容器技術已經提供了很是完備的資源隔離和安全隔離實現。與 WebAssembly 結合在一塊兒能夠應對不一樣場景對不一樣隔離級別的需求。

  • 共享進程資源 - 多個 WASM 應用模塊運行在一個 WASM 虛擬機進程內部,依賴 WASM 運行時進行隔離。隔離級別低,控制粒度比較粗,資源開銷極小。能夠以較小代價保障系統安全。適合受限問題域的應用安全隔離;

  • 獨立進程資源 - 不一樣 WASM 應用模塊運行在不一樣的 WASM 虛擬機進程中,能夠複用操做系統的進程級隔離能力,好比 CGroup。此外,還能夠利用相似 Kubernetes 中的 Network Policy (網絡策略),或者服務網格(如Istio)等技術,對進程的網絡訪問進行細粒度的控制,甚至實現零信任網絡。隔離級別比較高,控制粒度比較細,資源開銷適中。能夠應用於更加通用的場景。

注:固然利用安全沙箱如虛擬化等技術,結合 WebAssembly,能夠進一步最小化安全攻擊面,可是 ROI 不高。

調度與編排

在雲時代,Kubernetes 已經成爲分佈式環境下資源調度和應用編排的事實標準。Kubernetes 能夠屏蔽底層設施的差別性。能夠在同一個 K8s 集羣中包含 x8六、ARM 等不一樣體系架構的節點,能夠支持 Linux,Windows 等不一樣的操做系統。Kubernetes 和 WebAssembly 相結合能夠進一步提高應用的可移植性。

微軟的 Deis Labs 年初發布了一個實驗項目,來利用 Virtual Kubelet 相似的架構調度 WebAssembly 應用。可是這個方式有不少侷限,沒法藉助容器方式進行應用分發,也沒法利用 K8s 的語義進行資源編排。 

可貴有一個春節假期能夠宅在家裏,在此期間我基於 Derek McGowan 去年的一個實驗性項目,完善了 containerd 的 WASM shim 實現。可讓 containerd 支持 WASM container,而且能夠利用 Kubernetes 集羣管理和調度 WASM container。

項目的代碼實現: https://github.com/denverdino/containerd-wasm

注:這個項目更可能是概念驗證,進程管理、資源限制,性能優化等的細節並沒未完整實現。

整個系統的架構設計以下,「container-shim-wasm-v1」做爲 Containerd 的擴展,利用 wasmer 做爲 WASM 應用運行時環境,能夠實現與 runc 容器一致的用戶體驗。

6.png

咱們還會將其註冊爲 K8s 的一個 RuntimeClass ,容許用戶利用 K8s 來交付和運維 WASM 應用。

注:RuntimeClass 是 Kubernetes v1.12 引入的新概念,可讓 Kubernetes 支持多種不一樣的容器運行時,好比 runc 容器、或者 Kata Containers,gVisor 等安全沙箱容器。更多細節能夠參考:containerd 與安全沙箱的 Kubernetes 初體驗

Talk is Cheap, 放碼過來

首先,咱們將利用 Minikube 建立一個 K8s 測試環境,並將 Containerd 做爲 Kubernetes 集羣的容器運行時。

建立虛擬機測試環境

建立 Minikube K8s 集羣,並將 Containerd 做爲 Kubernetes 集羣容器運行時。

minikube start --image-mirror-country cn \
    --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.6.0.iso \
    --registry-mirror=https://tgtsuwdg.mirror.aliyuncs.com \
    --container-runtime=containerd

進入 Minikube 虛擬機:

$ minikube ssh
                         _             _
            _         _ ( )           ( )
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

配置環境所需依賴:

  • wasmer 0.13;
  • minikube 缺省安裝了 container 1.2.x,須要升級 containerd 1.3.x;
  • 我提供了一個預編譯的 containerd-wasm-shim-v1,也可本身編譯一個版本。
cd ~
# Install Wasmer 0.13.1
curl -L -O https://github.com/wasmerio/wasmer/releases/download/0.13.1/wasmer-linux-amd64.tar.gz
gunzip wasmer-linux-amd64.tar.gz
tar xvf wasmer-linux-amd64.tar
sudo cp bin/* /usr/bin/
# Upgrade containerd to v1.3.2
curl -L -O https://github.com/containerd/containerd/releases/download/v1.3.2/containerd-1.3.2.linux-amd64.tar.gz
gunzip containerd-1.3.2.linux-amd64.tar.gz
tar xvf containerd-1.3.2.linux-amd64.tar
sudo systemctl stop containerd
sudo cp bin/* /usr/bin/
sudo systemctl restart containerd
# Install containerd-wasm-shim
wget http://kubernetes.oss-cn-hangzhou.aliyuncs.com/containerd-wasm/containerd-shim-wasm-v1
chmod +x containerd-shim-wasm-v1
sudo mv containerd-shim-wasm-v1 /usr/bin/

配置 containerd 支持 WASM shim

在 containerd 配置文件中添加 wasm shim 相關配置,並重啓 containerd。

$ cat <<EOF | sudo tee -a /etc/containerd/config.toml
disabled_plugins = ["restart"]
[plugins.cri.containerd.runtimes.wasm]
  runtime_type = "io.containerd.wasm.v1"
EOF
$ sudo systemctl restart containerd

測試 Hello World WASM 容器應用:

$ sudo ctr image pull docker.io/denverdino/hellowasm:latest
docker.io/denverdino/hellowasm:latest:                                            resolved       |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132: done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:ecda28441283ecf01d35bca0361f2c1ef26a203454a06789ee5ce71ba1e32ca3:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:57974480d640c8d60d254a8b0fa4606b2c7107fe169bc3ddd455091277c3a5e4:   done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 3.0 s                                                                    total:   0.0 B (0.0 B/s)
unpacking linux/amd64 sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132...
done
$ sudo ctr run --rm --runtime io.containerd.wasm.v1 docker.io/denverdino/hellowasm:latest test1
Hello world

測試 Nginx 的 WASM 容器應用:

$ sudo ctr image pull docker.io/denverdino/nginxwasm:latest
docker.io/denverdino/nginxwasm:latest:                                            resolved       |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998: exists         |++++++++++++++++++++++++++++++++++++++|
layer-sha256:27f4d8ad067fbb709d18ea5acd7a5ddfb85851e5d9f030636e9da3d16cc4bd07:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:a55bd3bdb9d00fdac5ee2f64bfc1856e58e8bb90587943969ad3d8115f4ced70:   done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 3.0 s                                                                    total:   0.0 B (0.0 B/s)
unpacking linux/amd64 sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998...
done
$ sudo ctr run --rm --runtime io.containerd.wasm.v1 docker.io/denverdino/nginxwasm:latest test2
2020/02/01 07:01:21 [notice] 30672#0: using the "select" event method
2020/02/01 07:01:21 [notice] 30672#0: nginx/1.15.3
2020/02/01 07:01:21 [notice] 30672#0: built by clang 6.0.1  (emscripten 1.38.11 : 1.38.11)
2020/02/01 07:01:21 [notice] 30672#0: OS: Linux 4.19.81
2020/02/01 07:01:21 [notice] 30672#0: getrlimit(RLIMIT_NOFILE): 1024:1024

在 Minikube 外部,能夠用以下方式得到 nginx 應用的訪問地址:

$ echo http://$(minikube ip):8080
http://192.168.64.13:8080

利用瀏覽器打開上述地址,顯示以下:

7.png

建立 WASM 容器的 RuntimeClass CRD

爲了 WASM 容器能夠被 Kubernetes 所調度,咱們須要建立一個 RuntimeClass CRD。

下載示例文件:

$ git clone https://github.com/denverdino/wasm-container-samples
$ cd wasm-container-samples

註冊 RuntimeClass 「wasm」這個值:

$ cat wasm-runtimeclass.yaml
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
  name: wasm
handler: wasm
$ kubectl apply -f wasm-runtimeclass.yaml
runtimeclass.node.k8s.io/wasm created
$ kubectl get runtimeclass
kubectl get runtimeclass
NAME   CREATED AT
wasm   2020-02-01T06:24:12Z

在 K8s 中運行 WASM 容器應用

在 K8s 應用的 yaml manifest 中,咱們能夠在 Pod Spec 上指明所需 runtimeClassName。下面咱們就用 K8s 來部署一個 nginx 的 WASM 容器。

$ cat nginx-wasm.yaml
apiVersion: v1
kind: Pod
metadata:
 name: nginx-wasm
spec:
 runtimeClassName: wasm
 containers:
 - name: nginx
   image: denverdino/nginxwasm
   ports:
     - containerPort: 8080
$ kubectl apply -f nginx-wasm.yaml
pod/nginx-wasm created
$ kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-wasm   1/1     Running   0          9s

新機遇、新但願

目前爲止,WebAssembly 技術仍處於初期階段,WASI 也有不少侷限性。可是社區的進展很是快,SIMD 指令支持,多線程處理等規範也正在快速演進中。WebAssembly 已經打破次元壁,將高性能的計算能力帶領到 Web 瀏覽器端,愈來愈多的計算密集型的遊戲、AI 模型預測、和數據處理應用被移植到瀏覽器端,能夠爲應用提供更加優化的用戶體驗。

WebAssembly 更廣闊的空間在雲計算領域、區塊鏈等分佈式計算領域。WebAssembly 輕量、敏捷、安全的特性,能夠有效下降 Serverless 應用啓動速度和資源消耗。同時 WebAssembly 的可移植,可讓應用一致運行在從雲端服務器到邊緣 IoT 設備等不一樣平臺環境中,讓計算無處不在。

利用 containerd 的擴展機制,能夠爲 WebAssembly 應用提供與其餘容器應用一致的、抽象的、應用分發、交付和運維模型,能夠在 Kubernetes 集羣中進行統一調度和管理。但願經過相似的探索能夠簡化基於 WebAssembly 的分佈式應用管理和運維。

關於做者

易立,阿里雲資深技術專家,阿里雲容器服務的研發負責人。以前曾在 IBM 中國開發中心工做,擔任資深技術專員;做爲架構師和主要開發人員負責或參與了一系列在雲計算、區塊鏈、Web 2.0,SOA 領域的產品研發和創新。阿里雲容器平臺團隊求賢若渴!社招技術專家 / 高級技術專家,base 杭州 / 北京 / 深圳。歡迎發簡歷到 jiaxu.ljx@alibaba-inc.com

8.png

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術圈。」

相關文章
相關標籤/搜索