Как стать автором
Обновить
Флант
DevOps-as-a-Service, Kubernetes, обслуживание 24×7

WebAssembly: Docker без контейнеров

Уровень сложностиСредний
Время на прочтение16 мин
Количество просмотров14K
Автор оригинала: Asen Alexandrov

Введение

Полгода назад Docker объявил о поддержке WebAssembly на базе WasmEdge.

В этой статье расскажем, что такое WebAssembly, почему эта технология актуальна для экосистемы Docker, а также приведем несколько практических примеров. Предполагается, что вы знакомы с инструментарием Docker. Чтобы продемонстрировать, как создать интерпретатор PHP, упаковать его как часть OCI-образа и запустить с помощью Docker, воспользуемся нашим WebAssembly-портом PHP.

Обратите внимание: эта статья скорее направлена на получение практического опыта, нежели на обсуждение технических тонкостей. Вы можете воспроизвести приведенные ниже примеры сами или довериться нам — результат выполнения всех команд мы публикуем.

WebAssembly — что это и зачем?

В этом разделе приводятся базовые сведения. Его можно пропустить, если вы уже знакомы с технологией.

Что такое WebAssembly?

Открытый стандарт WebAssembly (или Wasm) определяет формат двоичных инструкций, который позволяет создавать портируемые исполняемые файлы из исходников, написанных на различных языках программирования.

Wasm есть во всех браузерах
Wasm есть во всех браузерах

Эти исполняемые файлы могут работать в различных окружениях. Формат поддерживают все основные браузеры.

Как Wasm работает в браузерах

В движки браузеров интегрирована виртуальная машина Wasm (обычно называемая «средой исполнения Wasm»), которая и отвечает за выполнение Wasm-инструкций. Специализированные компиляторы (например, Emscripten) могут компилировать исходный код в Wasm. Технология позволяет переносить legacy-приложения в браузер и обеспечивает их прямое взаимодействие с JS-кодом в веб-приложениях на стороне клиента.

Wasm в браузере
Wasm в браузере

Таким образом, традиционные настольные приложения теперь успешно работают в браузере, то есть их можно запускать на любом устройстве, на котором есть браузер с поддержкой Wasm. Среди примечательных примеров — Google Earth и библиотека компьютерного зрения OpenCV.

Как Wasm работает на серверах

Существуют рантаймы Wasm, которые могут работать вне браузера, в том числе в классических операционных системах, таких как Linux, Windows и macOS. Поскольку в данном случае на движок Javascript рассчитывать не приходится, коммуникация с внешним миром идет через различные интерфейсы — например, WASI (WebAssembly System Interface). Такие рантаймы позволяют Wasm-приложениям взаимодействовать с хост-системой по аналогии с POSIX (хотя есть и отличия). Проекты вроде WASI SDK и wasi-libc помогают компилировать существующие POSIX-совместимые приложения в WebAssembly.

Wasm на сервере
Wasm на сервере

При этом достаточно скомпилировать приложение в модуль Wasm только один раз, и его можно будет запускать где угодно.

Чем так хорош Wasm?

Некоторые из особенностей, благодаря которым Wasm отлично работает в браузерах, делают его привлекательным и для server-side-разработки:

🌐 Открытость. Стандарт широко распространен в отрасли. Браузерные войны остались в прошлом: крупные игроки активно сотрудничают в области стандартизации WASI и WebAssembly-приложений.

🚀 Быстрота. Почти нативная скорость благодаря JIT/AOT-возможностям большинства рантаймов. Никаких холодных стартов — в отличие от виртуальных машин или контейнеров.

🔒 Безопасность. Рантайм Wasm по умолчанию работает в режиме песочницы и следит за безопасным доступом к памяти. Модель, основанная на возможностях (capabilities-based), гарантирует, что Wasm-приложение имеет доступ только к тому, к чему ему явно разрешено. Повышается безопасность цепи поставок за счет виртуализации внешних зависимостей способом, с которым не нужно постоянно обновлять уязвимые компоненты приложения.

💼 Портируемость. Популярные рантаймы поддерживают большинство процессоров (x86, ARM, RISC-V) и большинство ОС, включая Linux, Windows, macOS, Android, ESXi и даже non-Posix-системы.

🔋 Эффективность. Можно сделать так, чтобы Wasm-приложение работало с минимальным объемом памяти и минимальными требованиями к процессору.

🗣 Полиглотизм. В Wasm можно скомпилировать исходники на 40+ языках. Инструменты для этого активно разрабатываются и совершенствуются.

Следующий шаг в эволюции серверных платформ

Возможно, вы видели этот твит Соломона Хайкса (одного из соучредителей корпорации Docker и автора Docker Open Source Initiative):

Если бы WASM+WASI существовали в 2008 году, нам бы не пришлось создавать Docker. Вот насколько они важны. WebAssembly на сервере — будущее компьютерных технологий.

В самом деле, WASM+WASI выглядят как следующий шаг в эволюции программной server-side-инфраструктуры.

  • Раньше нам приходилось работать с реальным оборудованием, кропотливо устанавливать ОС и приложения на каждое устройство и по очереди их обслуживать.

  • Все упростилось с внедрением виртуальных машин (здесь первопроходцем стала VMware). Их можно было копировать, клонировать и перемещать между устройствами. Однако все равно приходилось устанавливать ОС и приложения в виртуальные машины.

  • Затем появились контейнеры, ставшие популярными благодаря Docker. С их помощью стало возможно запускать конфигурации приложений в минималистском оберточном контексте, при этом не влияя на другие приложения на ОС хоста. Но контейнеры все равно приходилось дополнять средой исполнения и необходимыми библиотеками, а за границами безопасности следило ядро Linux.

  • И вот, наконец, появилась технология WebAssembly. Ее технические характеристики и портируемость позволяют распространять приложения, не «нагружая» их зависимостями системного уровня. Плюс они работают в строгих границах безопасности.

Учитывая все это, WebAssembly обычно рассматривается как «преемник» контейнеров и следующий логический шаг в развертывании инфраструктуры.

Wasm — следующий шаг в эволюции серверных платформ
Wasm — следующий шаг в эволюции серверных платформ

Но есть и другой взгляд на WebAssembly — как на альтернативный «бэкэнд» для Docker-инструментария. Можно применять те же инструменты командной строки и рабочие процессы, но вместо Linux-контейнеров запускать их WebAssembly-эквиваленты. В остальной части статьи рассматривается именно эта концепция — то, что мы называем «Docker без контейнеров».

Как Wasm работает с Docker'ом?

Docker Desktop теперь работает с WebAssembly. Поддержка реализована с помощью containerd shim'а, способного запускать Wasm-приложения в среде исполнения WasmEdge. То есть вместо обычных Windows- или Linux-контейнеров, которые запускают отдельный процесс из исполняемого файла в образе, под видом контейнера можно запустить Wasm-приложение в рантайме WasmEdge.

Такому «контейнеру» не нужны ОС или контекст рантайма — достаточно исполняемого Wasm-файла.

Подробнее об этом рассказывается в статье Introducing the Docker+Wasm Technical Preview (примечание редакции: это статья на английском языке).

Что такое WasmEdge

WasmEdge — это высокопроизводительный рантайм для WebAssembly, который:

  • является проектом с открытым исходным кодом и входит в состав CNCF;

  • поддерживает все основные архитектуры процессоров (x86, ARM, RISC-V);

  • поддерживает все основные операционные системы (Linux, Windows, macOS) и некоторые другие, такие как seL4 RTOS, Android;

  • оптимизирован для cloud-native и Edge-приложений;

  • расширяется и поддерживает связанные с ИИ технологии, такие как Tensorflow, OpenVINO, PyTorch;

  • поддерживает асинхронную работу с сетью с помощью Tokio. А также микросервисы, клиенты баз данных, очереди сообщений;

  • позволяет настроить интеграцию с экосистемой контейнеров Docker и Kubernetes (как показано в этой статье).

Что насчет интерпретируемых языков?

До сих пор мы говорили только о превращении в WebAssembly-программы исходников, написанных на компилируемых языках, таких как C и Rust. В случае интерпретируемых языков, таких как Python, Ruby и PHP, подход иной: их интерпретаторы написаны на C и могут быть скомпилированы в WebAssembly. После этого Wasm-интерпретатор cможет работать с исходниками в соответствующем формате (.py, .rb, .php и т. п.) После компиляции в Wasm любая платформа с Wasm-рантаймом сможет запускать программы, написанные на интерпретируемых языках, даже если интерпретатор изначально не предназначался для нее.

Wasm на сервере — интерпретируемые языки
Wasm на сервере интерпретируемые языки

Практические примеры

Давайте перейдем к практике. В примерах будем использовать интерпретатор PHP, скомпилированный в Wasm. Мы:

  • соберем Wasm-контейнер;

  • сравним Wasm и нативные исполняемые файлы;

  • сравним классические контейнеры и контейнеры Wasm;

  • продемонстрируем портируемость Wasm.

Требования

Чтобы воспроизвести примеры локально, необходимо подготовить окружение. Для этого понадобятся следующие компоненты:

  • WASI SDK для сборки WebAssembly-приложений из исходников на C;

  • PHP для запуска нативного PHP-файла для сравнения;

  • рантайм WasmEdge для запуска WebAssembly-приложений;

  • Docker Desktop + Wasm (на момент написания этой статьи доступен как стабильная бета в версии 4.15) для запуска Wasm-контейнеров.

В репозитории Wasm Language Runtimes содержится все необходимое для сборки интерпретатора PHP в виде WebAssembly-приложения.

Начать можно с клонирования демо-ветки:

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. Он включает в себя компилятор clang, способный собирать wasm32-wasi-модули, а также библиотеку wasi-libc, отвечающую за реализацию базовых интерфейсов системных вызовов POSIX поверх WASI. WASI SDK позволяет из кодовой базы PHP собрать модуль Wasm, написанный на C. После этого достаточно создать простой Docker-файл для сборки OCI-образа, который будет запускаться с помощью Docker+Wasm.

От кода на Си до Wasm-контейнера
От кода на Си до Wasm-контейнера

Собираем исполняемый 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/

... (через несколько минут и сотни строк логов)

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

PHP собирается с autoconf и make. Изучив скрипт scripts/wl-build.sh, вы увидите, что были установлены все нужные компилятору WASI_SDK переменные (CC, LD, CXX и т.д.).

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. В последующих примерах будем использовать бинарник php-wasmedge, специально собранный для WasmEdge. Его особенность — поддержка сокетов на стороне сервера (она пока не является частью WASI).

Оптимизируем исполняемый файл

Wasm — виртуальный набор инструкций, поэтому по умолчанию любой рантайм будет интерпретировать их «на лету». В некоторых случаях это грозит замедлением работы. WasmEdge позволяет создать AOT-оптимизированный (ahead-of-time) исполняемый файл, который нативно работает на текущей машине и может интерпретироваться на других.

Для этого нужно выполнить следующую команду:

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" ]

Также в образ можно положить некоторые вспомогательные данные, которые потребуются Wasm-бинарнику, когда его запустит Docker. Например, в 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 в классическом контейнере;

  • php-wasmedge-aot в Wasm-контейнере.

Схемы запуска index.php
Схемы запуска index.php

Во всех примерах ниже используется один и тот же файл images/php/docroot/index.php. Вот его содержимое:

<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>

Этот скрипт:

  • с помощью phpversion и php_uname выводит версию интерпретатора и платформы, на которой запущен;

  • выводит имена всех переменных окружения, к которым у скрипта есть доступ;

  • выводит приветствие с указанием текущего времени и даты;

  • выводит список содержимого корневой папки /.

Нативный PHP

При запуске нативного 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

При запуске с помощью php-aot-wasm и Wasmedge видим:

  • платформу wasi/wasm32, на которой выполняется скрипт;

  • пустой список переменных окружения, поскольку Wasm-приложению не был явно предоставлен доступ ни к одной из них;

  • попытка вывести содержимое / закончилась ошибкой, поскольку приложению Wasm не был предоставлен явный доступ к корневой директории.

Чтобы у php-wasmedge-aot был доступ на чтение файла index.php, нужно явно указать WasmEdge, что директория images/php/docroot должна быть открыта для доступа как /docroot в контексте Wasm-приложения.

Этот момент отлично демонстрирует одно из главных преимуществ 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 в контейнере

При запуске в классическом контейнере видим:

  • платформу под управлением Linux, на которой выполняется скрипт;

  • список из 14 переменных окружения, к которым у скрипта есть доступ;

  • приветствие с указанием текущего времени и даты;

  • список содержимого корневой папки /.

Уже заметна разница в лучшую сторону по сравнению с запуском на хост-машине: переменные окружения и содержимое / являются «виртуальными» и существуют только внутри контейнера.

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 в контейнере

При запуске с помощью php-aot-wasm и WasmEdge видим:

  • платформу wasi/wasm32, на которой выполняется скрипт;

  • всего 2 инфраструктурные переменные окружения, предварительно настроенные с помощью WasmEdge shim, который работает внутри containerd;

  • список всех файлов и директорий в / внутри контейнера, который явно предварительно открыт для доступа приложением Wasm (часть логики в WasmEdge shim).

Примечание: если внимательно посмотреть, можно увидеть, что для запуска контейнера из этого образа необходимо:

  • явно указать рантайм с помощью аргумента командной строки --runtime=io.containerd.wasmedge.v1pass, передав его напрямую 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. Давайте посмотрим, какие еще различия существуют между двумя типами контейнеров.

Сначала мы запустим два контейнера-демона и посмотрим, как можно интерпретировать их статистику. Затем мы рассмотрим различия в образах контейнеров.

Архитектура контейнеров
Архитектура контейнеров

Статистика по контейнерам

Запустим два контейнера-демона — один из обычного образа 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 привносит истинную портируемость. Исполняемый файл достаточно собрать один раз, после чего его можно будет запускать везде. Чтобы наглядно это продемонстрировать, мы подготовили несколько примеров запуска WordPress'а в интерпретаторе PHP, который собрали под WebAssembly.

WordPress будем запускать как отдельное Wasm-приложение и как контейнер Docker+Wasm. Кроме того, он сможет работать в любом приложении, в которое встроен Wasm-рантайм. В нашем примере — это apache httpd с модулем mod_wasm, который позволяет использовать Wasm-приложения как обработчики контента. Наконец, PHP.wasm с таким же успехом можно запускать прямо в браузере.

Сравнение контейнеров
Сравнение контейнеров

WordPress через WasmEdge

Для демонстрации есть компактный пример — связка 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 и проверить работу WordPress'а под интерпретатором PHP Wasm.

WordPress через Docker+Wasm

С 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 и убедиться, что WordPress работает под интерпретатором PHP Wasm прямо из Docker-контейнера.

WordPress через mod_wasm в Apache HTTPD

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 и посмотреть, как WordPress работает с интерпретатором PHP Wasm и модулем mod_wasm в Apache HTTPD.

Запуск WordPress непосредственно в браузере

Для примера зайдите на сайт https://wordpress.wasmlabs.dev. Увидите фрейм, в котором интерпретатор PHP Wasm рендерит WordPress в реальном времени.

Заключение

Спасибо, что дочитали до конца. Информации было много. Надеемся, она помогла оценить возможности WebAssembly и разобраться, как эта технология работает с существующими кодовыми базами и инструментами, в том числе с Docker'ом. 

А какой у вас опыт работы с Wasm? Делитесь в комментариях!

P.S.

Читайте также в нашем блоге:

Теги:
Хабы:
Всего голосов 53: ↑51 и ↓2+49
Комментарии35

Публикации

Информация

Сайт
flant.ru
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия
Представитель
Тимур Тукаев