WebAssembly(也称为 Wasm)作为一种可移植的二进制指令格式而广受欢迎,它为客户端和服务器应用程序提供了可嵌入且隔离的执行环境。可以将 WebAssembly 视为一个小型、快速、高效且非常安全的基于堆栈的虚拟机,旨在执行可移植的字节码,而无需关心它在哪个 CPU 或操作系统上运行。WebAssembly 最初是为 Web 浏览器设计的,旨在成为函数的一个轻量级、快速、安全和多语言的容器,但它不再局限于 Web。
在 Web 上,WebAssembly 使用浏览器提供的现有 API。WebAssembly 系统接口 (WASI) 的创建是为了填补 WebAssembly 与浏览器外部运行的系统之间的空白。这使得非浏览器系统能够利用 WebAssembly 的可移植性,使 WASI 成为在分发时实现可移植性并在运行工作负载时实现隔离的良好选择。
WebAssembly 提供了几个优势。由于它是平台中立的,因此可以编译单个二进制文件并在各种操作系统和架构上同时执行,且磁盘占用空间和启动时间非常低。有用的安全功能包括模块签名和可在运行时级别控制的安全旋钮,而不是依赖于主机操作系统的用户权限。沙盒内存仍然可以由现有的容器工具基础设施管理。
在本文中,我将介绍一个配置 容器运行时 以从轻量级容器镜像运行 Wasm 工作负载的场景。
在云基础设施上的采用和阻碍
WebAssembly 和 WASI 是相当新的技术,因此在容器生态系统中原生运行 Wasm 工作负载的标准尚未制定。本文仅介绍一种解决方案,但还有其他可行的方法。
一些解决方案包括将原生 Linux 容器运行时切换为与 Wasm 兼容的组件。例如,Krustlet v1.0.0-alpha1 允许用户引入 Kubernetes 节点,其中 Krustlet 用作标准 kubelet 的替代品。这种方法的局限性在于,用户必须在 Linux 容器运行时和 Wasm 运行时之间做出选择。
另一种解决方案是使用带有 Wasm 运行时的基础镜像并手动调用编译后的二进制文件。但是,这种方法会使容器镜像因运行时而变得臃肿,如果我们在低于容器运行时的级别原生调用 Wasm 运行时,则这不一定是必需的。
我将描述如何通过创建混合设置来避免这种情况,在该设置中,现有的开放容器倡议 (OCI) 运行时可以同时运行原生 Linux 容器和 WASI 兼容的工作负载。
在 Wasm 和 Linux 容器的混合设置中使用 crun
通过允许现有的 OCI 运行时在较低级别调用 Linux 容器和 Wasm 容器,可以轻松解决上面讨论的一些问题。这避免了诸如依赖容器镜像来携带 Wasm 运行时或引入仅支持 Wasm 容器的基础设施新层等问题。
一个可以处理此任务的容器运行时:crun。
Crun 速度快、内存占用低,并且是完全符合 OCI 标准的容器运行时,可以用作现有容器运行时的直接替代品。Crun 最初是为运行 Linux 容器而编写的,但它也提供处理程序,能够在容器沙箱内的原生方式运行任意扩展。
这是一种用 crun 替换现有运行时的非正式方式,只是为了展示 crun 是现有 OCI 运行时的完整替代品。
$ mv /path/to/exisiting-runtime /path/to/existing-runtime.backup
$ cp /path/to/crun /path/to/existing-runtime
其中一个处理程序是 crun-wasm-handler
,它将特别配置的容器镜像(Wasm 兼容镜像)委托给现有 Wasm 运行时的部分,这些部分在 crun 沙箱内以原生方式运行。这样,最终用户无需自行维护 Wasm 运行时。
Crun 与 wasmedge
、wasmtime
和 wasmer
原生集成,以开箱即用地支持此功能。当 crun 检测到配置的镜像是否包含任何 Wasm/WASI 工作负载时,它会动态调用这些运行时的部分,并且它在执行此操作时仍然支持原生 Linux 容器。
有关构建具有 Wasm/WASI 支持的 crun 的详细信息,请参阅 GitHub 上的 crun 存储库。
在 Podman 和 Kubernetes 上使用 Buildah 构建和运行 Wasm 镜像
用户可以使用 crun 作为底层 OCI 运行时,在 Podman 和 Kubernetes 上创建和运行平台无关的 Wasm 镜像。这是一个教程
使用 Buildah 创建 Wasm 兼容镜像
Wasm/WASI 兼容镜像很特殊。它们包含一个魔术注解,可帮助像 crun 这样的 OCI 运行时对它是 Linux 原生镜像还是具有 Wasm/WASI 工作负载的镜像进行分类。然后,它可以在需要时调用处理程序。
使用任何容器镜像构建工具创建这些 Wasm 兼容镜像都非常容易,但在本文中,我将演示如何使用 Buildah。
1. 编译您的 .wasm
模块。
2. 使用您的 .wasm
模块准备一个 Containerfile。
FROM scratch
COPY hello.wasm /
CMD ["/hello.wasm"]
3. 使用 Buildah 和注解 module.wasm.image/variant=compat
构建 Wasm 镜像
$ buildah build --annotation "module.wasm.image/variant=compat" -t mywasm-image
一旦构建了镜像并且容器引擎配置为使用 crun,crun 将自动执行必要的操作,并通过配置的 Wasm 处理程序运行提供的工作负载。
使用 Podman 运行 WASM 工作负载
Crun 是 Podman 的默认 OCI 运行时。Podman 包含利用大多数 crun 功能的旋钮和句柄,包括 crun Wasm 处理程序。一旦构建了 Wasm 兼容镜像,它就可以像任何其他容器镜像一样被 Podman 使用
$ podman run mywasm-image:latest
Podman 使用 crun 的 Wasm 处理程序运行请求的 Wasm 兼容镜像 mywasm-image:latest
,并返回输出,确认我们的工作负载已执行。
$ hello world from the webassembly module !!!!
Kubernetes 支持和测试的容器运行时接口 (CRI) 实现
以下是如何配置两个流行的容器运行时
CRI-O
- 通过编辑
/etc/crio/crio.conf
中的配置,将 CRI-O 配置为使用 crun 而不是 runc。红帽 OpenShift 文档包含有关 配置 CRI-O 的更多详细信息。 - 使用
sudo systemctl restart crio
重启 CRI-O。 - CRI-O 自动将 Pod 注解传播到容器规范。
Containerd
- Containerd 支持通过在
/etc/containerd/config.toml
定义的自定义配置来切换容器运行时。 - 通过确保运行时二进制文件指向 crun,将 containerd 配置为使用 crun。更多详细信息请参见 containerd 文档。
- 配置 containerd 以允许 Wasm 注解,以便可以通过在配置中设置
pod_annotations
将其传播到 OCI 规范:pod_annotations = ["module.wasm.image/variant.*"]
。 - 使用
sudo systemctl start containerd
重启 containerd。 - 现在 containerd 应该将 Wasm Pod 注解传播到容器。
以下是 Kubernetes Pod 规范的示例,该规范适用于 CRI-O 和 containerd
apiVersion: v1
kind: Pod
metadata:
name: pod-with-wasm-workload
namespace: mynamespace
annotations:
module.wasm.image/variant: compat
spec:
containers:
- name: wasm-container
image: myrepo/mywasmimage:latest
已知问题和解决方法
复杂的 Kubernetes 基础设施包含 Pod,在许多情况下,还包含带有 sidecar 的 Pod。这意味着当部署包含 sidecar 并且 sidecar 容器不包含 Wasm 入口点时,例如具有 Linkerd、Gloo 和 Istio 等服务网格或 Envoy 等代理的基础设施设置,crun 的 Wasm 集成就无用武之地。
您可以通过为 Wasm 处理程序添加两个智能注解来解决此问题:compat-smart
和 wasm-smart
。这些注解充当智能开关,仅在容器需要时才切换 Wasm 运行时。因此,在运行带有 sidecar 的部署时,只有包含有效 Wasm 工作负载的容器才由 Wasm 处理程序执行。常规容器像往常一样处理,并委托给原生 Linux 容器运行时。
因此,在为此类用例构建镜像时,请使用注解 module.wasm.image/variant=compat-smart
而不是 module.wasm.image/variant=compat
。
您可以在 GitHub 上的 crun 文档 中找到其他已知问题。
评论已关闭。