mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
2296 字
7 分钟
Wasm 容器:WasmEdge/WASI
2026-06-08

2023 年 3 月,Docker 宣布支持 Wasm 容器——你可以用 docker run 运行一个 .wasm 文件,就像运行 Linux 容器一样。这不是噱头,而是容器运行时演进的真实方向。

WebAssembly(Wasm)最初为浏览器设计,但它的沙箱隔离、跨平台、快速启动、小体积等特性,恰好解决了 Linux 容器的痛点:启动慢(需要创建 Namespace/Cgroup)、体积大(需要完整 rootfs)、安全弱(共享内核)。WASI(WebAssembly System Interface)定义了 Wasm 访问操作系统的标准接口,让 Wasm 可以在服务器端运行。

本章将深入 Wasm 容器的架构和实现,理解它如何与 OCI 规范集成,以及与 Linux 容器的对比。

WebAssembly 的故事始于浏览器。2017 年,W3C 将 WebAssembly 推荐为 Web 标准,它作为一种低级字节码格式,让 C/C++/Rust 等语言编译后的程序能在浏览器中以接近原生的速度运行。但 Wasm 的沙箱隔离、跨平台、快速启动等特性很快引起了服务端开发者的注意——如果 Wasm 能跑在浏览器之外呢?

2019 年,Fastly 的 Luke Wagner 提出 WASI(WebAssembly System Interface),定义了 Wasm 访问文件系统、网络、时钟等操作系统资源的标准接口。WASI 的出现让 Wasm 从浏览器走向了服务器。此后,WasmEdge、Fermyon Spin、runwasi 等运行时和工具相继涌现,让 Wasm 模块可以像容器一样运行。2023 年 3 月,Docker 官方宣布支持 Wasm 容器——docker run 可以直接运行 .wasm 文件,标志着容器运行时的边界从”Linux 进程”扩展到了”Wasm 模块”。容器不再只是 Linux 进程的隔离单元,Wasm 容器证明了:只要遵循 OCI 规范,任何运行时都可以成为容器。

前置知识#

  • Ch05 OCI 规范:Wasm 容器遵循 OCI 镜像规范和运行时规范,只是 payload 从 Linux rootfs 变成了 Wasm 模块
  • WebAssembly 基础概念:栈式虚拟机(基于操作数栈执行指令)、线性内存(一段连续的可寻址字节数组,Wasm 模块唯一的内存模型)、模块化(Wasm 程序以模块为单位,可导入/导出函数和内存)
Note

如果你不熟悉 WebAssembly,可以先阅读 Mozilla 的 WebAssembly 概念指南,了解 Wasm 的基本执行模型和核心概念后再继续阅读。

一、WebAssembly 基础#

1.1 Wasm 的核心特性#

特性说明对容器的意义
沙箱隔离Wasm 模块在独立沙箱中运行安全隔离,无需 Namespace
跨平台Wasm 字节码与平台无关一次编译,到处运行
快速启动Wasm 模块即时编译启动毫秒级启动
小体积Wasm 二进制比原生二进制更小镜像体积极小
确定性Wasm 执行是确定性的可重现的执行
线性内存Wasm 使用线性内存模型内存安全

1.2 Wasm 的执行模型#

graph TB subgraph Wasm模块["Wasm 模块 (.wasm)"] CODE["字节码指令"] MEMORY["线性内存"] TABLE["函数表"] GLOBAL["全局变量"] end subgraph 运行时["Wasm 运行时"] DECODE["解码 + 验证"] COMPILE["JIT/AOT 编译"] EXECUTE["执行"] SANDBOX["沙箱隔离"] end subgraph 主机环境["主机环境 (WASI)"] FS["文件系统"] NET["网络"] CLOCK["时钟"] ENV["环境变量"] end CODE --> DECODE DECODE --> COMPILE COMPILE --> EXECUTE EXECUTE --> SANDBOX SANDBOX --> FS SANDBOX --> NET SANDBOX --> CLOCK SANDBOX --> ENV style Wasm模块 fill:#bbdefb,stroke:#1565c0 style 运行时 fill:#c8e6c9,stroke:#2e7d32 style 主机环境 fill:#fff3e0,stroke:#e65100

1.3 Wasm vs Linux 容器#

维度Linux 容器Wasm 容器
隔离方式Namespace + CgroupWasm 沙箱
内核依赖依赖 Linux 内核不依赖(WASI 接口)
启动时间50-200ms1-10ms
镜像大小MB~GB 级KB~MB 级
语言支持任意语言Rust/C/C++/Go/Python/…
系统调用完整 Linux 系统调用WASI 子集
兼容性完整 Linux 兼容有限(无 fork/exec 等)

二、WASI:WebAssembly System Interface#

2.1 WASI 的设计目标#

WASI 定义了 Wasm 模块访问操作系统的标准接口,遵循最小权限原则——默认不允许任何操作,必须显式授权:

// Rust 编译为 Wasm + WASI
use std::fs::File;
use std::io::{Read, Write};
fn main() {
// 读取文件(需要 fs 权限)
let mut file = File::open("/app/data/input.txt").unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
// 写入文件(需要 fs 权限)
let mut output = File::create("/app/data/output.txt").unwrap();
output.write_all(content.as_bytes()).unwrap();
}

2.2 WASI 的核心接口#

接口功能类似 Linux
wasi_snapshot_preview1.fd_read读取文件描述符read()
wasi_snapshot_preview1.fd_write写入文件描述符write()
wasi_snapshot_preview1.path_open打开文件openat()
wasi_snapshot_preview1.path_filestat_get获取文件状态fstat()
wasi_snapshot_preview1.sock_accept接受连接accept()
wasi_snapshot_preview1.sock_recv接收数据recv()
wasi_snapshot_preview1.sock_send发送数据send()
wasi_snapshot_preview1.clock_time_get获取时间clock_gettime()
wasi_snapshot_preview1.environ_get获取环境变量getenv()
wasi_snapshot_preview1.proc_exit退出进程exit()

2.3 WASI 的权限模型#

# WasmEdge 的权限控制
wasmedge --env "KEY=VALUE" \
--dir /app/data:/host/data \ # 文件系统权限
--net host \ # 网络权限
myapp.wasm
# 只授予必要的权限(最小权限原则)
wasmedge --dir /app/data:/host/data:ro \ # 只读
myapp.wasm

2.4 WASI 能力与限制对比#

WASI 各子规范提供了不同的能力,但也有明确的边界限制:

WASI 子规范能力限制状态
wasi-fs文件读写、目录遍历无 inotify/fanotify,无 mmap 写稳定
wasi-clock系统时钟、随机数无高精度定时器稳定
wasi-socketsTCP/UDP 连接无 raw socket,无 packet socket稳定
wasi-httpHTTP 请求/响应处理仅 HTTP/1.1,无 HTTP/2 推送稳定
wasi-io异步 IO 流需 Component Model 支持草案
wasi-nn神经网络推理仅推理,无训练;依赖运行时插件稳定
wasi-crypto加密签名/哈希无 TLS 握手,无密钥管理草案
wasi-threads多线程共享内存无 fork/exec,无信号量稳定
Warning

WASI 最大的限制是没有进程管理能力——不能 fork、exec、signal,这意味着数据库(依赖 fork 做并发控制)和 Shell 工具(依赖 exec 调用子进程)无法在 Wasm 容器中运行。这是架构层面的取舍,不是实现缺陷。

2.5 WASI 的演进#

timeline title WASI 规范演进 2019 : wasi_snapshot_preview1<br/>基础文件/时钟/随机 2022 : WASI Threads<br/>多线程支持 2023 : WASI HTTP<br/>HTTP 请求处理 2023 : WASI Sockets<br/>网络套接字 2024 : WASI IO<br/>异步 IO 接口 2024 : Component Model<br/>组件化接口

三、Wasm 运行时#

3.1 WasmEdge#

WasmEdge 是 CNCF 孵化项目,专为云原生场景设计的 Wasm 运行时:

# 安装 WasmEdge
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
# 编译 Rust 为 Wasm
rustup target add wasm32-wasip2
cargo build --target wasm32-wasip2
# 运行 Wasm 模块
wasmedge target/wasm32-wasip2/debug/myapp.wasm
# 运行 HTTP 服务器
wasmedge --net host target/wasm32-wasip2/debug/myserver.wasm
# 服务器监听在 0.0.0.0:8080

3.2 WasmEdge 的架构#

graph TB subgraph 应用层["应用层"] WASM["Wasm 模块"] end subgraph WasmEdge["WasmEdge 运行时"] LOADER["Loader<br/>解码 + 验证"] VALIDATOR["Validator<br/>类型检查"] EXECUTOR["Executor<br/>JIT/AOT 执行"] STORE["Store<br/>运行时状态"] end subgraph WASI插件["WASI 插件"] WASI_FS["wasi-fs<br/>文件系统"] WASI_NET["wasi-socket<br/>网络"] WASI_HTTP["wasi-http<br/>HTTP"] WASI_NN["wasi-nn<br/>神经网络"] WASI_CRYPTO["wasi-crypto<br/>加密"] end WASM --> LOADER LOADER --> VALIDATOR VALIDATOR --> EXECUTOR EXECUTOR --> STORE EXECUTOR --> WASI_FS EXECUTOR --> WASI_NET EXECUTOR --> WASI_HTTP EXECUTOR --> WASI_NN EXECUTOR --> WASI_CRYPTO style 应用层 fill:#bbdefb,stroke:#1565c0 style WasmEdge fill:#c8e6c9,stroke:#2e7d32 style WASI插件 fill:#fff3e0,stroke:#e65100

3.3 其他 Wasm 运行时#

运行时特点适用场景
WasmEdgeCNCF 孵化,云原生服务器端应用
WasmtimeBytecode Alliance,标准实现通用 Wasm 运行
Wasmer多后端(Cranelift/LLVM)通用 Wasm 运行
WamrIntel 开源,轻量级嵌入式/IoT
V8Google,浏览器级性能Node.js/Deno

四、Wasm 容器与 OCI 集成#

4.1 runwasi:containerd 的 Wasm shim#

runwasi 是 containerd 的 Wasm shim,让 Wasm 模块可以通过 containerd/CRI 管理:

graph TB subgraph Kubernetes["Kubernetes"] KUBELET["Kubelet"] end subgraph containerd["containerd"] CRI_PLUGIN["CRI Plugin"] SHIM["containerd-shim-runwasi-v1"] end subgraph Wasm运行时["Wasm 运行时"] WASMEDGE["WasmEdge"] end subgraph Wasm模块["Wasm 模块"] APP["myapp.wasm"] end KUBELET --> CRI_PLUGIN CRI_PLUGIN --> SHIM SHIM --> WASMEDGE WASMEDGE --> APP style Kubernetes fill:#e8eaf6,stroke:#283593 style containerd fill:#c8e6c9,stroke:#2e7d32 style Wasm运行时 fill:#fff3e0,stroke:#e65100 style Wasm模块 fill:#ffcdd2,stroke:#c62828

4.2 Docker 的 Wasm 支持#

# 安装 Docker Wasm 集成
docker run --rm --runtime=io.containerd.wasmedge.v1 \
-wasi-dir /app/data \
myapp-wasmimage:latest
# Wasm 镜像的 Dockerfile
FROM scratch
COPY --from=builder /app/target/wasm32-wasip2/release/myapp.wasm /app.wasm
ENTRYPOINT ["/app.wasm"]

4.3 Wasm 镜像的 OCI 格式#

Wasm 镜像遵循 OCI Image Spec,但使用不同的媒体类型:

组件Linux 容器Wasm 容器
Config 媒体类型oci.image.config.v1+jsonoci.image.config.v1+json
Layer 媒体类型oci.image.layer.v1.tar+gzipapplication/wasm
层内容tar 归档(文件系统)Wasm 二进制
rootfs完整 Linux 文件系统不需要(Wasm 自包含)

五、Wasm 容器的应用场景#

5.1 场景对比#

场景Linux 容器Wasm 容器推荐
微服务成熟快速启动Wasm
Serverless/FaaS冷启动慢毫秒级启动Wasm
插件系统需要隔离天然沙箱Wasm
数据库完整兼容无 fork/execLinux
AI 推理GPU 支持wasi-nn看场景
全栈应用完整兼容有限兼容Linux

5.2 Wasm 容器的性能#

# 启动时间对比
# Linux 容器
time docker run --rm alpine echo hello
# real 0m0.350s
# Wasm 容器
time wasmedge myapp.wasm
# real 0m0.005s ← 快 70x
# 镜像大小对比
# Linux 容器: alpine = 7.3MB
# Wasm 容器: myapp.wasm = 2MB

六、动手实践#

6.1 构建和运行 Wasm 容器#

Note

Wasm 容器镜像通常只有几 MB(对比 Alpine 容器的 5MB+ 和 Ubuntu 容器的 70MB+),因为 Wasm 二进制不需要包含操作系统库。启动时间在毫秒级,因为不需要创建 Namespace 和 Cgroup——Wasm 沙箱本身就是隔离边界。

#!/bin/bash
# 构建和运行 Wasm 容器
# 1. 创建 Rust 项目
cargo new --name myapp myapp-wasm
cd myapp-wasm
# 2. 修改 Cargo.toml
cat > Cargo.toml << 'EOF'
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasi = "0.11"
EOF
# 3. 编写代码
cat > src/lib.rs << 'EOF'
use wasi::http::*;
#[no_mangle]
pub extern "C" fn _start() {
println!("Hello from Wasm container!");
}
EOF
# 4. 编译为 Wasm
rustup target add wasm32-wasip2
cargo build --target wasm32-wasip2 --release
# 5. 运行
wasmedge target/wasm32-wasip2/release/myapp.wasm
# Hello from Wasm container!
# 6. 构建 Docker Wasm 镜像
cat > Dockerfile << 'EOF'
FROM scratch
COPY --chmod=755 target/wasm32-wasip2/release/myapp.wasm /app.wasm
ENTRYPOINT ["/app.wasm"]
EOF
docker buildx build --platform wasm32-wasip2 -t myapp-wasm .

6.2 性能基准测试#

#!/bin/bash
# Wasm vs Linux 容器性能对比
echo "=== 启动时间 ==="
echo -n "Linux 容器: "
time (for i in {1..100}; do docker run --rm alpine echo hi > /dev/null; done) 2>&1 | grep real
echo -n "Wasm 容器: "
time (for i in {1..100}; do wasmedge myapp.wasm > /dev/null; done) 2>&1 | grep real
echo ""
echo "=== 镜像大小 ==="
echo -n "Linux 容器: "
docker images alpine --format "{{.Size}}"
echo -n "Wasm 容器: "
ls -lh myapp.wasm | awk '{print $5}'

七、Wasm 容器在 Kubernetes 中的部署#

7.1 使用 runwasi 部署 Wasm 工作负载#

# Kubernetes RuntimeClass for Wasm
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: wasmtime
handler: wasmtime
overhead:
podFixed:
memory: "10Mi"
cpu: "50m"
---
apiVersion: v1
kind: Pod
metadata:
name: wasm-app
spec:
runtimeClassName: wasmtime
containers:
- name: app
image: ghcr.io/example/myapp-wasm:latest
env:
- name: RUST_LOG
value: info

7.2 Wasm 容器的生态工具链#

工具功能项目
wasmtimeWasm 运行时Bytecode Alliance
WasmEdge云原生 Wasm 运行时CNCF
runwasicontainerd Wasm shimcontainerd
spinWasm 微应用框架Fermyon
wasm-packRust→Wasm 打包工具wasm-pack
wasmer通用 Wasm 运行时Wasmer

7.3 Wasm 组件模型(Component Model)#

Wasm Component Model 是 Wasm 的下一代模块化架构:

graph TB subgraph 组件模型["Wasm Component Model"] COMP1["组件 A<br/>(Rust 编写)"] COMP2["组件 B<br/>(Go 编写)"] COMP3["组件 C<br/>(Python 编写)"] INTERFACE["Wasm Interface<br/>(类型化接口)"] end COMP1 <--> INTERFACE COMP2 <--> INTERFACE COMP3 <--> INTERFACE style 组件模型 fill:#e0f2f1,stroke:#00695c

Component Model 的关键特性:

  • 跨语言互操作:不同语言编写的组件可以互相调用
  • 类型化接口:组件之间的接口有明确的类型定义
  • 版本化:组件可以独立版本化和升级
  • 可组合:小组件可以组合成大应用

7.4 Wasm 容器的未来方向#

方向说明进展
WASI HTTP原生 HTTP 服务器支持已实现
WASI NN神经网络推理已实现
WASI Crypto加密操作草案
WASI Threads多线程支持已实现
Garbage CollectionGC 语言支持已实现
Component Model组件化架构推进中

八、本章小结#

上一章深入探讨了镜像构建与 BuildKit。

特性Wasm 容器Linux 容器
隔离方式Wasm 沙箱Namespace + Cgroup
启动时间1-10ms50-200ms
镜像大小KB~MBMB~GB
内核依赖不依赖依赖 Linux 内核
兼容性有限(WASI 子集)完整 Linux
语言支持Rust/C/C++/Go/…任意语言
OCI 兼容(扩展媒体类型)
Tip

混合部署 Wasm 和 Linux 容器是当前最务实的方案——用 Wasm 容器跑 Serverless 函数和插件(利用快速启动+强隔离),用 Linux 容器跑数据库和有状态服务(利用完整兼容性)。Kubernetes 的 RuntimeClass 机制让这种混合部署非常自然。

Note

Wasm 容器不是要取代 Linux 容器,而是补充。在 Serverless、插件系统、边缘计算等场景中,Wasm 容器的快速启动、小体积、强隔离是独特优势。但在需要完整 Linux 兼容性的场景(数据库、系统工具),Linux 容器仍是最佳选择。


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

Wasm 容器:WasmEdge/WASI
https://blog.souloss.com/posts/container-runtime/wasm-containers/
作者
Souloss
发布于
2026-06-08
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
容器网络
容器运行时 容器网络的核心问题是——隔离的 Network Namespace 如何与外部通信?详细解读 veth pair(虚拟网卡对)、bridge(虚拟网桥)、iptables/NAT(地址转换)、CNI(容器网络接口)的完整链路,以及 Docker 的四种网络模式和 Kubernetes 的 Pod 网络模型——从「容器能 ping 通外网」到「理解每一条网络规则」。
2
容器存储
容器运行时 容器的可写层随容器删除而丢失,数据持久化需要 Volume。一网打尽容器存储的完整方案——Volume(绑定挂载/命名卷/tmpfs)、存储驱动(overlay2/devicemapper/btrfs)、CSI(容器存储接口)插件机制,以及 Kubernetes 的 PV/PVC/StorageClass 体系——从「docker run -v」到「理解容器存储的每一条挂载规则」。
3
容器在 Kubernetes 中
容器运行时 深入容器在 Kubernetes 中的运行机制——CRI 接口、Pod Sandbox 创建、多容器模式、Init Container、Sidecar 注入,以及 kubelet 如何通过 CRI 与容器运行时交互。
4
容器安全:seccomp/AppArmor/Capabilities
容器运行时 容器的安全边界在哪里?Namespace 提供视图隔离,但不阻止特权操作。从零讲透 Linux 安全模块在容器中的应用——Capabilities(权限细分)、seccomp(系统调用过滤)、AppArmor(文件访问控制),以及 rootless 容器的实现,让你理解容器的安全边界和加固方法。
5
综合实战:构建一个迷你容器运行时
容器运行时 综合实战——用 Go 从零构建一个迷你容器运行时——实现 Namespace 隔离(PID/Mount/UTS/IPC/Network)、Cgroup 资源限制(CPU/内存)、OverlayFS 分层文件系统、OCI Bundle 解析,最终实现一个能运行容器的 minirunc。将前 15 章的知识融会贯通,从「理解原理」到「动手实现」。