WebAssembly 在雲原生中的實踐指南
1 WebAssembly 介紹
WebAssembly(Wasm)是一種通用字節碼技術,它可以將其他編程語言(如 Go、Rust、C/C++ 等)的程序代碼編譯爲可在瀏覽器環境直接執行的字節碼程序。
WebAssembly 的初衷之一是解決 JavaScript 的性能問題,讓 Web 應用程序能夠達到與本地原生應用程序類似的性能。作爲底層 VM 的通用、開放、高效的抽象,許多編程語言,例如 C、C++ 和 Rust,都可以將現有應用程序編譯成 Wasm 的目標代碼,以便它們在瀏覽器中運行。這將應用程序開發技術與運行時技術解耦,並大大提高了代碼的可重用性。
2019 年 3 月,Mozilla 推出了 WebAssembly 系統接口(Wasi),以標準化 WebAssembly 應用程序與系統資源之間的交互抽象,例如文件系統訪問、內存管理和網絡連接,該接口類似於 POSIX 等標準 API。Wasi 規範的出現極大地擴展了 WebAssembly 的應用場景,使得 Wasm 不僅限於在瀏覽器中運行,而且可以在服務器端得到應用。同時,平臺開發者可以針對特定的操作系統和運行環境提供 Wasi 接口的不同實現,允許跨平臺的 WebAssembly 應用程序運行在不同的設備和操作系統上。
2 WebAssembly 會取代容器嗎?
Docker 的創始人 Solomon Hykes 是這樣評價 WASI 的:
如果 WASM+WASI 在 2008 年就存在,我們就不需要創建 Docker 了。這就是它的重要性。服務器上的 WebAssembly 是計算的未來。
Solomon Hykes 後續還發布了一條推文,表示 WebAssembly 將與容器一起工作,而不是取代它們。WebAssembly 可以成爲一種容器類型,類似於 Linux 容器或 Windows 容器。它將成爲標準的跨平臺應用程序分發和運行時環境。
3 WebAssembly 的優勢
WebAssembly 相較於傳統的容器有着許多顯著的優勢:
- 體積更小:WebAssembly 應用程序比容器小,以下是兩個簡單的用於輸出文檔的應用程序,都是使用標準工具構建的,從下圖可以看出,Wasm 應用程序比容器化應用程序小了近 10 倍。
-
速度更快:WebAssembly 應用程序的啓動速度可以比容器快 1000 倍,你可以在不到一毫秒的時間內執行應用程序的第一條指令,有時甚至可以達到微秒級。這將使構建可伸縮的應用程序變得更加容易,當請求達到峯值時,應用程序可以快速伸縮,當請求下降到零且沒有流量時,應用程序不會浪費 CPU 或內存。
-
更加安全:WebAssembly 在沙箱環境中運行,具有強大的安全性。它提供了一系列安全特性,如內存隔離、類型檢查和資源限制,以防止惡意代碼執行和訪問敏感信息。
-
可移植性更好:容器的架構限制了它們的可移植性。例如,針對 linux/amd64 構建的容器無法在 linux/arm64 上運行,也無法在 windows/amd64 或 windows/arm64 上運行。這意味着組織需要爲同一個應用程序創建和維護多個鏡像,以適應不同的操作系統和 CPU 架構。而 WebAssembly 通過創建一個在可以任何地方運行的單一 Wasm 模塊來解決這個問題。只需構建一次 wasm32/wasi 的應用程序,任何主機上的 Wasm 運行時都可以執行它。這意味着 WebAssembly 實現了一次構建,到處運行的承諾,不再需要爲不同的操作系統和 CPU 架構構建和維護多個鏡像。
關於 WebAssembly 和容器詳細的對比,可以查看這個表格: WebAssembly vs Linux Container [1]。
4 使用 Rust 開發 Wasm 應用
是否可以將應用程序編譯爲 Wasm 在很大程度上取決於所使用的編程語言。Rust、C、C++ 等語言對 Wasm 有很好的支持。從 Go 1.21 版本開始,Go 官方也初步支持了 Wasi,之前需要使用第三方工具如 tinygo 進行編譯。由於 Rust 對 Wasm 的一流支持以及無需 GC、零運行時開銷的特點,使其成爲了開發 Wasm 應用的理想選擇。因此,本文選用 Rust 來開發 Wasm 應用程序。
4.1 安裝 Rust
執行以下命令安裝 rustup,並通過 rustup 安裝 Rust 的最新穩定版本,rustup 是用於管理 Rust 版本和工具鏈的命令行工具。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
4.2 爲 Rust 添加 wasm32-wasi 編譯目標
前面提到過,Wasi(WebAssembly System Interface)是用於 WebAssembly 的系統級接口,旨在實現 WebAssembly 在不同環境中與宿主系統交互。它提供標準化的方式,使得 WebAssembly 可以進行文件 I/O、網絡操作和系統調用等系統級功能訪問。
rustc 本身是一個跨平臺的編譯器,其編譯的目標有很多,具體可以通過 rustup target list
命令來查看。wasm32-wasi 是 Rust 的編譯目標之一,用於將 Rust 代碼編譯爲符合 Wasi 標準的 Wasm 模塊。通過將 Rust 代碼編譯爲 wasm32-wasi 目標,可以將 Rust 的功能和安全性引入到 WebAssembly 環境中,同時利用 wasm32-wasi 提供的標準化系統接口實現與宿主系統的交互。
執行以下命令,爲 Rust 編譯器添加 wasm32-wasi 目標。
rustup target add wasm32-wasi
4.3 編寫 Rust 程序
首先執行以下命令構建一個新的 Rust 項目。
cargo new http-server
編輯 Cargo.toml 添加如下依賴。這裏我們使用 wrap_wasi 來開發一個簡單的 HTTP Server, warp_wasi 構建在 Warp 框架之上,Warp 是一個輕量級的 Web 服務器框架,用於構建高性能的異步 Web 應用程序。
原生的 Warp 框架編寫的代碼無法直接編譯成 Wasm 模塊。因此我們可以使用 warp_wasi,通過它我們可以在 Rust 中利用 Wasi 接口來開發 Web 應用程序。
[dependencies]
tokio_wasi = { version = "1", features = ["rt", "macros", "net", "time", "io-util"]}
warp_wasi = "0.3"
編寫一個簡單的 HTTP Server,在 8080 端口暴露服務,當接收到請求時返回 Hello, World!。
use warp::Filter;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let hello = warp::get()
.and(warp::path::end())
.map(|| "Hello, World!");
warp::serve(hello).run(([0, 0, 0, 0], 8080)).await;
}
執行以下命令,將程序編譯爲 Wasm 模塊。
cargo build --target wasm32-wasi --release
4.4 安裝 WasmEdge
編譯完成的 Wasm 模塊需要使用相應的 Wasm 運行時來運行。常見的 Wasm 運行時包括 WasmEdge、Wasmtime 和 Wasmer 等。
在這裏,我們選擇使用 WasmEdge,它是一個輕量、高性能且可擴展的 WebAssembly Runtime。執行以下命令安裝 WasmEdge。
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
運行以下命令以使已安裝的二進制文件在當前會話中可用。
source $HOME/.wasmedge/env
4.5 運行 Wasm 模塊
使用 wasmedge 來運行前面編譯好的 Wasm 模塊。
wasmedge target/wasm32-wasi/release/http-server.wasm
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
5 運行 Wasm 工作負載
5.1 在 Linux 容器中運行 Wasm 工作負載
在容器生態系統中運行 Wasm 應用程序最簡單的方法就是將 Wasm 模塊直接嵌入到 Linux 容器鏡像中。具體來說,我們可以將容器內的 Linux 操作系統精簡到足夠支持 Wasmedge 運行時,然後通過 Wasmedge 來運行 Wasm 模塊。由於 Wasm 應用程序包裝在常規容器中,因此它可以與任何容器生態系統無縫地協作。通過這種方式,整個 Linux 操作系統和 Wasmedge 運行時的內存佔用可以減少到僅爲 4MB。
相較於常規的 Linux 操作系統,精簡版的 Linux 操作系統大大減少了攻擊面。然而,這種方法仍然需要啓動 Linux 容器。即使是精簡版的 Linux 操作系統,在鏡像大小上仍然佔據了整個容器大小的 80%,因此仍然有很大的優化空間。
接下來根據前面編寫的 Rust 代碼構建出 Linux 容器鏡像。首先在前面創建的 http-server 項目根目錄下創建一個名爲 Dockerfile-wasmedge-slim 的 Dockerfile,將編譯完成的 Wasm 模塊添加到安裝了 wasmedge 的精簡 linux 鏡像中,並指定通過 wasmedge 命令來啓動 Wasm 模塊。
FROM wasmedge/slim-runtime:0.10.1
COPY target/wasm32-wasi/release/http-server.wasm /
CMD ["wasmedge", "--dir", ".:/", "/http-server.wasm"]
執行以下命令構建容器鏡像。
docker build -f Dockerfile-wasmedge-slim -t cr7258/wasm-demo-app:slim .
啓動容器。
docker run -itd -p 8080:8080 \
--name wasm-demo-app \
docker.io/cr7258/wasm-demo-app:slim
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
5.2 在支持 Wasm 的容器運行時中運行 Wasm 工作負載
前面我們介紹瞭如何將 Wasm 模塊直接嵌入到 Linux 容器中來運行 Wasm 工作負載,這種方式的好處就是可以無縫地與現有的環境進行集成,同時享受到 Wasm 帶來的性能的提升。
然而這種方法的性能和安全性不如直接在支持 Wasm 的容器運行時中運行 Wasm 程序那麼好。一般我們將容器運行時分爲高級運行時和低級運行時:
-
低級容器運行時 (Low level Container Runtime):一般指按照 OCI 規範實現的、能夠接收可運行文件系統(rootfs) 和 配置文件(config.json)並運行隔離進程的實現。低級容器運行時負責直接管理和運行容器。常見的低級容器運行時有:runc, crun, youki, gvisor, kata 等等。
-
高級容器運行時 (High level Container Runtime):負責容器鏡像的傳輸和管理,將鏡像轉換爲 rootfs 和 config.json,並將其傳遞給低級運行時執行。高級容器運行時是對低級容器運行時的抽象和封裝,爲用戶提供了更簡單、易用的容器管理接口,隱藏了低級容器運行時的複雜性。用戶可以使用同一種高級容器運行時來管理不同的低級容器運行時。常見的高級容器運行時有:containerd, cri-o 等等。
以下是一個概念圖,可以幫助你瞭解高級和低級運行時是如何協同工作的。
接下來將會分別介紹如何通過高級和低級容器運行時來運行 Wasm 模塊,首先構建一個 Wasm 鏡像。
5.2.1 構建鏡像
在前面創建的 http-server 項目根目錄下創建一個 Dockerfile 文件,這次我們直接使用 scratch 空鏡像來構建,scratch 是 Docker 中預留的最小的基礎鏡像。
FROM scratch
COPY target/wasm32-wasi/release/http-server.wasm /
CMD ["/http-server.wasm"]
執行以下命令構建容器鏡像。
docker build -t docker.io/cr7258/wasm-demo-app:v1 .
將鏡像推送到 Docker Hub 上,方便後續的實驗使用。
# 登錄 Docker Hub
docker login
# 推送鏡像
docker push docker.io/cr7258/wasm-demo-app:v1
在 Docker Hub 上可以看到這次構建的鏡像僅有 989.89 KB(壓縮後),大小僅有前面構建的 wasm-demo-app:slim 鏡像的 1/4。
5.2.2 低級容器運行時
在 5.2.2 章節中將會介紹使用 crun 和 youki 這兩種低級容器運行時在不依賴高級容器運行時的情況下,使用準備好的 config.json 和 rootfs 文件來直接啓動 Wasm 應用。
5.2.2.1 Crun
crun 是用 C 編寫的快速輕量的 OCI 容器運行時,並且內置了對 WasmEdge 的支持。本小節將演示如何通過 crun 來運行 Wasm 模塊。
請確保按照 4.4 小節安裝好了 WasmEdge。
然後在 Ubuntu 系統上從源代碼來構建它,執行以下命令安裝編譯所需的依賴。
apt update
apt install -y make git gcc build-essential pkgconf libtool \
libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libyajl-dev \
go-md2man libtool autoconf python3 automake
接下來,配置、構建和安裝支持 WasmEdge 的 crun 二進制文件。
git clone https://github.com/containers/crun
cd crun
./autogen.sh
./configure --with-wasmedge
make
make install
接下來,運行 crun -v 檢查是否安裝成功。看到有 +WASM:wasmedge,說明已經在 crun 中安裝了 WasmEdge 了。
crun -v
# 返回結果
crun version 1.8.5.0.0.0.23-3856
commit: 385654125154075544e83a6227557bfa5b1f8cc5
rundir: /run/crun
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +WASM:wasmedge +YAJL
創建一個目錄來存放運行容器所需的文件。
mkdir test-crun
cd test-crun
mkdir rootfs
# 將編譯好的 Wasm 模塊拷貝到 rootfs 目錄中,注意替換成自己對應的目錄
cp ~/hands-on-lab/wasm/runtime/http-server/target/wasm32-wasi/release/http-server.wasm rootfs
使用 crun spec
命令生成默認的 config.json 配置文件,然後進行修改:
-
- 在 args 中將
sh
替換爲/http-server.wasm
。
- 在 args 中將
-
- 在 annotations 中添加
"module.wasm.image/variant": "compat"
,表明表明這是一個沒有 guest OS 的 WebAssembly 應用程序。
- 在 annotations 中添加
-
- 在 network namespace 中添加
"path": "/proc/1/ns/net"
,讓程序與宿主機共享網絡 namespace,方便在本機進行訪問。
- 在 network namespace 中添加
修改完成後的配置文件如下:
{
"ociVersion": "1.0.0",
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"/http-server.wasm"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"effective": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"inheritable": [
],
"permitted": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"ambient": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
]
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
"root": {
"path": "rootfs",
"readonly": true
},
"hostname": "crun",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"annotations": {
"module.wasm.image/variant": "compat"
},
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "network",
"path": "/proc/1/ns/net"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "cgroup"
},
{
"type": "mount"
}
],
"maskedPaths": [
"/proc/acpi",
"/proc/asound",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
"readonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
通過 crun 啓動容器。
crun run wasm-demo-app
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
crun kill wasm-demo-app SIGKILL
5.2.2.2 Youki
youki 是一個使用 Rust 編寫的符合 OCI 規範的容器運行時。相較於 C,Rust 的使用帶來了內存安全的優勢。和 crun 一樣,Youki 同樣支持了 WasmEdge。
請確保按照 4.1 小節安裝好了 Rust。
然後 Ubuntu 系統上從源代碼來構建它,執行以下命令安裝編譯所需的依賴。
apt-get update
sudo apt-get -y install \
pkg-config \
libsystemd-dev \
libdbus-glib-1-dev \
build-essential \
libelf-dev \
libseccomp-dev \
libclang-dev \
libssl-dev
執行以下命令編譯支持 WasmEdge 的 youki 二進制文件。
./scripts/build.sh -o . -r -f wasm-wasmedge
指定 wasm-wasmedge 參數將在 $HOME/.wasmedge
目錄中安裝 WasmEdge 運行時庫。要使該庫在系統中可用,請運行以下命令:
export LD_LIBRARY_PATH=$HOME/.wasmedge/lib
或者:
source $HOME/.wasmedge/env
最後將編譯完成後的 youki 文件移動到任意 $PATH 所包含的目錄。
mv youki /usr/local/bin
創建一個目錄來存放運行容器所需的文件。
mkdir test-youki
cd test-youki
mkdir rootfs
# 將編譯好的 Wasm 模塊拷貝到 rootfs 目錄中,注意替換成自己對應的目錄
cp ~/hands-on-lab/wasm/runtime/http-server/target/wasm32-wasi/release/http-server.wasm rootfs
使用 youki spec
命令生成默認的 config.json 配置文件,然後進行修改,和前面修改 crun 配置文件的內容是一樣的:
-
- 在 args 中將
sh
替換爲/http-server.wasm
。
- 在 args 中將
-
- 在 annotations 中添加
"module.wasm.image/variant": "compat"
,表明表明這是一個沒有 guest OS 的 WebAssembly 應用程序。
- 在 annotations 中添加
-
- 在 network namespace 中添加
"path": "/proc/1/ns/net"
,讓程序與宿主機共享網絡 namespace,方便在本機進行訪問。
- 在 network namespace 中添加
修改完成後的配置文件如下:
{
"ociVersion": "1.0.2-dev",
"root": {
"path": "rootfs",
"readonly": true
},
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"process": {
"terminal": false,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"/http-server.wasm"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
"CAP_AUDIT_WRITE"
],
"effective": [
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
"CAP_AUDIT_WRITE"
],
"inheritable": [
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
"CAP_AUDIT_WRITE"
],
"permitted": [
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
"CAP_AUDIT_WRITE"
],
"ambient": [
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
"CAP_AUDIT_WRITE"
]
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
"hostname": "youki",
"annotations": {
"module.wasm.image/variant": "compat"
},
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "network",
"path": "/proc/1/ns/net"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "mount"
},
{
"type": "cgroup"
}
],
"maskedPaths": [
"/proc/acpi",
"/proc/asound",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
"readonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
通過 youki 啓動容器。
youki run wasm-demo-app
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
youki kill wasm-demo-app SIGKILL
5.2.3 高級容器運行時
在高級容器運行時中,使用不同的 shim 來對接各種低級容器運行時。在本節中,我們將以 containerd 爲例進行介紹。containerd shim 充當 containerd 和低級容器運行時之間的橋樑,其主要功能是抽象了底層運行時的細節,使 containerd 能夠統一地管理各種運行時。在 5.3 章節中將會介紹兩種 containerd 管理 Wasm 工作負載的方式:
-
containerd 使用 crun, youki 這兩種支持 WasmEdge 的不同的低級容器運行時來管理 Wasm 模塊。(當然這兩個運行時也可以運行普通的 Linux 容器)
-
containerd 通過 containerd-wasm-shim 直接通過 Wasm 運行時來管理 Wasm 模塊。
5.2.3.1 Containerd + Crun
請確保按照 5.2.2.1 小節安裝好了 crun。
使用以下命令安裝 containerd。
export VERSION="1.7.3"
sudo apt install -y libseccomp2
sudo apt install -y wget
wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz
wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum
sha256sum --check cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum
sudo tar --no-overwrite-dir -C / -xzf cri-containerd-cni-${VERSION}-linux-amd64.tar.gz
sudo systemctl daemon-reload
sudo systemctl start containerd
然後我們可以通過 containerd 運行 Wasm 程序:
-
--runc-binary:指定使用 crun 來啓動容器。
-
--runtime:指定 shim 的版本和名稱,這將由 containerd 轉換爲 shim 的二進制名稱,
io.containerd.runc.v2 -> containerd-shim-runc-v2
。containerd 會執行 containerd-shim-runc-v2 二進制文件來啓動 shim,真正啓動容器是通過 containerd-shim-runc-v2 去調用 crun 來啓動容器的。 -
--label:添加
"module.wasm.image/variant": "compat"
,表明表明這是一個沒有 guest OS 的 WebAssembly 應用程序。
# 先拉取鏡像
ctr i pull docker.io/cr7258/wasm-demo-app:v1
# 啓動容器
ctr run --rm --net-host \
--runc-binary crun \
--runtime io.containerd.runc.v2 \
--label module.wasm.image/variant=compat \
docker.io/cr7258/wasm-demo-app:v1 \
wasm-demo-app
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
ctr task kill wasm-demo-app --signal SIGKILL
5.2.3.2 Containerd + Youki
請確保按照 5.2.2.2 小節安裝好了 youki。
我們可以通過 containerd 運行 Wasm 程序,並指定使用 youki 來啓動容器。
ctr run --rm --net-host \
--runc-binary youki \
--runtime io.containerd.runc.v2 \
--label module.wasm.image/variant=compat \
docker.io/cr7258/wasm-demo-app:v1 wasm-demo-app
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
ctr task kill wasm-demo-app --signal SIGKILL
5.2.3.3 Containerd + Runwasi
runwasi 是一個用 Rust 編寫的庫,屬於 containerd 的子項目,使用 runwasi 可以編寫用於對接 Wasm 運行時的 containerd wasm shim,通過 Wasm 運行時可以管理 Wasm 工作負載。當前使用 runwasi 編寫的 containerd wasm shim 有以下幾個:
-
在 runwasi [2] 倉庫中包含了 WasmEdge 和 Wasmtime 兩種 containerd wasm shim 的實現。
-
在 containerd-wasm-shims [3] 倉庫中包含了 Spin, Slight (SpiderLightning), Wasm Workers Server (wws), lunatic 四種 containerd wasm shim 的實現。
我們直接使用 runwasi 提供的 wasmedge shim 來運行 Wasm 應用,首先克隆 runwasi 倉庫。
git clone https://github.com/containerd/runwasi.git
cd runwasi
然後安裝編譯所需的依賴。
sudo apt-get -y install \
pkg-config \
libsystemd-dev \
libdbus-glib-1-dev \
build-essential \
libelf-dev \
libseccomp-dev \
libclang-dev \
libssl-dev
執行以下命令編譯文件。
make build
sudo make install
然後我們使用 containerd 通過 WasmEdge shim 來運行 Wasm 應用:
- --runtime: 指定使用
io.containerd.wasmedge.v1
來運行 Wasm 應用。
ctr run --rm --net-host \
--runtime=io.containerd.wasmedge.v1 \
docker.io/cr7258/wasm-demo-app:v1 \
wasm-demo-app
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
ctr task kill wasm-demo-app --signal SIGKILL
5.3 在編排平臺運行 Wasm 工作負載
5.3.1 Docker Desktop 運行 Wasm
Docker Desktop 也使用了 runwasi 來支持 Wasm 工作負載,要在 Docker Desktop 中運行 Wasm 工作負載需要確保勾選以下兩個選項:
-
Use containerd for storing and pulling images
-
Enable Wasm
點擊 Apply & restart 應用更新,Docker Desktop 會下載並安裝以下可用於運行 Wasm 工作負載的運行時:
-
io.containerd.slight.v1
-
io.containerd.spin.v1
-
io.containerd.wasmedge.v1
-
io.containerd.wasmtime.v1
在 Docker 中運行 WebAssembly 應用的方式與普通的 Linux 容器沒有太大區別,只需要通過 --runtime=io.containerd.wasmedge.v1
指定使用相應的 Wasm 運行時即可。
docker run -d -p 8080:8080 \
--name=wasm-demo-app \
--runtime=io.containerd.wasmedge.v1 \
docker.io/cr7258/wasm-demo-app:v1
在本地通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
如果想要停止並刪除容器,可以執行以下命令。
docker rm -f wasm-demo-app
5.3.2 在 Kubernetes 中運行 Wasm 模塊
Kubernetes 作爲容器編排領域的事實標準,WebAssembly 正在推動雲計算的第三次浪潮 [4],而 Kubernetes 正在不斷髮展以利用這一優勢。
在 Kubernetes 中運行 Wasm 工作負載有兩種方式:
-
- 首先,我們需要使集羣中節點的容器運行時支持運行 Wasm 工作負載。接下來,可以通過使用 RuntimeClass,將 Pod 調度到指定節點並指定特定的運行時。在 RuntimeClass 中通過
handler
字段指定運行 Wasm 工作負載的 handler,可以是支持 Wasm 的低級容器運行時(例如 crun, youki),也可以是 Wasm 運行時;通過scheduling.nodeSelector
指定將工作負載調度到含有特定標籤的節點。
- 首先,我們需要使集羣中節點的容器運行時支持運行 Wasm 工作負載。接下來,可以通過使用 RuntimeClass,將 Pod 調度到指定節點並指定特定的運行時。在 RuntimeClass 中通過
-
- 將專門用於運行 Wasm 的特殊節點(Krustlet)加入集羣,通過標籤選擇器在調度時將 Wasm 工作負載指定到 Krustlet 節點。
Kind(Kubernetes in Docker) 是一個使用 Docker 容器運行本地 Kubernetes 集羣的工具。爲了方便實驗,在 5.3.2 章節中將使用 Kind 來創建 Kubernetes 集羣。使用以下命令安裝 Kind。
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
Kubectl 是用於管理 Kubernetes 集羣的命令行工作,執行以下命令安裝 Kubectl。
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/kubectl
5.3.2.1 Kubernetes + Containerd + Crun
使用以下命令創建一個單節點的 Kubernetes 集羣。
kind create cluster --name wasm-demo
每個 Kubernetes Node 都是一個 Docker 容器,通過 docker exec 命令進入該節點。
docker exec -it wasm-demo-control-plane bash
進入節點後,請確保按照 5.2.2.1 小節安裝好了 crun。
修改 containerd 配置文件 /etc/containerd/config.toml,在文件末尾添加以下內容。
-
配置 crun 作爲 containerd 的運行時 handler。格式是
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]
。 -
pod_annotations 表示允許把 Pod metadata 中設置的 Annotation
module.wasm.image/variant
傳遞給 crun,因爲 crun 需要通過這個 Annotation 來判斷這是一個 Wasm 工作負載。
cat >> /etc/containerd/config.toml << EOF
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun]
runtime_type = "io.containerd.runc.v2"
pod_annotations = ["module.wasm.image/variant"]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun.options]
BinaryName = "crun"
EOF
然後重啓 containerd。
systemctl restart containerd
創建一個名爲 crun 的 RuntimeClass 資源,並使用之前在 containerd 中設置的 crun handler。接下來,在 Pod Spec 中指定 runtimeClassName 來使用該 RuntimeClass,以告知 kubelet 使用所指定的 RuntimeClass 來運行該 Pod。此外,設置 Annotation module.wasm.image/variant: compat
,告訴 crun 這是一個 Wasm 工作負載。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: crun
handler: crun
---
apiVersion: v1
kind: Pod
metadata:
name: wasm-demo-app
annotations:
module.wasm.image/variant: compat
spec:
runtimeClassName: crun
containers:
- name: wasm-demo-app
image: docker.io/cr7258/wasm-demo-app:v1
可以通過 port-forward 將端口轉發到本地進行訪問。
kubectl port-forward pod/wasm-demo-app 8080:8080
然後在另一個終端通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
測試完畢後,銷燬該集羣。
kind delete cluster --name wasm-demo
5.3.2.2 KWasm Operator
Kwasm 是一個 Kubernetes Operator,可以爲 Kubernetes 節點添加 WebAssembly 支持。當你想爲某個節點增加 Wasm 支持時,只需爲該節點添加 kwasm.sh/kwasm-node=true
的 Annotation 。隨後,Kwasm 會自動創建一個 Job,負責在該節點上部署運行 Wasm 所需的二進制文件,並對 containerd 的配置進行相應的修改。
使用以下命令創建一個單節點的 Kubernetes 集羣。
kind create cluster --name kwasm-demo
Kwasm 提供了 Helm chart 方便用戶進行安裝,先執行以下命令安裝 Helm。
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
然後安裝 Kwasm Operator,爲所有節點添加 Annotation kwasm.sh/kwasm-node=true
啓用對 Wasm 的支持。
# 添加 Helm repo
helm repo add kwasm http://kwasm.sh/kwasm-operator/
# 安裝 KWasm operator
helm install -n kwasm --create-namespace kwasm-operator kwasm/kwasm-operator
# 爲節點添加 Wasm 支持
kubectl annotate node --all kwasm.sh/kwasm-node=true
創建一個名爲 crun 的 RuntimeClass 資源,並使用之前在 containerd 中設置的 crun handler。接下來,在 Pod Spec 中指定 runtimeClassName 來使用該 RuntimeClass,以告知 kubelet 使用所指定的 RuntimeClass 來運行該 Pod。此外,設置 Annotation module.wasm.image/variant: compat
,告訴 crun 這是一個 Wasm 工作負載。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: crun
handler: crun
---
apiVersion: v1
kind: Pod
metadata:
name: wasm-demo-app
annotations:
module.wasm.image/variant: compat
spec:
runtimeClassName: crun
containers:
- name: wasm-demo-app
image: docker.io/cr7258/wasm-demo-app:v1
Pod 運行成功後,可以通過 port-forward 將端口轉發到本地進行訪問。
kubectl port-forward pod/wasm-demo-app 8080:8080
我們在另一個終端通過 curl 命令訪問該服務。
curl http://localhost:8080
Hello, World!
測試完畢後,銷燬該集羣。
kind delete cluster --name kwasm-demo
5.3.2.3 Krustlet
Krustlet 是一個由 Rust 語言編寫的 kubelet,它在 Kubernetes 集羣中作爲一個節點,專門用於運行 Wasm 工作負載。當 Kubernetes 調度器將 Pod 調度到 Krustlet 節點時,Krustlet 會利用 Wasm 運行時來啓動相應的 Wasm 工作負載。儘管 Krustlet 項目目前已經很久沒有更新了,但是還是值得了解一番。
使用以下命令創建一個單節點的 Kubernetes 集羣。這裏通過 --image 參數指定創建 1.21.14 版本的 Kubernetes 集羣,Krustlet 最近一次更新還是在去年,可能不兼容最新的 Kubernetes 版本。我在最新的 Kubernetes 集羣上測試後,發現 Krustlet 無法正常工作。
kind create cluster --name krustlet-demo --image kindest/node:v1.21.14@sha256:8a4e9bb3f415d2bb81629ce33ef9c76ba514c14d707f9797a01e3216376ba093
接下來我們需要啓動一個 Krustlet 節點,並將它加入集羣。對於普通的節點,我們可以使用 kubeadm join 命令很方便的將節點加入集羣。因爲 kubeadm 會替你做很多事,例如生成 bootstrap token,生成 kubelet 證書等等。
對於 Krustlet 節點我們就需要手動處理這些事情了,我們可以使用 Krustlet 官方準備的腳本。這個腳本會爲我們創建 bootstrap token,這個 token 是 Krustlet 初始化時和 API Server 臨時通信而使用的。腳本還會根據 token 生成 Krustlet 臨時的 kubeconfig 文件,默認在 console ~/.krustlet/config/kubeconfig
。
```bash
bash <(curl https://raw.githubusercontent.com/krustlet/krustlet/main/scripts/bootstrap.sh)
接着執行以下命令安裝 Krustlet 二進制文件。
wget https://krustlet.blob.core.windows.net/releases/krustlet-v1.0.0-alpha.1-linux-amd64.tar.gz
tar -xzvf krustlet-v1.0.0-alpha.1-linux-amd64.tar.gz
mv krustlet-wasi /usr/local/bin/krustlet-wasi
最後,運行以下命令來啓動 Krustlet:
-
--node-ip:指定 Krustlet 的節點 IP,通常情況下 docker0 網卡的地址是
172.17.0.1
,我們在本機啓動的 Krustlet 要和 Kind 啓動的 Kubernetes 集羣進行通信,因此選擇將 Krustlet 程序綁定在 docker0 所在的地址上。可以使用ip addr show docker0
命令來確認 docker0 網卡的地址。 -
--node-name:指定 Krustlet 的節點名。
-
--bootstrap-file:指定前面通過腳本生成的 Krustlet 臨時的 kubeconfig 的文件路徑。
-
KUBECONFIG=~/.krustlet/config/kubeconfig:執行該命令的時候,這個 kubeconfig 文件還沒有生成,Krustlet 會在引導過程中生成私鑰和證書,並創建 CSR 資源,當 CSR 被批准後,Krustlet 在該路徑創建長期可用的 kubeconfig 文件,其中包含密鑰和已簽名的證書。
KUBECONFIG=~/.krustlet/config/kubeconfig \
krustlet-wasi \
--node-ip 172.17.0.1 \
--node-name=krustlet \
--bootstrap-file=${HOME}/.krustlet/config/bootstrap.conf
啓動 Krustlet 後,提示我們需要手動批准 CSR 請求。當然我們也可以設置自動批准,這裏先不展開說明。
BOOTSTRAP: TLS certificate requires manual approval. Run kubectl certificate approve instance-2-tls
執行以下命令,手動批准 CSR 請求。我們只需要在 Krustlet 第一次啓動時執行此步驟,之後它會將所需的憑證保存下來。
kubectl certificate approve instance-2-tls
然後查看節點,就可以看到 Krustlet 節點已經成功註冊到 Kubernetes 集羣中了。
# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
krustlet Ready <none> 30s 1.0.0-alpha.1 172.17.0.1 <none> <unknown> <unknown> mvp
krustlet-demo-control-plane Ready control-plane,master 4m17s v1.21.14 172.18.0.2 <none> Debian GNU/Linux 11 (bullseye) 5.19.0-1030-gcp containerd://1.7.1
查看節點信息,其架構顯示是 wasm-wasi,並且節點上有 kubernetes.io/arch=wasm32-wasi:NoExecute
和 kubernetes.io/arch=wasm32-wasi:NoSchedule
兩個污點,我們在創建 Pod 時需要指定容忍該污點才能調度到 Krustlet 節點上。
# kubectl describe node krustlet
Name: krustlet
Roles: <none>
Labels: beta.kubernetes.io/arch=wasm32-wasi
beta.kubernetes.io/os=wasm32-wasi
kubernetes.io/arch=wasm32-wasi
kubernetes.io/hostname=instance-2
kubernetes.io/os=wasm32-wasi
type=krustlet
Annotations: node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Tue, 29 Aug 2023 02:55:19 +0000
Taints: kubernetes.io/arch=wasm32-wasi:NoExecute
kubernetes.io/arch=wasm32-wasi:NoSchedule
Unschedulable: false
Lease:
HolderIdentity: krustlet
AcquireTime: Tue, 29 Aug 2023 02:55:49 +0000
RenewTime: Tue, 29 Aug 2023 02:55:49 +0000
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
Ready True Tue, 29 Aug 2023 02:55:49 +0000 Tue, 29 Aug 2023 02:55:19 +0000 KubeletReady kubelet is posting ready status
OutOfDisk False Tue, 29 Aug 2023 02:55:19 +0000 Tue, 29 Aug 2023 02:55:19 +0000 KubeletHasSufficientDisk kubelet has sufficient disk space available
Addresses:
InternalIP: 172.17.0.1
Hostname: instance-2
Capacity:
cpu: 4
ephemeral-storage: 61255492Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 4032800Ki
pods: 110
Allocatable:
cpu: 4
ephemeral-storage: 61255492Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 4032800Ki
pods: 110
System Info:
Machine ID:
System UUID:
Boot ID:
Kernel Version:
OS Image:
Operating System: linux
Architecture: wasm-wasi
Container Runtime Version: mvp
Kubelet Version: 1.0.0-alpha.1
Kube-Proxy Version: v1.17.0
PodCIDR: 10.244.0.0/24
PodCIDRs: 10.244.0.0/24
Non-terminated Pods: (0 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 0 (0%) 0 (0%)
memory 0 (0%) 0 (0%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal RegisteredNode 36s node-controller Node krustlet event: Registered Node krustlet in Controller
和前面直接在容器運行時裏運行 Wasm 鏡像不同,Krustlet 只支持 media types 是 application/vnd.wasm.config.v1+json
的 OCI 鏡像,我們之前構建的鏡像的 media types 是 application/vnd.oci.image.layer.v1.tar+gzip
。詳情參見:Open Containers Initiative [5]。
因此我們需要使用 wasm-to-oci 這個工具來構建鏡像,wasm-to-oci 是一個用於將 Wasm 模塊發佈到註冊表的工具,它打包模塊並將其上傳到註冊表。執行以下命令,安裝 wasm-to-oci。
wget https://github.com/engineerd/wasm-to-oci/releases/download/v0.1.2/linux-amd64-wasm-to-oci
mv linux-amd64-wasm-to-oci /usr/local/bin/wasm-to-oci
chmod +x /usr/local/bin/wasm-to-oci
當前暫不支持將 Wasm 模塊直接推送到 Docker Hub 上,因此這裏我們選擇使用 GitHub Package Registry [6] 來存放 Wasm 模塊。
docker login ghcr.io
Username: # Github 用戶名
Password: # Github Token
另外由於 Krustlet 是基於 wasmtime 來運行 Wasm 工作負載的,並且 wasmitime 目前暫不支持 HTTP,詳情參見:WASI Proposals Support [7]。
因此我們這裏寫一個簡單的打印 Hello, World 的 Rust 程序。執行以下命令構建一個新的 Rust 項目。
cargo new hello-world
然後在 main.rs 文件中添加以下代碼。
use std::thread;
use std::time::Duration;
fn main() {
loop {
println!("Hello, World!");
thread::sleep(Duration::from_secs(1));
}
}
執行以下命令,將程序編譯爲 Wasm 模塊。
cargo build --target wasm32-wasi --release
使用 wasm-to-oci 將編譯好的 Wasm 模塊上傳到 GitHub Package Registry。
wasm-to-oci push target/wasm32-wasi/release/hello-world.wasm ghcr.io/cr7258/wasm-demo-app:oci
可以看到鏡像的 media types 是 application/vnd.wasm.config.v1+json
。
爲了方便測試,我們將鏡像設置爲公開的。
然後創建 Pod 使用該鏡像,添加容忍運行調度到 Krustlet 節點上,由於我們的 Kubernetes 集羣中只有一個節點,因此不用設置節點選擇器。
apiVersion: v1
kind: Pod
metadata:
name: wasm-demo-app
spec:
containers:
- name: wasm-demo-app
image: ghcr.io/cr7258/wasm-demo-app:oci
tolerations:
- key: "kubernetes.io/arch"
operator: "Equal"
value: "wasm32-wasi"
effect: "NoExecute"
- key: "kubernetes.io/arch"
operator: "Equal"
value: "wasm32-wasi"
effect: "NoSchedule"
查看 Pod 日誌可以看到每隔 1s 打印 Hello, World!。
kubectl logs wasm-demo-app
Hello, World!
Hello, World!
Hello, World!
測試完畢後,銷燬該集羣。
kind delete cluster --name krustlet-demo
6 總結
本文首先闡述了 WebAssembly 基本概念以及其相較於傳統容器的優勢,然後介紹了使用 Rust 開發 Wasm 應用的流程。接着,爲讀者詳細展示了在各種環境中運行 Wasm 工作負載的方法,涵蓋了在 Linux 容器、支持 Wasm 的容器運行時,以及編排平臺上的運行方法。
本文使用到的代碼以及配置文件可以在我的 Github 上找到:https://github.com/cr7258/hands-on-lab/tree/main/wasm/runtime 。
7 附錄
7.1 關於 compat 和 compat-smart 註解
本文中使用 "module.wasm.image/variant": "compat"
Annotation 來告訴容器運行時這是 Wasm 工作負載,當前 crun 支持了一個新的 Annotation "module.wasm.image/variant": "compat"
。詳情參見:WasmEdge issue: Add crun "-smart" annotation [8]。
當使用 compat-smart
註解時,crun
可以根據工作負載是 Wasm 還是普通 OCI 容器來智能地選擇容器的啓動方式。這種選擇只會在標準 OCI 容器和 Wasm 應用程序位於同一個 pod 中時產生影響。下面是一個示例的 Pod 資源文件,其中包含一個 Wasm 應用程序和一個普通的 Linux 應用程序。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: crun
handler: crun
---
apiVersion: v1
kind: Pod
metadata:
name: wasm-demo-app
annotations:
module.wasm.image/variant: compat-smart
spec:
runtimeClassName: crun
containers:
- name: wasm-demo-app
image: docker.io/cr7258/wasm-demo-app:v1
- name: linux-demo-app
image: nginx:1.20
7.2 Krustlet 報錯
在啓動 Krustlet 的時候可能會遇到以下報錯:
libssl.so.1.1: cannot open shared object file: No such file or directory
原因是 Krustlet 依賴 openssl 1.1 版本,可以參考該鏈接解決:解決報錯 libssl.so.1.1 [9]。
7.3 WasmEdge 報錯
在用容器運行時啓動容器的時候可能會出現以下報錯。
FATA[0000] failed to create shim task: OCI runtime create failed: could not load `libwasmedge.so.0`: `libwasmedge.so.0: cannot open shared object file: No such file or directory`: unknown
重新執行 WasmEdge 安裝命令。
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
8 參考資料
-
[1] WebAssembly vs Linux Container: https://wasmedge.org/wasm_linux_container/
-
[2] runwasi: https://github.com/containerd/runwasi
-
[3] containerd-wasm-shims: https://github.com/deislabs/containerd-wasm-shims
-
[4] WebAssembly 正在推動雲計算的第三次浪潮: https://nigelpoulton.com/webassembly-the-future-of-cloud-computing
-
[5] Open Containers Initiative: https://github.com/opencontainers/artifacts/blob/main/artifact-authors.md#visualizing-artifacts
-
[6] GitHub Package Registry: https://github.com/features/packages
-
[7] WASI Proposals Support: https://docs.wasmtime.dev/stability-wasi-proposals-support.html
-
[8] 解決報錯 libssl.so.1.1: https://blog.csdn.net/estelle_belle/article/details/111181037
-
[9] WasmEdge issue: Add crun "-smart" annotation: https://github.com/WasmEdge/WasmEdge/issues/1338
-
[10] WasmEdge Docs: https://wasmedge.org/docs/
-
[11] Kwasm: https://kwasm.sh/
-
[12] 各種容器運行時都解決了什麼問題: https://www.zeng.dev/post/2020-container-runtimes/
-
[13] Container Runtimes Part 3: High-Level Runtimes: https://www.ianlewis.org/en/container-runtimes-part-3-high-level-runtimes
-
[14] WebAssembly and its platform targets: https://snarky.ca/webassembly-and-its-platform-targets/
-
[15] WebAssembly: Docker without containers!: https://wasmlabs.dev/articles/docker-without-containers/
-
[16] Standardizing WASI: A system interface to run WebAssembly outside the web: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
-
[17] Manage WebAssembly Apps Using Container and Kubernetes Tools: https://www.secondstate.io/articles/manage-webassembly-apps-in-wasmedge-using-docker-tools/
-
[18] Build and Manage Wasm Applications using Container Tools - Michael Yuan, WasmEdge: https://www.youtube.com/watch?v=kOvoBEg4-N4
-
[19] Executing WebAssembly (Wasm) modules in containers using crun, podman, and MicroShift: https://www.youtube.com/watch?v=3fudsMOkRCM
-
[20] What's New in Docker + Wasm Technical Preview 2?: https://kodekloud.com/blog/whats-new-in-docker-wasm-technical-preview-2/#
-
[21] Running WebAssembly Applications on Kubernetes with WasmEdge | Mirantis Labs - Tech Talks: https://www.youtube.com/watch?v=--T-JFFNGlE
-
[22] Running Wasm in a container: https://atamel.dev/posts/2023/06-29_run_wasm_in_docker/
-
[23] Cloud Native Apps with Server-Side WebAssembly - Liam Randall, Cosmonic: https://www.youtube.com/watch?v=2OTyBxPyW7Q
-
[24] Containerd Adds Support for a New Container Type: Wasm Containers: https://www.infoq.com/news/2023/02/containerd-wasi/
-
[25] Using WebAssembly and Kubernetes in Combination: https://alibaba-cloud.medium.com/using-webassembly-and-kubernetes-in-combination-7553e54ea501
-
[26] Run WASM applications from Kubernetes: https://msazure.club/run-wasm-applications-from-kubernetes/
-
[27] A First Look at Wasm and Docker: https://dev.to/docker/a-first-look-at-wasm-and-docker-5dg0
-
[28] What is runwasi: https://nigelpoulton.com/what-is-runwasi/
-
[29] Getting started with Docker + Wasm: https://nigelpoulton.com/getting-started-with-docker-and-wasm/
-
[30] Wasm and Kubernetes – Working Together: https://collabnix.com/wasm-and-kubernetes-working-together/
-
[31] Rust microservices in server-side WebAssembly: https://blog.logrocket.com/rust-microservices-server-side-webassembly
-
[32] What is cloud native WebAssembly: https://nigelpoulton.com/what-is-cloud-native-webassembly/
-
[33] Compile Rust & Go to a Wasm+Wasi module and run in a Wasm runtime
-
[34] Cloud Native Wasm Day EU 2023: Summaries, Insights, and Opinions: https://cosmonic.com/blog/industry/cloud-native-wasm-day-2023-wrap-up
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/vRtNd-eMgUhP9hq4s3vkeA