在 Docker 上玩 WASM
字節碼可以在任何地方運行的想法可以追溯到 JVM 的初始階段,WebAssembly 是舊思想的新實現。WebAssembly 的目的是在瀏覽器中運行,而 Docker 宣佈它可以在不需要容器的情況下運行 WASM 代碼。在這篇文章中,我們來探索它是如何工作的。
先決條件
運行 WebAssembly 是一個測試版功能,需要使用 containerd。要啓用 containerd,請轉到 Docker Desktop 儀表板,然後單擊 “設置> 開發中的功能> Beta 功能>使用 containerd 存儲和提取鏡像”。
爲了比較常規鏡像與 WebAssembly,因此,需要一個既可以編譯爲本機代碼又可以編譯爲 WASM 的項目。出於這個原因,我們使用 Rust 語言創建一個帶有兩個 dockerfile 的簡單項目:一個編譯爲本地代碼,另一個編譯爲 WASM。
在本機構建
創建一個 Rust 項目:
cargo new wasm-docker-example
src/main.rs 文件中代碼如下:
fn main() {
println!("Hello, world!");
}
爲了便於比較,我們可以在本地構建 Webassembly 目標:
rustup target add wasm32-wasi
cargo build --target wasm32-wasi --release
文件相對較小:
-rwxr-xr-x 1 Justin staff 2093838 6 19 17:39 wasm-docker-example.wasm
構建簡單的 Docker 鏡像
在項目根目錄下創建 Dockerfile-wasm 文件,內容如下:
FROM rust:1.70-slim-bullseye as build
COPY Cargo.toml .
COPY Cargo.lock .
COPY src src
RUN rustup target add wasm32-wasi
RUN cargo build --target wasm32-wasi --release
FROM scratch
COPY --from=build /target/wasm32-wasi/release/wasm-docker-example.wasm wasm.wasm
ENTRYPOINT [ "/wasm.wasm" ]
1,從一個 Rust Docker 映像開始
2,添加 WASM 目標
3,構建 Webassembly
4,從 scratch 開始使用多級構建。
5,複製上一階段生成的 Webassembly 文件
使用如下命令構建鏡像:
docker build -f Dockerfile-wasm -t docker-wasm:1.0 .
使用如下命令運行 WASM:
docker run --runtime=io.containerd.wasmedge.v1 docker-wasm:1.0
Hello, world!
爲了進行比較,我們可以用相同的代碼創建一個本地鏡像,在項目根目錄下創建 Dockerfile-native 文件,內容如下:
FROM rust:1.70-slim-bullseye as build
COPY Cargo.toml .
COPY Cargo.lock .
COPY src src
RUN RUSTFLAGS='-C target-feature=+crt-static' cargo build --release
FROM scratch
COPY --from=build /target/release/wasm-docker-example native
從 scratch 開始構建鏡像並生成二進制文件。
使用如下命令構建鏡像:
docker build -f Dockerfile-native -t docker-native:1.0 .
現在我們可以比較鏡像的大小:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-native 1.0 f48a37ac1a66 6 seconds ago 7.32MB
docker-wasm 1.0 332c53bb03e0 5 minutes ago 2.61MB
Webassembly 鏡像大約是本機鏡像的三分之一。
構建複雜的 Docker 鏡像
在 Cargo.toml 文件中加入以下依賴項:
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1.28", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
在 src/main.rs 中更新代碼來發出請求並打印結果:
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use reqwest::get;
#[tokio::main(flavor = "current_thread")]
async fn main() {
match get("http://httpbin.org/get").await {
Ok(response) => {
let result = response.json::<GetBody>().await;
match result {
Ok(json) => {
println!("{:#?}", json);
}
Err(err) => {
println!("{:#?}", err)
}
}
}
Err (err) => {
println!("{:#?}", err)
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct GetBody {
args: HashMap<String, String>,
headers: HashMap<String, String>,
origin: String,
url: String,
}
使用如下命令構建鏡像:
docker build -f Dockerfile-wasm -t docker-wasm:1.1 .
使用如下命令運行 WASM:
docker run --runtime=io.containerd.wasmedge.v1 docker-wasm:1.1
GetBody {
args: {},
headers: {
"X-Amzn-Trace-Id": "Root=1-64905d7f-2371d2807e7f74780d60ab96",
"Host": "httpbin.org",
"User-Agent": "Go-http-client/1.1",
"Accept": "*/*",
},
origin: "103.82.4.2",
url: "http://httpbin.org/get",
}
總結
在這篇文章中,實現了幾個 WASM Docker 鏡像,從最簡單的 Hello World 到 HTTP 客戶端。雖然 Docker 關於 WASM 的生態系統還有改進的空間,但 Docker 對 WASM 的支持已經可以讓我們從中受益。WASM 鏡像的尺寸小是一個巨大的優點。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/MfwwrsxWHM7BU97_Upgx9A