LabHub

ブログ

WebAssembly サーバーサイドと WASI 2026 徹底解剖 — Spin / Wasmtime / Wasmer / WasmEdge / wasmCloud / Extism / JCO / Component Model 完全ガイド

한국어English日本語

プロローグ — 2026 年、WASM は「ブラウザの速いアセンブリ」ではない

Docker 創業者 Solomon Hykes が 2019 年に残したツイートは、いまや引用を越えて現実になった。

「もし 2008 年に WASM+WASI が存在していたら、Docker を作る必要はなかった」

2026 年の WebAssembly は次のとおりだ。

本稿はその変化のど真ん中を 24-28 章で整理する。コードはすべて 2026 年 5 月時点で実際に動く形であり、引用 URL もすべて実在する。

一行要約: 「自分のコードはどこで、どんな権限で動くのか、それを誰が組み立てるのか」 — この二つの問いが 2026 年の WASM ツール選びの 90% を決める。


第 1 章 · WASM の本質を再確認 — アセンブリ・隔離・移植性

WebAssembly はしばしば「速いアセンブリ」と紹介されるが、本質は次の三軸だ。

意味結果
Portable bytecodeスタックマシン型の仮想 ISA同一バイナリがどこでも動く
Sandboxed by defaultホストメモリやシステムコールへ直接触れない信頼境界が明確
Deterministic浮動小数点 NaN を除けば決定的キャッシュ性・再現性が高い

ブラウザはあくまで第一の舞台だった。2017 年の MVP 以降、コア仕様は reference types、multi-value、bulk memory、SIMD、threads、tail call、GC、exception handling、multi-memory、function references まで拡張された。2026 年現在、GC と exception handling は主要ランタイムで安定化し、その上で Java・Kotlin・OCaml・Dart のような GC 言語が自然にコンパイルされる。

重要な発想転換: 2026 年の WASM は「C/Rust を速く回す VM」ではなく 「言語中立のコンポーネント ABI」 だ。だから次章の Component Model こそが本丸である。


第 2 章 · WASI Preview 1 と Preview 2 — POSIX 模倣からケーパビリティ・インターフェースへ

初期の WASI(WebAssembly System Interface)は POSIX の部分模倣だった。fd_read、fd_write、path_open のような関数が wasi_snapshot_preview1 インターフェースに平坦に並び、Rust の wasm32-wasi ターゲットがそれを呼んでいた。実質「ランタイムが貸してくれた POSIX」である。

WASI Preview 2(WASI 0.2)は違う。

これがまさに ケーパビリティベースのセキュリティ だ。周囲に漂う権限(ambient authority)は存在しない。モジュールは自分が import したことしかできない。コンテナの seccomp / capabilities / AppArmor よりはるかに明示的でコンポーザブルだ。

P1 → P2 の移行は 2025 年でほぼ完了した。Rust の wasm32-wasip2 ターゲット、TinyGo の wasip2、jco の P2 コンポーネント生成が標準経路である。


第 3 章 · Component Model — 言語中立 ABI という事件

Component Model は WASM に二層を追加する。

  1. Core module — 従来の .wasm。関数・メモリ・テーブル・グローバル。
  2. Component — 複数の core module を束ね、WIT 型(record、variant、list、option、result、resource、tuple、string)を外部インターフェースとして公開する。

Component Model が解決したのは 言語間の ABI 調停 だ。C と Rust はメモリを直接扱う。Go は GC を持つ。JavaScript は GC + JIT。これらは互いの関数を直接呼べない。Component Model はその中間に canonical ABI を置き、lift / lower で型を変換する。

WIT インターフェース定義の一片を見てみよう。

package example:greeter@0.2.0;

interface api {
    /// 挨拶文を組み立てる。
    greet: func(name: string) -> string;

    /// カウンタリソース。
    resource counter {
        constructor();
        increment: func();
        get: func() -> u64;
    }
}

world greeter {
    export api;
    import wasi:clocks/wall-clock@0.2.0;
    import wasi:logging/logging@0.2.0;
}

この WIT 一枚から:

呼び出し側は実装言語を知らない。それが Component Model の約束だ。


第 4 章 · Wasmtime — Bytecode Alliance のリファレンスランタイム

Wasmtime は Bytecode Alliance が手がける WASM の事実上のリファレンス実装である。Rust で書かれ、Cranelift コードジェンを通じて x86_64 / aarch64 / s390x へ AOT / JIT コンパイルする。

2026 年現在、Wasmtime 26.x が安定系列だ。主な特徴:

Wasmtime の真骨頂はホスト埋め込みのきれいさだ。Rust ホストがコンポーネントをロードして関数を呼ぶ流れ:

use wasmtime::{Engine, Config, Store};
use wasmtime::component::{Component, Linker};

fn main() -> anyhow::Result<()> {
    let mut config = Config::new();
    config.wasm_component_model(true);
    config.async_support(false);

    let engine = Engine::new(&config)?;
    let component = Component::from_file(&engine, "greeter.wasm")?;

    let mut linker = Linker::new(&engine);
    wasmtime_wasi::add_to_linker_sync(&mut linker)?;

    let wasi = wasmtime_wasi::WasiCtxBuilder::new()
        .inherit_stdio()
        .build_p1();
    let mut store = Store::new(&engine, wasi);

    let instance = linker.instantiate(&mut store, &component)?;
    let greet = instance.get_typed_func::<(String,), (String,)>(&mut store, "greet")?;
    let (out,) = greet.call(&mut store, ("WASI 2026".into(),))?;
    println!("{out}");
    Ok(())
}

このパターンは Spin・wasmCloud・Lambda Adapter がいずれも内部で変奏している。


第 5 章 · Wasmer — マルチバックエンドとパッケージマネージャとしての WASM

Wasmer は Wasmtime と毛色が違う。最初から 複数のコンパイラバックエンド(Cranelift、LLVM、Singlepass)を選べる設計で、WAPM(WebAssembly Package Manager)という npm 風の配布チャネルも備えている。

2026 年の Wasmer 5.x の強みは次のとおり。

Wasmer で Python を動かす一行:

wasmer run python/python --mapdir=/app:./app -- /app/main.py

WAPM は Component Model の上にパッケージを束ねる。2026 年に入って OCI レジストリ(GHCR、Docker Hub)との相互運用が加速し、ghcr.io に WASM コンポーネントを push する標準フローが確立した。

Wasmer の P2 対応は Wasmtime に少し遅れたが 5.x で追いついた。WASIX と P2 を一つのランタイムで扱える点が Wasmer の差別化だ。


第 6 章 · WasmEdge — クラウドネイティブと AI に特化したランタイム

WasmEdge は CNCF Sandbox から Incubating を経て、2025 年に Graduated に近いステータスを得た。CloudOS・CDN・AI 推論に特化した設計が特徴だ。

Docker Desktop 4.x 以降、WasmEdge は docker run --runtime=io.containerd.wasmedge.v1 一行で実行できる。Kubernetes では次のように RuntimeClass を定義する。

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: wasmedge
handler: wasmedge
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-wasm
spec:
  replicas: 3
  selector:
    matchLabels: { app: hello-wasm }
  template:
    metadata:
      labels: { app: hello-wasm }
    spec:
      runtimeClassName: wasmedge
      containers:
        - name: hello
          image: ghcr.io/example/hello-wasm:0.1.0

WasmEdge は「K8s で WASM を回すいちばん簡単な道」というポジショニングを明確に取っている。


第 7 章 · Spin(Fermyon) — WASM マイクロサービスのフレームワーク

Fermyon の Spin は「WASM 版の Express / Flask」と言ってよい。コンポーネント一つが HTTP ハンドラや Redis コンシューマや cron トリガとして動き、コンポーネント間は WIT で結ばれる。

Spin の中核要素:

最も単純な HTTP コンポーネントのマニフェスト:

spin_manifest_version = 2

[application]
name = "hello-spin"
version = "0.1.0"

[[trigger.http]]
route = "/hello/..."
component = "hello"

[component.hello]
source = "target/wasm32-wasip2/release/hello.wasm"
allowed_outbound_hosts = ["https://api.example.com"]
key_value_stores = ["default"]
sqlite_databases = ["default"]

[component.hello.build]
command = "cargo build --target wasm32-wasip2 --release"
watch = ["src/**/*.rs", "Cargo.toml"]

Spin は単一バイナリ(spin up)としてローカルで動き、Fermyon Cloud または Fermyon Platform for Kubernetes(spin-operator)経由でデプロイする。一言で言えば「WASM ネイティブのマイクロサービス運用体系」だ。

2026 年に入って Spin は LangChain / LlamaIndex 風の AI ワークフロー(spin-llm)と統合し、エッジ AI サーバーのカテゴリへ広がった。


第 8 章 · wasmCloud — 分散アクターモデルの上の WASM

wasmCloud は CNCF Incubating プロジェクトで、「WASM コンポーネント + アクターモデル + NATS メッセージング」を一式で提供する。中核の発想:

これはまさに依存性反転だ。コンポーネントは「Redis を呼ぶ」のではなく「wasi:keyvalue/store を呼ぶ」。その実体が Redis なのか NATS KV なのか Postgres なのかは、運用者が wadm(wasmCloud Application Deployment Manager)上でバインドする。

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: hello-wasmcloud
spec:
  components:
    - name: hello
      type: component
      properties:
        image: ghcr.io/example/hello:0.1.0
      traits:
        - type: spreadscaler
          properties:
            instances: 5
        - type: link
          properties:
            target: redis-kv
            namespace: wasi
            package: keyvalue
            interfaces: ["store"]
    - name: redis-kv
      type: capability
      properties:
        image: ghcr.io/wasmcloud/redis-kv:0.10.0

複数のクラウド・エッジ・オンプレに同じ lattice を伸ばせる点が wasmCloud の強みだ。Adobe・BMW・Bosch がカンファレンス事例で繰り返し登場する。


第 9 章 · Lunatic — Erlang / Elixir 由来の WASM ランタイム

Lunatic は BEAM(Erlang VM)のアクター・スーパーバイザツリー・プリエンプティブスケジューリングというアイデアを WASM に移したランタイムだ。Rust で書かれ、Wasmtime をコアに利用する。

特化領域は次のとおり。

Spin が「HTTP ハンドラの束」に近いとすれば、Lunatic は「WASM 版 BEAM」だ。両者は競合ではなく、異なるユースケースに住んでいる。


第 10 章 · Extism — ホストアプリに WASM プラグインを埋め込む標準

Extism は「自分のアプリを WASM プラグインで拡張したい」というたった一つの問題に集中する。Dylibso が OSS で開発している。

代表的なシナリオ:

Extism は Component Model の汎用性を一部譲って、ホスト統合の単純さ を取った。2026 年時点で Extism 1.x が安定版であり、OCI レジストリからプラグインを取得する extism call oci://... フローが標準化している。


第 11 章 · JCO と StarlingMonkey — JavaScript もコンポーネントになる

JCO(JavaScript Component Object)は Bytecode Alliance が作った JavaScript ↔ Component 変換ツールだ。2026 年現在 jco 1.x が安定版である。

主な機能:

StarlingMonkey は Mozilla の SpiderMonkey を組み込み形態に切り出したもので、Cloudflare workerd に続く次世代の JS-on-WASM ランタイムだ。Fastly Compute と Fermyon Spin が JS コンポーネントのランタイムとして StarlingMonkey を採用している。

JCO の真価は TypeScript 型の自動生成 にある。WIT ファイルから .d.ts を生成し、呼び出し側が全関数・全リソースに型安全にアクセスできる。

// app.js — jco componentize の入力
import { now } from 'wasi:clocks/wall-clock@0.2.0';
import { log } from 'wasi:logging/logging@0.2.0';

export const api = {
  greet(name) {
    const { seconds } = now();
    log('info', 'greeter', `now=${seconds}`);
    return `Hello, ${name}! It is now ${seconds}.`;
  },
};

このファイル一枚が jco を通せば、どのホスト(Wasmtime、Spin、wasmCloud、Cloudflare Workers)でも実行可能なコンポーネントになる。


第 12 章 · ポリグロットなコンパイル経路 — Rust、Go、C/C++、AssemblyScript、Python、Java、.NET

各言語の 2026 年標準コンパイル経路を短く整理する。

言語ツールターゲット備考
Rustrustc + cargo-componentwasm32-wasip2一級対応、最短経路
C/C++wasi-sdk(clang 19+)wasm32-wasip2wit-bindgen-c でコンポーネント化
GoTinyGo 0.34+wasip2標準 Go も wasip1 対応、wasip2 は TinyGo が速い
AssemblyScriptasc 0.27+wasm32TS ライクな構文、小さなバイナリ
JavaScriptjco + StarlingMonkeycomponent第 11 章参照
Pythoncomponentize-pycomponentCPython を WASM に梱包
JavaTeaVM、CheerpJ、Spasmwasm32-gcJVM バイトコードを WASM-GC へ
C# / .NETwasi-experimental + NativeAOTwasi.NET 9 で WASI P2 正式化が進行
Rubyruby.wasmwasiRuby 3.3+ 公式 WASM ビルド
Zigzig build -target wasm32-wasiwasiコンポーネント化は wasm-tools

特に Python・Java・.NET がコンポーネント化できるようになったのが 2024-2025 年の大きな変化だ。「C/Rust だけの領域」という認識はもう過去のものだ。


第 13 章 · WIT と wit-bindgen — インターフェース・ファースト開発

Component Model の本当の働き方は「まず WIT を書き、次に実装言語を選ぶ」という流れだ。

wit-bindgen は WIT を読んで各言語のバインディングを生成する。Rust 例:

wit_bindgen::generate!({
    world: "greeter",
    path: "./wit",
});

use exports::example::greeter::api::Guest;

struct Component;

impl Guest for Component {
    fn greet(name: String) -> String {
        format!("Hello, {name} from Rust WASM!")
    }
}

export!(Component);

ビルドは wasm-tools でコンポーネント化する。

cargo build --target wasm32-wasip2 --release
wasm-tools component new \
  target/wasm32-wasip2/release/greeter.wasm \
  -o greeter.component.wasm
wasm-tools validate greeter.component.wasm

生成された greeter.component.wasm は Wasmtime、Spin、jco、wasmCloud のどこで動かしても同一だ。これが Component Model の約束だ。


第 14 章 · Cloudflare Workers と WASM — V8 isolate の上のモジュール

Cloudflare Workers は V8 isolate を基本の隔離単位としつつ、WASM を一級モジュールとしてサポートする。

典型的な Rust → WASM → Workers の流れ:

cargo install wasm-pack
wasm-pack build --target web
wrangler deploy

Workers は強力だが、Component Model のあらゆる側面(任意のホスト import など)を扱うわけではない。Cloudflare は自前のビルトインバインディング(KV、R2、D1、Queues、AI、Durable Objects)を提供する形を取っている。


第 15 章 · Fastly Compute@Edge — WASM ファーストなエッジの原型

Fastly Compute@Edge は最初から WASM(Wasmtime ベース)の上に作られたエッジプラットフォームだ。V8 isolate を経由せず、直接 WASM インスタンスを起動する。

Fastly の強みは ロギング・リアルタイムメトリクスの充実 と SOC2 / PCI / HIPAA の認証範囲だ。メディア・EC・金融サービスが Fastly Compute に多く住んでいる。


第 16 章 · AWS Lambda Web Adapter と WASM — Lambda 上でコンポーネントを動かす

AWS Lambda は 2026 年現在、公式の WASM ランタイムを持たない。代わりに二つの迂回路が標準だ。

  1. AWS Lambda Web Adapter — Lambda のコンテナイメージ内に Wasmtime を組み込み、コンポーネントを実行する。awslabs/aws-lambda-web-adapter GitHub リポジトリ。
  2. Fermyon Spin on Lambda — Spin コンポーネントを Lambda Adapter でラップしてデプロイ。

Lambda の 350ms 級コールドスタートと Wasmtime のマイクロ秒級コールドスタートの差は、そのままユーザーの負担になる。だから本気の WASM エッジは Fastly・Cloudflare・Fermyon Cloud・Cosmonic・Wasmer Edge へ流れることが多い。

ただし AWS は Bedrock のユーザー定義関数 で WASM を受け入れる方向性を 2025 年後半に発表した。今後 1-2 年で Lambda + WASM が一級になる可能性は高い。


第 17 章 · Docker WASM と containerd-wasm-shims — コンテナなしの WASM

Docker Desktop は 4.15+ で WASM ワークロードを公式ベータとしてサポートし、2025 年に GA を迎えた。実装は containerd-shim-wasmtimecontainerd-shim-wasmedgecontainerd-shim-wasmercontainerd-shim-spin の四種類だ。

OCI イメージの中に WASM バイナリがあれば、ノードで --runtime=io.containerd.wasmedge.v1 のようなフラグ一行で WASM が走る。コンテナランタイムがコンテナではなく WASM インスタンスを起動するという意味だ。

Kubernetes でも RuntimeClass で同じことが可能だ。結果として一台のノードでコンテナと WASM が共存し、ワークロードの種類に応じてスケジューラが自動的に振り分ける。


第 18 章 · ケーパビリティ型セキュリティ — なぜ WASM はコンテナより狭い信頼境界なのか

コンテナの隔離は Linux カーネルの namespace + cgroup + seccomp + AppArmor の組み合わせだ。強力だが、信頼がカーネル一点に依存する。CVE 一件で隔離全体が崩れうる。

WASM の隔離は違う。

このモデルがコンテナよりも 狭い信頼境界 を生む。コンテナは「基本は全部あげる、そこから引け」、WASM は「基本は何もあげない、そこから足せ」のモデルだ。

エンタープライズのセキュリティチームにとって、この差は非常に大きい。マルチテナント SaaS、ユーザーコード実行(Cloudflare Workers、Replit、Modal)、信頼できないプラグイン — どのシナリオでも WASM はコンテナより安全な答えだ。


第 19 章 · 性能 — コールドスタート、JIT、AOT、そして pre-instantiation

WASM の性能を一行で答えるのは難しい。三つの段階を分けよう。

  1. コンパイル — .wasm バイトコードをネイティブコードへ変換。JIT(Wasmtime のデフォルト)vs AOT(WasmEdge・Wasmer LLVM・Wasmtime --cache)。
  2. インスタンス化 — コンパイル済みモジュールにメモリ・テーブル・グローバルを束ねて実行可能インスタンスを作る。
  3. 実行 — 実際の関数呼び出し。

コールドスタートの肝は pre-instantiation と pooling だ。

実行性能は LLVM バックエンドでネイティブ比 70-95%。SIMD・threads・tail call が効くワークロード(画像処理・暗号・ML 推論)は 90% 超もよくある。

コールドスタート比較(2026 年 5 月時点の報告値):

ランタイムコールドスタート
AWS Lambda(Node)約 350ms
Cloudflare Workers(JS isolate)約 5ms
Fastly Compute@Edge(WASM)1ms 未満
Wasmtime + pooling約 50µs
WasmEdge AOT約 30µs

第 20 章 · ポリグロットデモ — Rust でコンポーネント、JS から呼び出し

この章一つで Component Model の実用を見る。WIT は第 3 章の greeter をそのまま使う。

Rust 実装(src/lib.rs):

wit_bindgen::generate!({ world: "greeter", path: "./wit" });

use exports::example::greeter::api::{Counter, Guest, GuestCounter};
use std::cell::Cell;

struct Component;

impl Guest for Component {
    fn greet(name: String) -> String {
        format!("Hi, {name}!")
    }
    type Counter = CounterImpl;
}

struct CounterImpl(Cell<u64>);

impl GuestCounter for CounterImpl {
    fn new() -> Self { Self(Cell::new(0)) }
    fn increment(&self) { self.0.set(self.0.get() + 1); }
    fn get(&self) -> u64 { self.0.get() }
}

export!(Component);

ビルドと JS 側からの呼び出し:

cargo build --target wasm32-wasip2 --release
wasm-tools component new target/wasm32-wasip2/release/greeter.wasm -o greeter.wasm
jco transpile greeter.wasm -o out --name greeter
node -e "import('./out/greeter.js').then(m => { const c = new m.api.Counter(); c.increment(); c.increment(); console.log(m.api.greet('JS'), c.get()); })"

同じ .wasm を Spin・wasmCloud・Wasmtime CLI でもそのまま呼べる。ポリグロットの約束が紙の上ではなく実行可能なコードの上にあるという点が肝心だ。


第 21 章 · WASM と AI — LLM 推論と ggml on WASM

2024 年から本格化した流れだ。

WasmEdge ggml の魅力は モデルを OS / ハードウェア非依存に配布 できる点だ。Linux x86_64、macOS arm64、Raspberry Pi、AWS Graviton に同じ .wasm を投げ込めば、その場で推論が始まる。組み込み・エッジ AI のゲームチェンジャーだ。


第 22 章 · LINE / NHN Cloud / Cybozu — 韓国・日本の WASM 事例

韓国と日本の導入はインフラ・コンテンツ系企業が先導している。

事例の共通点は コンテナでは答えが出にくいマルチテナント・プラグイン・エッジ隔離 の問題に WASM が入ってきたことだ。


第 23 章 · 運用 — 観測、デバッグ、デプロイ

WASM が運用水準に到達した分、観測ツールも整ってきた。

デバッグはまだ進化途中だが、2025 年に入って DWARF デバッグ情報を保持した .wasm、wasmtime の --gdb モード、Chrome DevTools の WASM デバッガが組み合わさり、実務でも使える水準になった。AssemblyScript と Rust は DWARF 出力が良く、Go はまだ弱点が残る。

デプロイは OCI レジストリ(ghcr.io、docker.io)にコンポーネント .wasm を push し、Spin / wasmCloud / Knative が pull する GitOps フローが標準だ。


第 24 章 · 未来 — wasi-preview3、async / streams、wasi-gpu、wasi-threads

2026 年半ば時点で可視化されている次の一歩。

WASM はもはや単一仕様ではなく、IETF / W3C 風にインターフェースをガバナンスする多層エコシステムになった。


第 25 章 · 意思決定ツリー — 自分のワークロードにどのランタイムを選ぶか

最後に実用ガイド。

ワークロード推奨
エッジの HTTP APIFastly Compute@Edge、Cloudflare Workers、Spin + Fermyon Cloud
自社 K8s クラスタのサイドカーWasmEdge + RuntimeClass、Spin + spin-operator
分散マルチクラウドのマイクロサービスwasmCloud + NATS
AI 推論(エッジ / 組み込み)WasmEdge ggml、Wasmer + Burn
ホストアプリのプラグインExtism
並行性中心のサービスLunatic
ユーザーコード実行(マルチテナント)Wasmtime + epoch interruption + pooling
Lambda 上に載せるLambda Web Adapter + Wasmtime

選択の四軸:

  1. 信頼境界 — ユーザーのコードが入るか。入るなら WASM。
  2. コールドスタート — ms 未満が必要か。必要なら Fastly・Spin・WasmEdge AOT。
  3. 言語多様性 — ポリグロットか。なら Component Model 一級対応(Wasmtime / Spin / wasmCloud)。
  4. 運用モデル — K8s の標準に乗せたいか、PaaS に任せたいか。

この四問に答えれば、ツールはほぼ自動的に決まる。


第 26 章 · まとめ — 「Docker の次」ではなく「Docker の上の強い隔離」

WASM の未来をめぐって「コンテナを置き換えるのか」という問いが繰り返される。2026 年の現場の答えは明快だ — 置き換えではなく補完 だ。

両者は K8s ノード上に同居する。ワークロードの種類に応じて RuntimeClass が振り分ける。Solomon Hykes のツイートは「WASM が Docker を置き換えていたはずだ」ではなく 「WASM は Docker が解決してきた問題の一部を別のやり方で解ける」 という、より微妙な真実に近い。

本稿は 26 章でその「別のやり方」の全貌を描いた。WIT 一行を書くところから始まり — その一行が Rust・Go・JS・Python で実装され、Wasmtime・Spin・wasmCloud・Fastly・Cloudflare で同じ形で実行される — 2026 年の風景はそれらすべてが同時に可能になった時代だ。

「自分のコードはどこで、どんな権限で動くのか、そして誰がそれを組み立てるのか」。この二つの問いに明確に答えられるなら、私たちはいまやその答えを同じ .wasm 一つに収めて持ち歩ける。


References

コメント

まだコメントはありません。

ログインするとコメントできます