基礎編 #07:「Wasmランタイム(実行エンジン)」って何だ?WasmtimeとWasmEdgeの役割の違い
Rustを使って頑丈でメモリ安全なプログラムを書き、それをWebAssembly(Wasm)の軽量なバイナリファイルへ変換しても、そのファイルが自力でサーバー上を走り始めるわけではありません。
Wasmバイナリは、精密に設計された建築部材を小さな箱へ収めたものです。VPSという土地の上で箱を開き、CPUが理解できる形へ変換し、安全な区画の中で動かすためには、専用の施工機が必要になります。
その施工機にあたるものが、Wasmランタイム(実行エンジン)です。
サーバーサイドWasmでは、代表的なランタイムとしてWasmtimeとWasmEdgeが知られています。名前は似ていますが、得意な現場は少し違います。本記事では、Wasmランタイムの役割、WasmtimeとWasmEdgeの設計思想、VPS運用での選び方、RustからWasmtimeを呼び出す最小実装までを整理します。
1. 結論:最初の基幹ランタイムにはWasmtime
結論から言えば、両者の違いは「どちらが上か」ではなく、何を中心に設計されているかです。
- Wasmtime:標準規格への追従、汎用性、Rustとの親和性、組み込みやすさを重視する場面に向く
- WasmEdge:クラウドネイティブ、エッジ処理、プラグイン拡張、AI推論などを積極的に扱う場面に向く
銀翼の艦橋のように、VPS上でデータ収集、記事処理、WordPress連携などを長時間安定して動かす基幹系では、まずWasmtimeを選ぶのが分かりやすい判断です。
一方、将来ローカルAI推論やGPUを使う処理が独立モジュールとして必要になった場合は、その部分だけWasmEdgeへ任せる構成も考えられます。
最初から二者択一にするのではなく、基幹処理はWasmtime、特殊処理はWasmEdgeも候補という整理が現実的です。
2. Wasmランタイムは何をしているのか
「ランタイム」という言葉は抽象的ですが、役割を分解すると理解しやすくなります。
① WasmをCPUが実行できる形へ変換する
.wasmファイルは、CPUがそのまま理解するネイティブ命令ではありません。
Wasmランタイムは、Wasmの命令を読み込み、実行時コンパイル(JIT)や事前コンパイル(AOT)を使って、ホストCPUが実行できる形へ変換します。
つまり、Wasmランタイムは「設計図を読み取り、現場の機械に合う加工方法へ翻訳する施工機」です。
② メモリと実行状態を管理する
Wasmモジュールは独立した線形メモリを持ちます。ランタイムは、そのメモリ領域や関数呼び出し、実行状態を管理します。
Wasm側が扱うメモリと、ホストアプリケーション側のメモリを分離することで、プログラム同士が無秩序に干渉しにくい構造を作ります。
③ OS資源へのアクセスを制御する
Wasmプログラムがファイル、環境変数、ネットワークなどへ触れるには、ホスト側から明示的に機能を渡す必要があります。
何も許可しなければ、Wasmは勝手にサーバー内部を探索できません。必要なディレクトリや通信機能だけを渡すことで、権限を小さく保てます。
ここで重要なのは、Wasmだから自動的にすべて安全になるわけではない点です。安全性は、ランタイムの設定、渡す権限、バージョン管理、ホスト側コードを含めた全体設計で成立します。
3. Wasmtimeの特徴
Wasmtimeは、Bytecode Allianceが開発を主導するWebAssemblyランタイムです。
軽量性、安全性、標準準拠を重視し、CLIとして単独実行するだけでなく、Rustなどのホストアプリケーションへ組み込めます。
Wasmtimeの強み
- WebAssemblyとWASIの標準仕様へ継続的に対応している
- Rust向けAPIが整備されている
- Craneliftを利用したコンパイル基盤を持つ
- ホスト側からWasm関数を型付きで呼び出せる
- ファイル、メモリ、実行時間などの制御を組み込みやすい
- サーバー処理、プラグイン、隔離実行など幅広い用途へ適用できる
銀翼の艦橋では、WordPress連携やデータ処理といった基幹ロジックを小さなモジュールへ分け、必要な処理だけを安全に呼び出す構成と相性が良いと言えます。
注意点
Wasmtimeは強力ですが、AI推論用GPUや独自データベース連携などが最初からすべて内蔵されているわけではありません。
特殊な処理を行う場合は、WASI機能、ホスト関数、専用プラグイン、外部サービスとの連携を設計する必要があります。
4. WasmEdgeの特徴
WasmEdgeは、CNCFのSandboxプロジェクトとして運営されている、クラウドネイティブやエッジ用途を強く意識したWebAssemblyランタイムです。
WASIに加えて、ネットワーク、データベース、AI推論などへ接続するための拡張やプラグインが用意されています。
WasmEdgeの強み
- 軽量なサーバーレス処理やエッジ実行を想定している
- AOTコンパイルに対応している
- Rustを含む複数言語から利用できる
- HTTP、データベース、メッセージングなどの拡張がある
- WASI-NNプラグインを通じてAI推論バックエンドへ接続できる
- LLM、音声認識、画像処理などの推論用途へ発展させやすい
WasmEdgeのAI機能は、Wasm内部だけでモデルを完結させるというより、WASI-NNを経由してホスト側に用意された推論エンジンを利用する構成です。
注意点
プラグインや独自拡張を多く使うほど、その環境への依存も増えます。
標準的なWASIだけで動くモジュールより、ランタイムのバージョン、プラグイン、バックエンド、GPU環境などの組み合わせを管理する必要があります。
5. WasmtimeとWasmEdgeの比較
| 比較項目 | Wasmtime | WasmEdge |
|---|---|---|
| 主な設計方向 | 標準準拠・汎用・組み込み | クラウド・エッジ・拡張 |
| Rustとの連携 | 強い | 対応 |
| WASI対応 | 強い | 対応 |
| AI推論 | ホスト連携やWASI-NNで構成 | WASI-NNプラグインが豊富 |
| プラグイン拡張 | ホスト関数中心 | プラグイン群が豊富 |
| 基幹処理 | 向いている | 用途により可能 |
| 特殊な推論処理 | 別途設計が必要 | 得意分野の一つ |
| 銀翼の艦橋での位置 | 基本ランタイム候補 | 将来の特殊処理候補 |
迷ったときは、次の順で考えると整理できます。
- 標準WASIとRustの組み込みを中心にしたいか
- AI推論やエッジ向け拡張を最初から重視するか
- 運用するVPSで必要な依存関係を管理できるか
- モジュールをほかのランタイムへ移せる状態に保ちたいか
銀翼の艦橋では、最初からすべてをWasm化する必要はありません。Rust本体で動いている安定部分を維持し、隔離したい処理や交換可能にしたい処理から段階的にWasmへ移す方が安全です。
6. RustからWasmtimeを呼び出す最小実装
ここでは、Rustのホストプログラムから小さなWasm関数を呼び出します。
まずプロジェクトを作成します。
cargo new wasmtime-host
cd wasmtime-host
Cargo.tomlへWasmtimeを追加します。
[dependencies]
wasmtime = "45"
Wasmtimeは更新が速いため、実際に導入する際はプロジェクトで採用するメジャーバージョンを固定し、検証後に更新します。
src/main.rsを次のようにします。
use wasmtime::{Engine, Instance, Module, Result, Store};
fn main() -> Result<()> {
println!("--- Wasmtimeホスト起動 ---");
// Wasmをコンパイル・実行するエンジンを作成する。
let engine = Engine::default();
// Wasmインスタンスの状態を保持するStoreを作成する。
let mut store = Store::new(&engine, ());
// 学習用として、Wasmのテキスト表現であるWATを直接読み込む。
let wat = r#"
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
)
)
"#;
// WATをコンパイルしてWasmモジュールを生成する。
let module = Module::new(&engine, wat)?;
// 外部インポートを持たないため、空のインポート一覧で実体化する。
let instance = Instance::new(&mut store, &module, &[])?;
// Wasmが公開しているadd関数を、型付き関数として取得する。
let add = instance.get_typed_func::<(i32, i32), i32>(
&mut store,
"add",
)?;
// サンドボックス内の関数を呼び出す。
let result = add.call(&mut store, (40, 2))?;
println!("計算結果: {result}");
Ok(())
}
実行します。
cargo run
結果は次のようになります。
--- Wasmtimeホスト起動 ---
計算結果: 42
この例ではファイルやネットワークへ触れていません。
実務でWASIを使う場合は、必要なディレクトリ、標準入出力、環境変数などをホスト側で設定し、Wasmモジュールへ渡します。
7. 運用で詰まりやすいポイント
① バージョンを固定する
Wasmランタイムは更新が速く、APIやWASIの対応状況も変化します。
Cargo.toml、VPSへ導入するCLI、プラグイン、Wasmターゲットを記録し、開発環境と本番環境で同じ組み合わせを使います。
最新版を毎回追いかけるより、動作確認済みの組み合わせを一定期間固定する方が安定します。
② wasm32-wasiではなく現在のターゲット名を確認する
Rustの従来ターゲットwasm32-wasiは、現在ではwasm32-wasip1という名称へ移行しています。
古い記事のコマンドをそのまま使うと、ターゲットが見つからない場合があります。
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1
Component ModelやWASI Preview 2を採用する場合は、Preview 1と同じ手順ではありません。どのWASI世代を使うかを最初に決める必要があります。
③ 権限は必要なものだけ渡す
Wasmランタイムの隔離性を活かすには、ホスト側から無制限のファイルアクセスやネットワーク機能を渡さないことが重要です。
- 読み取り専用ディレクトリだけ許可する
- 書き込み先を専用spoolへ限定する
- APIキーをWasmへ直接埋め込まない
- タイムアウトとメモリ上限を設定する
- 呼び出しごとに追跡IDを発行する
銀翼の艦橋でWasmを使う場合も、現在のRustサービスが持つすべての権限を、そのままWasmモジュールへ渡してはいけません。
④ AI推論は依存関係まで設計する
WasmEdgeでWASI-NNを使う場合は、ランタイムだけでなく、プラグインと推論バックエンドの用意が必要です。
モデル形式、CPU・GPU、必要メモリ、プラグイン配置、バージョンをセットで管理します。
「WasmEdgeを入れればAIが即座に動く」のではなく、推論基盤を安全に接続しやすいランタイムだと捉える方が正確です。
8. 銀翼の艦橋での使い分け
銀翼の艦橋は、Rust製のOperations Core、記事生成・登録、WordPressキュー、GA4収集など、複数の機能を持っています。
現時点では、安定しているRust処理を無理にWasmへ置き換える必要はありません。
Wasm化の候補は、次のような交換可能な処理です。
- 記事本文の静的検査
- 禁止語や不足見出しの確認
- SEO設定の形式検証
- 外部から受け取ったデータの正規化
- 投稿前の小さな変換処理
- 将来追加するユーザー定義ルール
これらをWasmtimeで隔離実行すれば、Operations Core本体を再コンパイルせず、検査モジュールだけを交換できる設計へ発展できます。
一方、ローカルLLMによる分類や画像・音声処理などを導入する段階では、WasmEdgeとWASI-NNを使う専用ワーカーを別系統で検討できます。
つまり完成形は、巨大な一枚岩ではありません。
Operations Core
├─ 基幹API・DB・制御
├─ Wasmtime:標準的な検査・変換モジュール
└─ WasmEdge:将来のAI・特殊処理ワーカー
用途ごとにエンジンを分けることで、銀翼の艦橋は部品交換可能なシステムへ育っていきます。
9. まとめ
Wasmランタイムとは、Wasmバイナリを現実のサーバー上で実行するためのエンジンです。
- WasmをCPUが動かせる形へ変換する
- メモリと実行状態を管理する
- OS資源へのアクセスを制御する
- ホストアプリケーションとWasm関数を接続する
Wasmtimeは、標準仕様とRust連携を重視する基幹処理の第一候補です。
WasmEdgeは、クラウド・エッジ・プラグイン・AI推論などへ踏み込むときに力を発揮します。
銀翼の艦橋では、まずWasmtimeで小さな検査モジュールを動かし、必要になった段階でWasmEdgeを特殊処理へ追加する。この段階的な構成が、安全性と将来性を両立する航路です。