Rust - WASM - Docker 集成

在這篇文章中,我們將構建一個 Rust 應用程序,它給出兩個數字的和。我們將在瀏覽器中以 WebAssembly 應用程序的形式運行應用程序,並將其打包爲 docker 容器。

WASM

很長一段時間以來,開發人員一直在使用 Javascript 來提供 web 上的定製體驗,也有一些其他的 web 腳本語言,但它們都有侷限性。爲了增強體驗,開發人員開始使用針對不同瀏覽器的二進制插件,儘管如此,它們在執行具有高級功能的 Web 應用程序時還很欠缺。這就是 WebAssembly 的用處所在,現在開發人員可以用 C/C++/Rust 等語言開發代碼,並使用 WebAssembly 編譯來創建可以在 web 瀏覽器中運行的本地字節碼代碼。

WebAssembly 不能自己工作,它仍然需要 Javascript。但它可以取代 Javascript 中的緩慢計算部分,並提供接近本機的速度。它的工作方式是,當開發人員用本地語言編寫代碼時,他們可以使用 WebAssembly 作爲編譯目標。WebAssembly 生成的字節碼可以在瀏覽器提供的 WebAssembly 運行時中運行。一些例子是像《末日 3》這樣的遊戲,以及像 Autocad 和 Figma 這樣的 web 應用程序,它們現在可以通過任何瀏覽器作爲 WebApp 使用。這裏最大的優勢是應用程序現在是獨立於主機的,即相同的應用程序不受操作系統和 CPU 架構的影響。

除了瀏覽器,WebAssembly 字節碼也可以被容器化並作爲 docker 容器執行。這開啓了一個充滿可能性的全新世界。讓我們看看下面的內容。

docker 與 WebAssembly 的比較:

Docker 提供了一種將應用程序及其依賴項 (OS 依賴項和庫) 打包到映像中的方法,開發人員可以將該映像的各種實例作爲容器運行。這是由容器運行時啓用的,可以是 Docker engine, runc, containd 等。所以基本上容器運行時可以啓動應用程序的不同實例作爲不同的容器,它還允許與主機操作系統資源通信。

在 WebAssembly 的情況下,WebAssembly 運行時啓用代碼執行,所有現代瀏覽器都提供這個運行時。WebAssembly Runtime 的其他例子有 Wasmedge, NodeJs 等。與系統資源的通信是通過 WebAssembly 系統接口實現的,如圖所示。

Containerd - 是一個流行的 docker 容器運行時環境,目前 Docker 和 Kubernetes 都支持它。Docker 的工作人員正在爲 Wasmedge 運行時環境啓用容器進行努力,這將允許 WebAssembly 應用程序作爲 docker 容器執行。

將 WebAssembly 應用程序作爲 docker 容器運行的優點:

構建應用程序

讓我們先從安裝開始:

1,安裝 Rust - https://www.rust-lang.org/learn/get-started

2,安裝 Wasm pack - https://rustwasm.github.io/wasm-pack/installer/

3,可選安裝 cargo-generate - 啓動模板項目

4,可選安裝 npm - 測試 / 運行 javascript 應用程序

5,安裝 Docker 桌面 - 啓用容器提取和存儲圖像,也啓用實驗功能 (如果沒有啓用)

WebApp

讓我們先從創建 WebApp 開始,當你必須將應用程序創建爲 Docker 容器時,有一個小的區別,我將在下一節告訴你。

使用 cargo 創建一個作爲 lib 模塊的新項目:

cargo init --lib rust-wasm-docker-hello-world

Cargo.toml 文件如下:

[package]
name = "rust-wasm-docker-hello-world"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasm-bindgen = "0.2.63"

[lib]
crate-type = ["cdylib"]

在 lib.rs 文件中寫入如下代碼:

use wasm_bindgen::prelude::*; 

#[wasm_bindgen] 
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

使用 wasm-pack 進行構建:

wasm-pack build --target web

你會注意到一個 pkg 文件夾,裏邊有 Javascript 和 wasm 文件。

在項目根目錄下創建一個 html 文件夾,並在文件夾中創建一個 index.html 文件,使用 Javascript 配置 Wasm 應用程序,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta >
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>HTML 5 Boilerplate</title>
</head>
<body>
<script type="module">
    import init, { add } from '../pkg/rust_wasm_docker_hello_world.js'
    await init()
    console.log(add(1,3))
</script>
</body>
</html>

在這裏我們使用 Javascript 導入在 Wasm 應用程序中創建的 “add” 函數並調用。正如我上面提到的,wasm-bindgen 支持 Javascript 和 wasm 字節碼之間的通信。你可以使用 NodeJs 或任何其他服務器來託管你的應用程序,並使用 web 瀏覽器打開它。如下所示,控制檯正在打印輸出:

Docker

現在要對這個應用程序進行容器化,我們需要構建可以承載 wasm 文件的映像。在此之前,我們需要一個 main.rs 文件。

Docker 只能通過 main 函數進入應用程序,Docker 將使用 Wasmedge 環境來執行 main 函數中的代碼。

mod lib;
use std::env;
fn main() {
    let args: Vec<String> = env::args().collect();
    let num1 = &args[1];
    let num2 = &args[2];
    let sum = lib::add(num1.parse::<usize>().unwrap(), num2.parse::<usize>().unwrap());
    println!("Sum of 2 numbers is {}", sum);
}

執行如下命令測試一下代碼:

cargo run 1 2

Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/rust-wasm-docker-hello-world 1 2`
Sum of 2 numbers is 3

在構建應用程序之前還需要修改 Cargo.toml 和 lib.rs 文件,如下:

Cargo.toml

[dependencies]
# wasm-bindgen = "0.2.63"

[lib]
# crate-type = ["cdylib"]

lib.rs

// use wasm_bindgen::prelude::*; 

// #[wasm_bindgen] 
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

完成之後,爲 WASM 編譯 / 構建應用程序:

cargo build --target wasm32-wasi --release

在項目根目錄下創建 Dockerfile 文件:

FROM scratch
COPY ./target/wasm32-wasi/release/rust-wasm-docker-hello-world.wasm /rust-wasm-docker-hello-world.wasm
ENTRYPOINT [ "rust-wasm-docker-hello-world.wasm" ]

我們使用的是 scratch,這意味着沒有提供基本鏡像。因此這個鏡像只包含應用程序字節碼。

構建鏡像:

docker buildx build --platform wasi/wasm32 -t paras301/docker-wasm:latest .

注意,鏡像的大小隻有 522Kb,鏡像的操作系統是 WASI,即 WebAssembly 系統接口。

運行 docker 鏡像:

docker run --rm --name=docker-wasm --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 paras301/docker-wasm:latest 1 2

Sum of 2 numbers is 3

在運行 docker 鏡像時,需要傳遞運行時和平臺,因此 docker 會理解使用 wasmedge 作爲這個特定容器的運行時環境。

現在你看到了 Docker 和 Wasm 集成帶來的可能性,由於鏡像大小隻有幾 mb,開發人員可以開始創建容器,爲每個請求提供接近本機的速度,並且預熱時間也接近 0。此外,相同負載的資源需求也會減少很多。到目前爲止,該特性的唯一缺點是仍處於測試階段,我相信 Wasm Apps 和 Wasm Docker 容器會有一個美好的未來。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Odd58NMax6Btp1xCPOBf2A