WebAssembly(WASM)是基于堆栈的虚拟机的二进制指令格局。用相熟的术语来说,WASM 是各种编程语言(例如 C,C ++,Rust 或 Golang)的编译指标,生成具备已知格局的紧凑二进制文件。Mozilla 开发人员称 WebAssembly 对 Web 平台具备微小的意义 – 它提供了一种以近乎本机的速度在 Web 上运行以多种语言编写的代码的形式。
这里的最大含意是可能以靠近本机的速度在 Web 上执行模块。过来应用 JavaScript 编写时性能低下的工作能够用高性能编程语言(例如 C ++ 或 Rust)来重写。
然而 WebAssembly 不仅实用于 Web。WebAssembly 零碎接口我的项目(WASI)旨在通过提供操作系统工作的形象来标准化 WebAssembly 以在 Web 内部运行。这带来了两个次要长处:可移植性和安全性。明天,您能够应用 wasmtime 之类的运行时,在具备对文件系统和网络的细粒度拜访的沙盒环境中,在各种操作系统(Linux,macOS,Windows)上执行 WASM 模块。
咱们认真想想,这些劣势不正是现在如日中天的容器具备的劣势吗?
WASI 能够为容器生态系统提供一个十分乏味的代替办法 - 然而对于本文,咱们仅探讨如何散发 WebAssembly 模块。
应用 OCI 注册核心散发 WebAssembly 模块
目前,有两种调配 WebAssembly 模块的办法 – wasm-pack(应用 NPM 来存储模块)或 WAPM(独立于编程语言和工具链,但仍是一个十分晚期的工具,尚未在其内部宽泛采纳)。然而,如果咱们认为 WebAssembly 是 Linux 容器的潜在跨平台替代品,那么咱们还须要一种独立于编程语言和工具链的散发形式。为何不齐全应用 OCI 注册核心散发容器镜像的办法呢?
此外,OCI 最近发表了 OCI Artifacts 我的项目,该我的项目旨在扩大 OCI 注册管理机构标准并存储其余云原生工件(思考 Helm 图表或 CNAB 捆绑软件)。具备间接的长处 – 一种统一的形式来调配多个工件类型,应用曾经存在的注册表服务或重用和扩大以后的平安模型(例如 TUF)。
ORAS(OCI 注册表存储)是 OCI Artifacts 我的项目的拟议施行,可显著简化 OCI 注册表中任意内容的存储。因而,咱们能够应用 ORAS 客户端库来构建一个非常简单的工具,以将 WebAssembly 模块推入和推到 OCI 注册表中。
然而请留神,以后,大多数注册表服务都回绝未知的工件类型 –ORAS 已通过开源 Docker Distribution 我的项目和 Azure Container Registry 进行了测试。
第一步是定义要与 WebAssembly 模块关联的媒体类型 – 这有助于辨认工件类型,能够在配置注册表以显式容许或不容许存储它们时应用。
ConfigMediaType = "application/vnd.wasm.config.v1+json"
ContentLayerMediaType = "application/vnd.wasm.content.layer.v1+wasm"
为了推送,咱们读取了模块的内容,将它们作为单个层增加到 OCI 描述符中,而后应用oras.Push
:
contents, err := ioutil.ReadFile(module)
desc := store.Add(module, ContentLayerMediaType, contents)
layers := []ocispec.Descriptor{desc}
pushOpts := []oras.PushOpt{oras.WithConfigMediaType(ConfigMediaType),
oras.WithNameValidation(nil),
}
manifest, err := oras.Push(ctx, resolver, ref, store, layers, pushOpts...)
拉取同样简单明了 – 咱们应用 oras.Pull
来获取 OCI 清单和理论模块,而后将其写入文件中:
pullOpts := []oras.PullOpt{oras.WithAllowedMediaType(ContentLayerMediaType),
oras.WithPullEmptyNameAllowed(),}
_, layers, err := oras.Pull(ctx, resolver, ref, store, pullOpts...)
manifest, contents, _ := store.Get(layers[0])
ioutil.WriteFile(outFile, contents, 0755)
能够在 GitHub 上找到 Go 软件包和一个 wasm-to-oci
实用程序。
应用 OCI 注册表进行测试
咱们有一个本地模块(能够在 repo 的 testdata
目录中找到),并且咱们应用 wasm-to-oci
推送到咱们以后登录的 Azure 容器注册表存储库(应用 Docker CLI):
$ ls
.rwxr-xr-x 1.6M radu hello.wasm
$ wasm-to-oci push hello.wasm <oci-registry>.azurecr.io/wasm-to-oci:v1
Pushed: <oci-registry>.azurecr.io/wasm-to-oci:v1
Size: 1624962
Digest: sha256:4c7915b4c1f9b0c13f962998e4199ceb00db39a4a7fa4554f40ae0bed83d9510
此时,咱们能够应用雷同的实用程序从刚刚推送的存储库中提取信息,而后应用抉择的 WebAssembly 运行时执行模块:
$ wasm-to-oci pull <oci-registry>.azurecr.io/wasm-to-oci:v1 --out test.wasm
Pulled: <oci-registry>.azurecr.io/wasm-to-oci:v1
Size: 1624962
Digest: sha256:4c7915b4c1f9b0c13f962998e4199ceb00db39a4a7fa4554f40ae0bed83d9510
$ wasmtime test.wasm
Hello from WebAssembly!
$ wasmer run test.wasm
Hello from WebAssembly!
咱们能够查看生成的 OCI 清单,并查看咱们之前设置的媒体类型,以及清单和理论模块的摘要和大小:
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.wasm.config.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2
},
"layers": [
{
"mediaType": "application/vnd.wasm.content.layer.v1+wasm",
"digest": "sha256:4c7915b4c1f9b0c13f962998e4199ceb00db39a4a7fa4554f40ae0bed83d9510",
"size": 1624962
}
]
}
论断
这是将 WASM 存储在 OCI 注册核心的乏味概念证实。如果您当初正在 Web 上应用 WebAssembly,则很可能不须要它,然而在 WASI 的状况下,它很有用,尤其是思考到 WebAssembly 的 container shim 程序。
PS: 本文属于翻译,原文