首页 » PHP教程 » php挪用wasm技巧_Docker社区大年夜会WebAssembly无需容器的 Docker下

php挪用wasm技巧_Docker社区大年夜会WebAssembly无需容器的 Docker下

duote123 2024-12-09 0

扫一扫用手机浏览

文章目录 [+]

作者:Asen Alexandrov,Wasm Labs 工程师,文中的我们均指作者或 Wasm Labs。

上篇【Docker社区大会】WebAssembly:无需容器的 Docker(上)讲解了做事端 Wasm 为什么有着重要的浸染、什么是 WasmEdge 以及如何让阐明型措辞编写的程序在 Wasm 里运行。
这篇文章,我们将通过动手示例理解在 Docker + Wasm 背景下的 Wasm container 有什么好处以及如何运行一个做事 WordPress 的 php.wasm 镜像。

php挪用wasm技巧_Docker社区大年夜会WebAssembly无需容器的 Docker下

动手示例

让我们开始吧!
在动手示例中,我们将利用编译为 Wasm 的 PHP 阐明器。
我们会:

php挪用wasm技巧_Docker社区大年夜会WebAssembly无需容器的 Docker下
(图片来自网络侵删)
构建一个 Wasm 容器。
比较 Wasm 和原生二进制文件。
比较传统容器和 Wasm 容器。
展示 Wasm 的可移植性前期准备

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

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

我们还充分利用 webassembly-language-runtimes[4] repo,它供应了将 PHP 阐明器构建为 WebAssembly 运用程序的方法。
可以像这样查看 demo 分支:

git clone --depth=1 -b php-wasmedge-demo \ https://github.com/vmware-labs/webassembly-language-runtimes.git wlr-democd 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 是用 autoconfmake 构建的。
以是如果你看一眼脚本 scripts/wl-build.sh ,你会把稳到我们设置了所有干系变量,如 CC、LD、 CXX 等,以利用来自 WASI_SDK 的编译器。

export WASI_SYSROOT="${WASI_SDK_ROOT}/share/wasi-sysroot"export CC=${WASI_SDK_ROOT}/bin/clangexport LD=${WASI_SDK_ROOT}/bin/wasm-ldexport CXX=${WASI_SDK_ROOT}/bin/clang++export NM=${WASI_SDK_ROOT}/bin/llvm-nmexport AR=${WASI_SDK_ROOT}/bin/llvm-arexport 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 优化二进制文件的更多信息,请查看这里。
[5]

构建 OCI 镜像

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

FROM scratchARG PHP_TAG=php-7.4.32ARG PHP_BINARY=phpCOPY build-output/php/${PHP_TAG}/bin/${PHP_BINARY} /php.wasmENTRYPOINT [ "php.wasm" ]

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

FROM scratchARG PHP_TAG=php-7.4.32ARG PHP_BINARY=phpCOPY build-output/php/${PHP_TAG}/bin/${PHP_BINARY} /php.wasmCOPY images/php/docroot /docrootENTRYPOINT [ "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 文件并将运行它时得到的结果与以下内容进行比较:

phpphp-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><?phpforeach (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 27Warning: scandir(): (errno 76): Capabilities insufficient in /docroot/index.php on line 27Warning: array_diff(): Expected parameter 1 to be an array, bool given in /docroot/index.php on line 27Warning: 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 二进制文件(不是必需的)。

末了一点,纵然利用 Docker,Wasm 也加强了运行 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 /docrootdocker 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=10Control Group Tasks %CPU Memorypodruntime 145 0.1 636.3Mpodruntime/docker 145 0.1 636.3Mdocker 2 0.0 39.7Mdocker/ee444b... 1 0.0 6.7M 镜像大小

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

$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEphp 7.4.32-cli 680c4ba36f1b 2 hours ago 166MBphp 7.4.32-cli-alpine a785f7973660 2 minutes ago 30.1MBghcr.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[6] ,利用由 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[7] 并利用由 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[8] 并利用由 PHP Wasm 阐明器做事的 WordPress,它由 Apache HTTPD 中的 mod_wasm 加载。

直接在浏览器中做事 WordPress

访问 https://wordpress.wasmlabs.dev[9] 得到示例。
你将看到一个框架,个中 PHP Wasm 阐明器会现场渲染 WordPress。

结论

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

参考资料

[1]

Wasm Labs @ VMware OCTO: https://wasmlabs.dev/

[2]

Docker+WebAssembly 的演讲: https://www.bilibili.com/video/BV1314y1w7vp/

[3]

4.15版: https://docs.docker.com/desktop/release-notes/#4150

[4]

webassembly-language-runtimes: https://github.com/vmware-labs/webassembly-language-runtimes

[5]

查看这里。
: https://wasmlabs.dev/articles/docker-without-containers/build-output/php/php-7.4.32/bin/php-wasmedge-aot

[6]

http://localhost:8085: http://localhost:8085/

[7]

http://localhost:8086: https://wasmlabs.dev/articles/docker-without-containers/

[8]

http://localhost:8087: https://wasmlabs.dev/articles/docker-without-containers/

[9]

https://wordpress.wasmlabs.dev: https://wordpress.wasmlabs.dev/

标签:

相关文章