【Docker社区大会】WebAssembly:无需容器的 Docker——VMware技术总监 Daniel Lopez

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

本文授权翻译自 Wasm Labs @ VMware OCTO 的 blog WebAssembly: Docker without container。这是 Wasm Labs 在 2022 年 12 月 15 日在冬季Docker Community All Hands 7 的关于 Docker+WebAssembly 的演讲的文字版。
作者Asen AlexandrovWasm Labs 工程师
文中的我们均指作者或 Wasm Labs。本文先做概念阐释如 Wasm 是什么Wasm 与 Docker 的关系是什么之后以 PHP 为例带领大家实践 Docker + Wasm。

最近Docker 宣布与 WasmEdge 合作支持 WebAssembly

本文将解释什么是 WebAssemblyWasm为什么它与 Docker 生态相关并提供一些实践示例供大家尝试。 我们假设你已经熟悉 Docker 工具。 我们将使用我们在 PHP 的 WebAssembly 端口上做的工作来演示如何构建 PHP 解释器将其打包为 OCI 镜像的一部分并使用 Docker 运行它。

请注意本文专注动手经验而不是讨论技术细节。

WebAssembly 是什么为什么选它

本节是对 WebAssembly 非常基本的介绍。 已经熟悉 Wasm 的小伙伴可以快速重温一下。

什么是 WebAssembly?

WebAssembly 是一种定义二进制指令格式的开放标准它支持从不同的源语言创建可移植的二进制可执行文件。 这些二进制文件可以在各种环境中运行。 它起源于 Web并得到各大主流浏览器的支持。

Wasm 如何在浏览器中工作

浏览器引擎集成了一个 Wasm 虚拟机通常称为 Wasm 运行时可以运行 Wasm 二进制指令。 编译器工具链如 Emscripten可以将源代码编译为 Wasm 目标。 这允许将现有的应用程序移植到浏览器并直接与在客户端 Web 应用程序中运行的 JS 代码通信。

这些技术能让传统的桌面应用程序在浏览器中运行。现在它们可以在任何装了浏览器的设备上运行。 一些著名的例子包括 Google Earth 和用于计算机视觉的 Open CV库。

Wasm 如何在服务器上运行

除了浏览器也有可以在浏览器之外运行的 Wasm 运行时包括 Linux、Windows 和 macOS 等传统操作系统。 因为无法依赖可用的 JavaScript 引擎所以他们使用不同的接口与外界通信例如 WASIWebAssembly 系统接口。 这些运行时允许 Wasm 应用程序以与 POSIX 类似但不完全相同的方式与其 host 系统交互。 WASI SDK 和 wasi-libc 等项目帮助人们将现有的兼容 POSIX 的应用程序编译为 WebAssembly。

你只需将应用程序编译成 Wasm 模块一次然后这个同样的二进制文件就可以在任何地方运行。

Wasm 厉害在哪里

下面这些特性让 Wasm 在浏览器大放异彩也使得它用在服务端开发颇具优势

开放——它是业界广泛采用的标准。 与过去的浏览器争夺战相反各大公司正积极合作实现 WASI 和 WebAssembly 应用程序的标准化。

快速——它可以通过大多数运行时的 JIT/AOT 能力提供类似原生的速度。 与启动 VM 或启动容器不同的是它没有冷启动。

安全——默认情况下Wasm 运行时是沙箱化的允许安全访问内存。 基于能力的模型确保 Wasm 应用程序只能访问得到明确允许的内容。软件供应链更加安全。

可移植——几个主要的 Wasm 运行时支持大多数 CPUx86、ARM、RISC-V和大多数操作系统包括 Linux、Windows、macOS、Android、ESXi甚至非 Posix 操作系统。

高效——最小的内存占用和最低的 CPU 门槛就能运行 Wasm 应用程序。

️ 支持多语言——40 多种编程语言可以编译成 Wasm有现代的、不断改进的工具链。

服务器平台发展的下一步是什么

也许你已经看过 Solomon Hykes (Docker的创始人之一)这句话

如果在2008年已经有了 WASM + WASI我们根本不需要创建 Docker。 Wasm 就有这么重要。 服务端的 WebAssembly 是计算的未来。

事实上WASM+WASI 似乎的确是服务端软件基础设施发展的下一步。

  • 最早我们有物理硬件可以使用。 我们会给机房里每个服务器精心安装操作系统和应用程序并一一维护。
  • 然后随着 VMware 开创的 VM 的采用一切变得更容易了。 人们可以跨硬件机器复制、克隆和移动虚拟机。 但这仍然需要在 VM 中安装操作系统和应用程序。
  • 随后出现了由 Docker 推广的容器这使得在最小打包的上下文下运行应用程序配置变得更加容易而不会影响主机操作系统上的任何其他应用程序。 但是仍然需要分发与其运行时和必要的库捆绑在一起的应用程序。 安全边界由 Linux 内核提供。
  • 现在有了 WebAssembly。 它的技术特性和可移植性使得分发应用程序成为可能无需 ship 操作系统级别的依赖项并且可以在严格的安全约束下运行。

鉴于所有这些开发者通常将 WebAssembly 视为容器的“继承者”以及基础设施部署的自然而然的下一步。

然而另一种看待 WebAssembly 的方式是将其作为 Docker 工具的另一个“后端”选择。 可以使用相同的命令行工具和工作流替代 Linux 容器使用基于 WebAssembly 的容器等同等的东西来实现。 本文的其余部分探讨了这个概念这就是标题所说的“没有容器的 Docker”。

Wasm 如何结合 Docker 运行

Docker Desktop 现在加入了对 WebAssembly 的支持。 它是通过 containerd shim 实现的该 shim 可以使用名为 WasmEdge 的 Wasm 运行时来运行 Wasm 应用程序。 这意味着现在可以在 WasmEdge 运行时模拟容器中运行 Wasm 应用程序而不是用典型的 Windows 或 Linux 容器运行容器镜像中二进制文件的单独进程。

因此容器镜像不需要包含正在运行的应用程序的操作系统或运行时上下文——单个 Wasm 二进制文件就足够了。

这在 Docker 的 Wasm 技术预览文章中有详细解释。

WasmEdge 是什么?

WasmEdge 是一个高性能的 WebAssembly 运行时

  • 是开源的属于 CNCF
  • 支持所有主要的 CPU 架构x86、ARM、RISC-V。
  • 支持所有主要操作系统Linux、Windows、macOS以及其他操作系统例如 seL4 RTOS、Android。
  • 针对云原生和边缘应用程序进行了优化。
  • 可扩展并支持标准和新兴技术
    • 使用 Tensorflow、OpenVINO、PyTorch 进行人工智能推理
    • Tokio 的异步网络。 支持微服务、数据库客户端、消息队列等。
    • 与容器生态、Docker 和 Kubernetes 无缝集成如本文所示

解释型语言呢

到目前为止我们只提到了 C 和 Rust 等编译语言可以编译为 WebAssembly。 对于 Python、Ruby 和 PHP 等解释型语言方法有所不同它们的解释器是用 C 语言编写的可以编译为 WebAssembly。 然后这个解释器编译成的 Wasm 可以用来执行源代码文件通常以 .py、.rb、.php 等结尾。 一旦编译为 Wasm任何带有 Wasm 运行时的平台都将能够运行这些解释型语言即使实际的解释器从未为该平台原生编译过。

下面将介绍如何将 PHP 解释器编译 Wasm 并打包成 OCI 镜像并使用内置了 WasmEdge 的 Docker Desktop 运行这个 OCI 镜像我们也将介绍传统容器与 Wasm 容器的不同之处。

动手示例

让我们开始吧 在动手示例中我们将使用编译为 Wasm 的 PHP 解释器。 我们会

  • 构建一个 Wasm 容器。
  • 比较 Wasm 和原生二进制文件。
  • 比较传统容器和 Wasm 容器。
  • 展示 Wasm 的可移植性

前期准备

如果想在本地重现这些示例你需要使用以下部分或全部内容来准备你的环境

  • WASI SDK - 从构建 C 代码构建 WebAssembly 应用程序
  • PHP - 为了比较而运行本机 PHP 二进制文件
  • WasmEdge Runtime - 运行 WebAssembly 应用程序
  • Docker Desktop + Wasm (本文写作时作为稳定 beta 版在 Docker Desktop4.15版可用) - 能够运行 Wasm 容器

我们还充分运用 webassembly-language-runtimes repo它提供了将 PHP 解释器构建为 WebAssembly 应用程序的方法。 可以像这样查看 demo 分支

git clone --depth=1 -b php-wasmedge-demo \
   https://github.com/vmware-labs/webassembly-language-runtimes.git wlr-demo
cd wlr-demo

构建一个 Wasm 容器

第一个示例我们将展示如何构建基于 C 的应用程序例如 PHP 解释器。

该构建使用 WASI-SDK 工具集。 它包括一个可以构建到 wasm32-wasi 目标的 clang 编译器以及在 WASI 之上实现基本 POSIX 系统调用接口的 wasi-libc。 使用 WASI SDK我们可以从 PHP 的代码库中构建一个用 C 编写的 Wasm 模块。之后我们需要一个非常简单的基于 scratch 的 Dockerfile 来制作一个可以使用 Docker+Wasm 运行的 OCI 镜像。

构建一个 WASM 二进制码

假设你现在位于 wlr-demo 文件夹这是前期准备工作的一部分可以运行以下命令来构建 Wasm 二进制文件。

export WASI_SDK_ROOT=/opt/wasi-sdk/
export WASMLABS_RUNTIME=wasmedge

./wl-make.sh php/php-7.4.32/ && tree build-output/php/php-7.4.32/bin/

... ( a few minutes and hundreds of build log lines)几分钟和数百行构建日志

build-output/php/php-7.4.32/bin/
├── php-cgi-wasmedge
└── php-wasmedge

PHP 是用 autoconf 和 make 构建的。 所以如果你看一眼脚本 scripts/wl-build.sh 你会注意到我们设置了所有相关变量如 CCLD、 CXX 等以使用来自 WASI_SDK 的编译器。

export WASI_SYSROOT="${WASI_SDK_ROOT}/share/wasi-sysroot"
export CC=${WASI_SDK_ROOT}/bin/clang
export LD=${WASI_SDK_ROOT}/bin/wasm-ld
export CXX=${WASI_SDK_ROOT}/bin/clang++
export NM=${WASI_SDK_ROOT}/bin/llvm-nm
export AR=${WASI_SDK_ROOT}/bin/llvm-ar
export RANLIB=${WASI_SDK_ROOT}/bin/llvm-ranlib

然后进一步深入查看 php/php-7.4.32/wl-build.sh可以看到像通常一样我们使用 autoconf 构建过程。

./configure --host=wasm32-wasi host_alias=wasm32-musl-wasi \
   --target=wasm32-wasi target_alias=wasm32-musl-wasi \
   ${PHP_CONFIGURE} || exit 1
...
make -j ${MAKE_TARGETS} || exit 1

WASI 是一项正在进行的工作许多 POSIX 调用仍然不能在它之上实现。 因此要构建 PHP我们必须在原始代码库之上应用多个补丁。

我们在上面看到输出二进制文件会转到 build-output/php/php-7.4.32。 在下面的示例中我们将使用专门为 WasmEdge 构建的 php-wasmedge 二进制文件因为它提供服务端 socket 支持服务端 socket 支持还不是 WASI 的一部分

优化二进制码

Wasm 是一个虚拟指令集因此任何运行时的默认行为都是即时解释这些指令。 当然这在某些情况下可能会让速度变慢。 因此为了通过 WasmEdge 获得两全其美的效果你可以创建一个 AOT提前编译优化的二进制文件它可以在当前机器上原生运行但仍然可以在其他机器上进行解释。

要创建优化的二进制文件请运行以下命令

wasmedgec --enable-all --optimize 3 \
   build-output/php/php-7.4.32/bin/php-wasmedge \
   build-output/php/php-7.4.32/bin/php-wasmedge-aot

我们在下面的例子中使用这个 build-output/php/php-7.4.32/bin/php-wasmedge-aot 二进制码。要了解有关 WasmEdge AOT 优化二进制文件的更多信息请查看这里。

构建 OCI 镜像

现在我们有了一个二进制文件我们可以将它包装在一个 OCI 镜像中。 让我们看一下这个 images/php/Dockerfile.cli。 我们需要做的就是复制 Wasm 二进制文件并将其设置为 ENTRYPOINT

FROM scratch
ARG PHP_TAG=php-7.4.32
ARG PHP_BINARY=php
COPY build-output/php/${PHP_TAG}/bin/${PHP_BINARY} /php.wasm

ENTRYPOINT [ "php.wasm" ]

我们还可以在镜像添加更多内容当 Docker 运行它时Wasm 二进制文件可以访问这些内容。 例如在 images/php/Dockerfile.server 中我们还添加了一些 docroot 内容在容器启动时由 php.wasm 提供服务。

FROM scratch
ARG PHP_TAG=php-7.4.32
ARG PHP_BINARY=php
COPY build-output/php/${PHP_TAG}/bin/${PHP_BINARY} /php.wasm
COPY images/php/docroot /docroot

ENTRYPOINT [ "php.wasm" , "-S", "0.0.0.0:8080", "-t", "/docroot"]

基于以上文件我们可以轻松地在本地构建我们的 php-wasm 镜像。

docker build --build-arg PHP_BINARY=php-wasmedge-aot -t ghcr.io/vmware-labs/php-wasm:7.4.32-cli-aot -f images/php/Dockerfile.cli .
docker build --build-arg PHP_BINARY=php-wasmedge-aot -t ghcr.io/vmware-labs/php-wasm:7.4.32-server-aot -f images/php/Dockerfile.server .

原生 vs Wasm

现在让我们将原生 PHP 二进制文件与 Wasm 二进制文件在本地和 Docker 容器中分别进行比较。 我们将使用相同的 index.php 文件并将运行它时得到的结果与以下内容进行比较

  • php
  • php-wasmedge-aot
  • 在传统容器中运行的 php
  • 在 Wasm 容器中运行的 php-wasmedge-aot

在下面所有的示例中我们使用同样的 images/php/docroot/index.php 文件让我们来看一下。简而言之该脚本将

  • 使用 phpversion 和 php_uname 展示解释器版本和它运行的平台
  • 打印脚本可以访问的所有环境变量的名称
  • 打印一条包含当前时间和日期的问候消息
  • 列出根文件夹的内容 /
<html>
<body>
<h1>Hello from PHP <?php echo phpversion() ?> running on "<?php echo php_uname()?>"</h1>

<h2>List env variable names</h2>
<?php
$php_env_vars_count = count(getenv());
echo "Running with $php_env_vars_count environment variables:\n";
foreach (getenv() as $key => $value) {
    echo  $key . " ";
}
echo "\n";
?>

<h2>Hello</h2>
<?php
$date = getdate();

$message = "Today, " . $date['weekday'] . ", " . $date['year'] . "-" . $date['mon'] . "-" . $date['mday'];
$message .= ", at " . $date['hours'] . ":" . $date['minutes'] . ":" . $date['seconds'];
$message .= " we greet you with this message!\n";
echo $message;
?>

<h2>Contents of '/'</h2>
<?php
foreach (array_diff(scandir('/'), array('.', '..')) as $key => $value) {
    echo  $value . " ";
}
echo "\n";
?>

</body>
</html>

Native PHP 运行 index.js

我们使用本地 php 二进制码时看到一个基于 Linux 的平台。

  • 58 个环境变量的列表脚本可以在需要时访问
  • / 中所有文件和文件夹的列表如果需要脚本可以再次访问这些文件和文件夹
$ php -f images/php/docroot/index.php

<html>
<body>
<h1>Hello from PHP 7.4.3 running on "Linux alexandrov-z01 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64"</h1>

<h2>List env variable names</h2>
Running with 58 environment variables:
SHELL NVM_INC WSL2_GUI_APPS_ENABLED rvm_prefix WSL_DISTRO_NAME TMUX rvm_stored_umask TMUX_PLUGIN_MANAGER_PATH MY_RUBY_HOME NAME RUBY_VERSION PWD NIX_PROFILES LOGNAME rvm_version rvm_user_install_flag MOTD_SHOWN HOME LANG WSL_INTEROP LS_COLORS WASMTIME_HOME WAYLAND_DISPLAY NIX_SSL_CERT_FILE PROMPT_COMMAND NVM_DIR rvm_bin_path GEM_PATH GEM_HOME LESSCLOSE TERM CPLUS_INCLUDE_PATH LESSOPEN USER TMUX_PANE LIBRARY_PATH rvm_loaded_flag DISPLAY SHLVL NVM_CD_FLAGS LD_LIBRARY_PATH XDG_RUNTIME_DIR PS1 WSLENV XDG_DATA_DIRS PATH DBUS_SESSION_BUS_ADDRESS C_INCLUDE_PATH NVM_BIN HOSTTYPE WASMER_CACHE_DIR IRBRC PULSE_SERVER rvm_path WASMER_DIR OLDPWD BASH_FUNC_cr-open%% _

<h2>Hello</h2>
Today, Wednesday, 2022-12-14, at 12:0:36 we greet you with this message!

<h2>Contents of '/'</h2>
apps bin boot dev docroot etc home init lib lib32 lib64 libx32 lost+found media mnt nix opt path proc root run sbin snap srv sys tmp usr var wsl.localhost

</body>
</html>

php-aot-wasm 运行 index.js

如果我们在 WasmEdge 使用 php-aot-wasm 我们看到

  • 一个 wasi/wasm32 平台
  • 没有环境变量因为没有明确暴露给 Wasm 应用程序
  • Wasm 应用程序未获得对 / 的明确访问权限因此尝试列出其内容失败并出现错误

自然地为了让 php-wasmedge-aot 能够读取 index.php 文件我们必须明确地向 WasmEdge 声明我们想要预先打开 images/php/docroot 以便在 Wasm 应用程序的上下文中作为 /docroot 进行访问。这显而易见展示了 Wasm 除了可移植性之外的最大优势之一。 我们得到了更佳的安全性因为除非明确说明否则无法访问任何内容。

$ wasmedge --dir /docroot:$(pwd)/images/php/docroot \
   build-output/php/php-7.4.32/bin/php-wasmedge-aot -f /docroot/index.php


<html>
<body>
<h1>Hello from PHP 7.4.32 running on "wasi (none) 0.0.0 0.0.0 wasm32"</h1>

<h2>List env variable names</h2>
Running with 0 environment variables:


<h2>Hello</h2>
Today, Wednesday, 2022-12-14, at 10:8:46 we greet you with this message!

<h2>Contents of '/'</h2>

Warning: scandir(/): failed to open dir: Capabilities insufficient in /docroot/index.php on line 27

Warning: scandir(): (errno 76): Capabilities insufficient in /docroot/index.php on line 27

Warning: array_diff(): Expected parameter 1 to be an array, bool given in /docroot/index.php on line 27

Warning: Invalid argument supplied for foreach() in /docroot/index.php on line 27


</body>
</html>

容器中的 PHP 运行 index.js

当我们从一个传统的容器中使用 php 时我们看到

  • 基于 Linux 的平台
  • 脚本有权访问的 14 个环境变量的列表
  • 带有当前时间和日期的问候消息
  • 包含根文件夹内容的列表 /

与在主机上使用 php 运行它相比已经明显有区别表现更佳。 由于 / 的环境变量和内容是“虚拟的”并且仅存在于容器内。

docker run --rm \
   -v $(pwd)/images/php/docroot:/docroot \
   php:7.4.32-cli \
   php -f /docroot/index.php


<html>
<body>
<h1>Hello from PHP 7.4.32 running on "Linux 227b2bc2f611 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64"</h1>

<h2>List env variable names</h2>
Running with 14 environment variables:
HOSTNAME PHP_INI_DIR HOME PHP_LDFLAGS PHP_CFLAGS PHP_VERSION GPG_KEYS PHP_CPPFLAGS PHP_ASC_URL PHP_URL PATH PHPIZE_DEPS PWD PHP_SHA256

<h2>Hello</h2>
Today, Wednesday, 2022-12-14, at 10:15:35 we greet you with this message!

<h2>Contents of '/'</h2>
bin boot dev docroot etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

</body>
</html>

php-aot-wasm 在一个容器中运行 index.js

如果我们在 WasmEdge 使用 php-aot-wasm 我们看到

  • 一个 wasi/wasm32 平台
  • 只有 2 个基础设施环境变量使用在 containerd 中运行的 WasmEdge shim 预先设置
  • 容器中 内所有文件和文件夹的列表明确预打开以供 Wasm 应用程序访问WasmEdge shim 中的逻辑的一部分

注意如果你仔细观察会发现要从这个镜像运行一个容器我们必须

  • 通过 --runtime=io.containerd.wasmedge.v1 将命令行参数直接传递给 php.wasm 明确声明运行时而不包括二进制文件本身。 拉到上面可以看到我们可以使用传统的 PHP 容器明确编写完整的命令包括 php 二进制文件不是必需的。

最后一点即使使用 DockerWasm 也加强了运行 index.php 的安全性因为暴露给它的要少得多。

docker run --rm \
   --runtime=io.containerd.wasmedge.v1 \
   -v $(pwd)/images/php/docroot:/docroot \
   ghcr.io/vmware-labs/php-wasm:7.4.32-cli-aot \
   -f /docroot/index.php


<html>
<body>
<h1>Hello from PHP 7.4.32 running on "wasi (none) 0.0.0 0.0.0 wasm32"</h1>

<h2>List env variable names</h2>
Running with 2 environment variables:
PATH HOSTNAME

<h2>Hello</h2>
Today, Wednesday, 2022-12-14, at 11:33:10 we greet you with this message!

<h2>Contents of '/'</h2>
docroot etc php.wasm

</body>
</html>

传统容器 vs Wasm 容器

我们构建并运行了一个 Wasm 二进制文件并将其作为容器运行。 我们看到了 Wasm 和传统容器之间的输出差异以及 Wasm 带来的高级“沙箱隔离”。我们可以轻松看到的两种容器之间的其他差异。

首先我们将运行两个 daemon 容器看看我们如何解释有关它们的一些统计信息。 然后我们将检查容器镜像的差异。

容器数据

让我们运行两个 daemon 容器 - 一个是从传统的 php 镜像另一个是从 php-wasm 镜像。

docker run --rm -d \
   -p 8083:8080 -v $(pwd)/images/php/docroot:/docroot \
   php:7.4.32-cli \
   -S 0.0.0.0:8080 -t /docroot
docker run --rm -d \
   --runtime=io.containerd.wasmedge.v1 \
   -p 8082:8080 -v $(pwd)/images/php/docroot:/docroot \
   ghcr.io/vmware-labs/php-wasm:7.4.32-cli-aot 
   -S 0.0.0.0:8080 -t /docroot

但是如果我们看 docker stats我们只看到传统容器的数据。这之后可能会变化因为 Docker+Wasm 现在是 beta 版特性。 所以如果真的想看看发生了什么可以改为监视对照组。 每个传统容器都有自己的控制组如 docker/ee44...。另一方面Wasm 容器作为 podruntime/docker 控制组的一部分包含在内可以间接观察它们的 CPU 或内存消耗。

$ systemd-cgtop -kP --depth=10

Control Group           Tasks    %CPU     Memory
podruntime              145      0.1      636.3M
podruntime/docker       145      0.1      636.3M
docker                  2        0.0      39.7M
docker/ee444b...        1        0.0      6.7M 

镜像大小

首先探索镜像我们看到 Wasm 容器镜像比传统镜像小得多。 即使是 alpine 版本的 php 容器也比 Wasm 容器大。

$ docker images


REPOSITORY                     TAG                 IMAGE ID       CREATED          SIZE
php                            7.4.32-cli          680c4ba36f1b   2 hours ago      166MB
php                            7.4.32-cli-alpine   a785f7973660   2 minutes ago    30.1MB
ghcr.io/vmware-labs/php-wasm   7.4.32-cli-aot      63460740f6d5   44 minutes ago   5.35MB

这是意料之中的因为对于 Wasm我们只需要在容器内添加可执行二进制文件而对于传统容器我们仍然需要来自运行二进制文件的操作系统的一些基本库和文件。这种大小差异对于第一次拉取镜像的速度以及进行在本地存储库中占用的空间非常有帮助。

Wasm 可移植性

Wasm 最大优势之一就是它的可移植性。 当人们想要一个可移植的应用程序时Docker 已经提供了传统的容器作为一种选择。 然而除了镜像特别大之外传统容器还绑定到它们运行的平台架构。 作为程序员相比许多人都经历过这种坎坷针对不同的架构必须构建支持的软件版本并为每种架构打包对应镜像。

WebAssembly 带来了真正的可移植性。 构建一次二进制文件就能在任何地方运行它。 作为这种可移植性的证明我们准备了几个通过我们为 WebAssembly 构建的 PHP 解释器运行 WordPress 的示例。

当 PHP 作为独立的 Wasm 应用程序运行时它会为 WordPress 提供服务。 它也可以在 Docker+Wasm 容器中运行。 此外它还能在嵌入 Wasm 运行时的任何应用程序中运行。 在我们的示例中这是 apache httpd它可以通过 mod_wasm 使用 Wasm 应用程序作为内容处理程序。 最后PHP.wasm 也可以在浏览器中运行。

通过 WasmEdge 服务 WordPress

我们为本次演示准备了一个紧凑的 WordPress+Sqlite 示例。 由于它是 ghcr.io/vmware-labs/php-wasm:7.4.32-server-wordpress 容器镜像的一部分我们先将其下载到本地。

此命令将只创建一个临时容器拉取镜像将 WordPress 文件复制到 /tmp/wp/docroot然后删除容器。

container_id=$(docker create ghcr.io/vmware-labs/php-wasm:7.4.32-server-wordpress) && \
   mkdir /tmp/wp && \
   docker cp $container_id:/docroot /tmp/wp/ && \
   docker rm $container_id

现在我们有了 WordPress让我们添加服务器

wasmedge --dir /docroot:/tmp/wp/docroot \
   build-output/php/php-7.4.32/bin/php-wasmedge-aot \
   -S 0.0.0.0:8085 -t /docroot

可以访问 http://localhost:8085 使用由 PHP Wasm 解释器服务的 WordPress。

通过 Docker+Wasm 服务 WordPress

自然的有了 Docker 会容易很多。

docker run --rm --runtime=io.containerd.wasmedge.v1 \
   -p 8086:8080 -v /tmp/wp/docroot/:/docroot/ \
   ghcr.io/vmware-labs/php-wasm:7.4.32-cli-aot 
   -S 0.0.0.0:8080 -t /docroot

可以访问 http://localhost:8086 并使用由 PHP Wasm 解释器服务的 WordPress这回是在 Docker 容器中运行。

通过 mod_wasm in Apache HTTPD 服务 WordPress

Apache HTTPD 是使用最广泛的 HTTP 服务器之一。 现在有了 mod_wasm它还可以运行 WebAssembly 应用程序。 为了避免在本地安装和配置它我们准备了一个容器其中包含 Apache HTTPD、mod_wasm 和 WordPress。

docker run -p 8087:8080 projects.registry.vmware.com/wasmlabs/containers/php-mod-wasm:wordpress

可以访问 http://localhost:8087 并使用由 PHP Wasm 解释器服务的 WordPress它由 Apache HTTPD 中的 mod_wasm 加载。

直接在浏览器中服务 WordPress

访问 https://wordpress.wasmlabs.dev 获得示例。 你将看到一个框架其中 PHP Wasm 解释器会现场渲染 WordPress。

结论

感谢阅读本文。 需要消化的内容很多但我们希望本文有助于理解 WebAssembly 的能力以及它如何与你现有的代码库和工具包括 Docker结合运行。 期待看到你使用 Wasm 编程

https://github.com/WasmEdge/WasmEdge

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Docker