wasmtime & wasmer
สองรันไทม์อิสระระดับ production ที่ครองระบบนิเวศ WASI: wasmtime (ดูแลโดย Bytecode Alliance, เขียนด้วย Rust) และ wasmer (เขียนด้วย Rust, ข้ามแพลตฟอร์ม) ทั้งคู่ implement WASI spec, รองรับ ahead-of-time (AOT) compilation และเปิดเผย embedding API สำหรับ Rust, Python, Go และภาษาอื่น ๆ
การติดตั้งรันไทม์
หัวข้อที่มีชื่อว่า “การติดตั้งรันไทม์”# wasmtime — via installer scriptcurl https://wasmtime.dev/install.sh -sSf | bash
# wasmer — via installer scriptcurl https://get.wasmer.io -sSfL | sh
# Verifywasmtime --versionwasmer --versionรัน WASI module ด้วย wasmtime
หัวข้อที่มีชื่อว่า “รัน WASI module ด้วย wasmtime”# Basic executionwasmtime my_app.wasm
# Pass command-line arguments (-- separates runtime flags from module args)wasmtime my_app.wasm -- hello world
# Grant access to a directorywasmtime --dir /tmp my_app.wasm
# Grant access with a path alias (host path::guest path)wasmtime --dir /host/data::/data my_app.wasm
# Pass environment variableswasmtime --env DATABASE_URL=postgres://localhost/db my_app.wasm
# Combine: dir + env + argswasmtime --dir /data --env LOG_LEVEL=info my_app.wasm -- --config /data/cfg.tomlรัน WASI module ด้วย wasmer
หัวข้อที่มีชื่อว่า “รัน WASI module ด้วย wasmer”# Basic executionwasmer my_app.wasm
# Mount a directorywasmer --dir /tmp my_app.wasm
# Pass environment variableswasmer --env KEY=value my_app.wasm
# Run from the Wasmer registry (wapm packages)wasmer run python/python -- --versionEmbed wasmtime ในแอปพลิเคชัน Rust
หัวข้อที่มีชื่อว่า “Embed wasmtime ในแอปพลิเคชัน Rust”พลังที่แท้จริงของรันไทม์อิสระคือการ embed — โหลด plugin .wasm ขณะ runtime โดยไม่ต้องคอมไพล์ host application ใหม่
use wasmtime::{Engine, Linker, Module, Store};use wasmtime_wasi::{p1::WasiP1Ctx, WasiCtxBuilder};
fn run_plugin(wasm_bytes: &[u8]) -> anyhow::Result<()> { let engine = Engine::default(); let module = Module::new(&engine, wasm_bytes)?;
// Build a minimal WASI Preview 1 context — no filesystem, no env vars let wasi: WasiP1Ctx = WasiCtxBuilder::new().inherit_stdio().build_p1(); let mut store = Store::new(&engine, wasi);
let mut linker = Linker::new(&engine); wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |s| s)?;
let instance = linker.instantiate(&mut store, &module)?; let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; start.call(&mut store, ())?; Ok(())}pattern นี้คือวิธีที่ระบบ plugin ทำงาน: host application โหลดไฟล์ .wasm ตามอำเภอใจขณะ runtime และเรียก exported function โดยมี sandbox บังคับ isolation อย่างเข้มงวด
sequenceDiagram
participant Host as Host App (Rust)
participant WT as wasmtime Engine
participant M as Plugin (.wasm)
Host->>WT: Engine::default()
Host->>WT: Module::new(wasm_bytes)
Host->>WT: Linker + WasiCtxBuilder
Host->>WT: linker.instantiate()
WT->>M: instantiate + link imports
Host->>M: typed_func("process").call(args)
M-->>Host: return value ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
WASI capability-based security (--dir/--env) | ปลอดภัยกว่ามาก — module ที่ wasmtime/wasmer รันได้เฉพาะสิทธิ์ที่ flag ระบุไว้อย่างชัดเจน | ยังไม่ compatible กับ POSIX เต็มรูปแบบ binary ที่ port มาจาก native code ซึ่ง assume ambient access จะรันไม่ได้ตรง ๆ |
| Embed wasmtime/wasmer สำหรับ edge/serverless | Cold-start ระดับ microsecond เมื่อเทียบกับการ spin container ใหม่ทุกครั้ง | Container ecosystem ยังมี tooling, orchestration และ library support ที่ mature และกว้างกว่า |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ลืมส่ง
--dirหรือ--envตอนรัน แล้วแปลกใจว่าทำไม module เข้าถึง filesystem หรือ environment variable ไม่ได้ — ต้อง grant capability ให้ runtime อย่างชัดเจนเสมอ - คิดว่า SIMD หรือ threads proposal รองรับเหมือนกันทุก runtime — wasmtime และ wasmer อาจ support level ต่างกัน ต้อง check ความสามารถของ runtime version ที่ใช้ก่อน deploy
- Embed wasmtime version เก่าเข้ากับ component ที่ build ด้วย Component Model รุ่นใหม่กว่า — WIT interface ที่ยังพัฒนาอยู่ทำให้ binding code เก่าพังตอน link หรือ instantiate
💡 ตัวอย่างจากของจริง
Fermyon Spin build บน Wasmtime เพื่อ embed และรัน serverless Wasm module ส่วน Fastly Compute และ Cloudflare Workers ใช้หลักการ embedding และ sandboxing แบบเดียวกันเพื่อ isolate tenant code ด้วย cold-start ที่ต่ำมาก