Изучение .NET WebAssembly с помощью WASI и Wasmtime


Обзор

WebAssembly (Wasm) — это то, что изучает команда Cloud Native Advocacy. Она существует уже несколько лет и в основном используется в браузерных приложениях. В блогах можно найти множество сообщений о том, что делает WebAssembly идеальной целью для запуска приложений (например, меньший размер .wasm-файлов по сравнению с контейнерами, изоляция кода и «песочница»). Мой коллега Стивен Муравски написал серию блогов о том, как начать размещать Wasm-приложения на новой PaaS-платформе под названием Hippo, разработанной специалистами компании Fermyon. В первой части серии он представил темы и дал определение некоторым аббревиатурам, таким как «Wagi» и «WASI». Он также представил среду выполнения под названием Wasmtime, которая реализует стандарт WebAssembly System Interface (WASI). В этой статье мы со Стивеном расскажем о том, как мы получили консольное приложение .NET, работающее как приложение Wasm на среде выполнения Wasmtime в контейнере Dev Container. Консольное приложение .NET, созданное в этой статье, также было внесено в качестве шаблона csharp в репозиторий yo-wasm, который также поддерживается Fermyon; так что вы сможете быстро протестировать его для себя позже.

Стоп… Wasmtime!

Почему появление таких стандартов, как WASI, и таких сред выполнения, как Wasmtime, является интересным? Ну, теперь мы можем запускать не только веб-приложения в браузере. Мы можем начать рассматривать возможность запуска серверных приложений Wasm в местах, реализующих стандарт WASI. Это означает, что мы можем запускать любое приложение в любом месте, если оно скомпилировано в один двоичный файл .wasm и на хосте установлена среда выполнения на основе WASI.

Это замечательно, но что это значит для разработчиков .NET? Мы знаем, что Blazor WebAssembly идет по этому пути уже несколько лет, но Blazor WebAssembly в основном нацелена на веб-браузеры в качестве среды выполнения, и компиляция проекта Blazor WebAssembly не дает единого двоичного файла .wasm, который необходим для запуска с помощью Wasmtime. Если бы только у разработчиков .NET был инструментарий, который мог бы компилировать приложения .NET в один двоичный файл .wasm (подобно тому, как команда dotnet build может компилировать проект в одну .dll) и компилировать эти приложения .NET в целевой WASI, чтобы эти приложения .NET могли работать вне браузеров. Оказывается, Стив Сандерсон и команда разработчиков .NET создали экспериментальный SDK, который позволит вам сделать именно это.

Экспериментальный SDK опубликован здесь, и SDK действительно прост в использовании. Он опубликован в виде пакета NuGet, и все, что вам нужно сделать, это добавить пакет в ваш проект .NET. Вот и все… SDK подключается к конвейеру сборки и создает единственный .wasm, который нам нужен. Он просто компилирует приложение .NET в Wasm с помощью команды dotnet build.

Этот SDK является экспериментальным и в ближайшем будущем может быть перенесен в соответствующий репозиторий Microsoft на GitHub.

Давайте пройдемся по шагам, которые мы предприняли для его создания, и дадим вам краткий обзор проекта yo-wasm, чтобы вы могли использовать его для начала работы над своими проектами Wasm.

Руководство

Откройте ваш любимый терминал, создайте папку для работы, cd в папку и откройте ее с помощью VS Code.

mkdir MyFirstWasiApp
cd MyFirstWasiApp
code .
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Почему именно Dev Container?

Этот экспериментальный пакет Wasi.Sdk требует .NET 7, который на момент написания этой статьи находится в стадии предварительного просмотра. Вы можете установить предварительную версию на свою локальную машину. Поскольку некоторые люди могут не захотеть устанавливать предварительные версии .NET на локальную машину, мы решили протестировать пакет в контейнере VS Code Dev Container. Мы столкнулись с несколькими препятствиями, и в этом разделе мы расскажем, как мы их преодолели.

Этот подход требует, чтобы на вашей локальной машине был запущен Docker Desktop и расширение Remote — Containers VS Code.

Создать и запустить Dev-контейнер с помощью VS Code довольно просто. Если вы знакомы с созданием Dev-контейнеров, вы можете быстро пролистать содержание ниже, выбрать ключевые шаги (поскольку мы создаем пользовательский контейнер .NET 7), а затем перейти к разделу .NET Wasm.

В VS Code нажмите клавишу F1 на клавиатуре (Ctrl+Shift+P тоже работает). Откроется приглашение, в котором вы можете ввести слово devcontainer. Вы должны увидеть запись под названием Remote-Containers: Add Development Container Configuration Files…. Нажмите на нее, чтобы запустить мастер настройки.

Вам будет представлен список предопределенных конфигураций контейнеров. Мы будем использовать определение C# (.NET).

Если вы не видите его в списке, вы можете поискать его в текстовом поле над списком.

На следующем шаге мастера вы заметите, что последняя поддерживаемая версия .NET — 6.0. Поддержка .NET 7.0 пока отсутствует. Давайте выберем последнюю версию и приступим к созданию нового контейнера Dev Container, поддерживающего .NET 7.0.

После выбора версии .NET вам будут предложены дополнительные опции Dev Container (т.е. версия Node.js и дополнительные функции для установки). Пройдите по ним, выбрав lts/* для NodeJS и не выбирая никаких дополнительных возможностей (просто нажмите кнопку OK, не выбирая никаких возможностей).

Это не совсем то, что мы искали, но в итоге мы получаем структуру того, как настраиваются Dev Containers. Мы видим, что все, что нам нужно, это каталог .devcontainer с файлом devcontainer.json и файлом Dockerfile.

Если вы откроете файл devcontainer.json, то заметите, что в качестве аргумента сборки можно передать значение VARIANT. Здесь передан тег 6.0-bullseye для сборки контейнера .NET 6 на Debian 11.

Было бы неплохо, если бы мы могли просто передать что-то вроде 7.0.100-preview.6-jammy для сборки контейнера .NET 7 на Ubuntu 22.04.

Однако это не сработает, поскольку команда VS Code Dev Container пока не публикует тег образа .NET 7.

Список всех опубликованных тегов для образа vscode/devcontainers/dotnet можно найти здесь

Поскольку команда VS Code пока не публикует VS Code Dev Container, поддерживающий теги предварительного просмотра .NET 7, мы создадим свой собственный.

Если вы вернетесь к файлу devcontainer.json, вы увидите некоторую информацию о том, откуда берется контейнер. Перейдите по URL, чтобы просмотреть репозиторий GitHub, в котором размещена эта конфигурация.

В репозитории vscode-dev-containers вы увидите, что там тоже есть каталог .devcontainer. Он содержит инструкции по сборке dotnet vscode-dev-container. Щелкните по директории.

Здесь есть несколько файлов и один подкаталог, и я объясню, что они делают.

Вернувшись в VS Code, откройте терминал и убедитесь, что вы находитесь в директории .devcontainer.

Нам понадобится загрузить файл base.Dockerfile и установочные скрипты в директории library-scripts.

Выполните следующие команды, чтобы перезаписать то, что у нас уже есть:

mkdir library-scripts
cd library-scripts
curl -O https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.241.1/containers/dotnet/.devcontainer/library-scripts/common-debian.sh
curl -O https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.241.1/containers/dotnet/.devcontainer/library-scripts/node-debian.sh
curl -O https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.241.1/containers/dotnet/.devcontainer/library-scripts/meta.env
cd -
curl -o Dockerfile https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.241.1/containers/dotnet/.devcontainer/base.Dockerfile
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы сохраним наш файл devcontainer.json и внесем лишь несколько изменений. Обновим значение VARIANT, чтобы оно указывало на правильный тег .NET 7 Preview (7.0-jammy) и добавим некоторые расширения VS Code.

Набор инструментов, необходимый для правильной сборки файла .wasm, был создан с использованием архитектуры amd64 (x86_x64), вам следует использовать соответствующий тег. Вы можете найти подходящий тег для использования здесь.

Также, из-за зависимости от amd64, компиляция кода Wasm может работать некорректно, если вы используете чипы M1 на более новых Mac.

Мы можем добавить несколько расширений VS Code в массив customizations.vscode.extensions:

  • ms-vsliveshare.vsliveshare
  • dtsvet.vscode-wasm

Вы можете добавить больше расширений по мере необходимости.

Файл должен выглядеть следующим образом:

Теперь нам нужно включить шаги по установке Wasmtime в наш Dockerfile. Если вы посмотрите на домашнюю страницу Wasmtime, вы найдете инструкции по его установке. Давайте начнем с создания нового скрипта в каталоге library-scripts для выполнения установки. Добавьте в скрипт команду curl.

cat << EOF > wasmtime.sh
curl https://wasmtime.dev/install.sh -sSf | bash
EOF
Вход в полноэкранный режим Выйдите из полноэкранного режима

Если вы используете терминал Windows, приведенный выше скрипт heredoc не будет работать. В этом случае просто создайте новый файл wasmtime.sh и добавьте в него команду curl.

Сценарий установки Wasmtime полагается на пакет под названием xz-utils для распаковки файлов, и нам нужно убедиться, что эта утилита доступна в нашем контейнере.

Перейдите к файлу common-debian.sh и добавьте его в переменную package_list (если она еще не существует). Возможно, имеет смысл включить его после пакетов unzip и zip.

Последнее, что нам нужно сделать, это обновить Dockerfile для запуска нашего недавно созданного скрипта wasmtime.sh. Прямо перед строкой, которая удаляет каталог /library-scripts, добавьте команду RUN для вызова нашего скрипта.

# Install wasmtime
RUN su vscode -c 'bash /tmp/library-scripts/wasmtime.sh'
Вход в полноэкранный режим Выход из полноэкранного режима

Поскольку нам нужен wasmtime, когда контейнер запущен, запустите код, используя не root-пользователя vscode.

Теперь мы готовы создать наш Dev-контейнер и вернуться к созданию нашего приложения .NET Wasm.

.NET Wasm

Убедитесь, что все файлы сохранены и Docker запущен на вашей машине. Нажмите клавишу F1 и начните набирать открыть папку. Вы должны увидеть запись для Remote-Containers: Open Folder in Container…. Щелкните на нем, чтобы собрать ваш dev-контейнер.

Процесс начальной сборки контейнера может занять несколько минут.

После сборки контейнера вы можете открыть новый терминал в VS Code и выполнить команду dotnet --version, чтобы проверить версию dotnet, которая была установлена.

Прогресс! Давайте вернемся к созданию приложения .NET с помощью Wasi.Sdk.

mkdir src
cd src
dotnet new console -o MyFirstWasiApp
cd MyFirstWasiApp
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте запустим приложение, чтобы убедиться, что оно работает:

dotnet run
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы должны увидеть текст Hello, World!, выведенный в консоль.

Теперь давайте добавим пакет Wasi.Sdk.

dotnet add package Wasi.Sdk --prerelease
Вход в полноэкранный режим Выйдите из полноэкранного режима

Запустите проект снова, и вы снова увидите текст Hello, World!, но на этот раз приложение было запущено с использованием двоичного файла .wasm вместо двоичного файла .dll.

Опять же, из-за зависимости от amd64, компиляция кода Wasm может работать некорректно, если вы используете чипы M1 на более новых Mac.
Запуск контейнеров на базе amd64 на архитектуре M1 использует эмуляцию qemu для совместимости, и это может привести к странным результатам.
Для достижения наилучших результатов следует использовать архитектуру amd64.

Не уверены на 100%, что команда dotnet run использует wasmtime и двоичный файл .wasm? Выполните следующую команду:

wasmtime bin/Debug/net7.0/MyFirstWasiApp.wasm
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы должны снова увидеть текст Hello, World!, выведенный на консоль.

Йоу, Wasm!

Я знаю, что вы думаете… это было много шагов, чтобы просто запустить простое консольное приложение «Hello World». Но поскольку Wasi-Sdk является экспериментальным и имеет зависимость от .NET 7 (предварительная версия), это хороший путь для тех, кто просто хочет попробовать это без необходимости устанавливать биты .NET предварительной версии на свою локальную машину.

Как только команда VS Code начнет публиковать .NET 7 Dev Container, мы будем использовать этот контейнер и нам не придется создавать свой собственный.

Вернемся к Wasm и репо yo-wasm. Это репо существует, чтобы помочь вам легко создавать модули Wasm, которые могут быть опубликованы в реестрах OCI. Проект yo-wasm в настоящее время поддерживает публикацию в Azure Container Registry или Hippo и использует Yeoman для создания проектов на основе шаблонов, определенных в этом репозитории. Существуют шаблоны для Assembly Script, C, Rust, Swift и TinyGo. Мы добавили новый шаблон для C#, так что давайте попробуем его.

Перейдите к репо yo-wasm, клонируйте его на свою локальную машину, затем откройте репо с помощью VS Code.

Если наш pull request еще не рассмотрен, вы можете клонировать и использовать этот репозиторий вместо него.

Откройте терминал и следуйте инструкциям из файла yo-wasm README.

npm install -g yo
npm install -g generator-wasm
Войдите в полноэкранный режим Выйдите из полноэкранного режима

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

npm install
npm run compile
npm link
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь создайте новый каталог для вашего нового тестового проекта.

cd
mkdir -p tmp/yo-csharp
cd tmp/yo-csharp
Войти в полноэкранный режим Выйти из полноэкранного режима

Создайте новый проект C# с помощью команды yo wasm и следуйте подсказкам.

yo wasm
Войти в полноэкранный режим Выйдите из полноэкранного режима

Вот окончательный результат. Вы можете видеть все файлы проекта для базового консольного приложения «Hello World», а конфигурация .devcontainer также включена в шаблон.

Если у вас установлен .NET 7 (preview) и Wasmtime, не стесняйтесь запустить dotnet run локально для тестирования. Если нет, вы можете использовать devcontainer для тестирования 😄.

Когда вы решите опубликовать свой модуль, шаблон создаст файл рабочего процесса GitHub Action, который использует исполняемый файл wasm-to-oci для отправки вашего .wasm файла в реестр OCI, в данном случае Azure Container Registry.

Для этого необходимо, чтобы реестр OCI был предварительно развернут. Если вы хотите опубликовать реестр Azure Container Registry, посмотрите это руководство по его настройке и это руководство по созданию секрета репозитория, который должен содержать значение ключа доступа к реестру контейнеров.

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

Резюме

В заключение мы рассмотрели, как WebAssembly развивается и становится чем-то большим, чем просто запуск в веб-браузерах. С помощью WASI вы можете запускать любые приложения, скомпилированные в двоичный файл .wasm, на любом хосте. Это все еще развивающаяся область, но концепция запуска Wasm на сервере и возможность публикации модулей Wasm в реестрах OCI может открыть множество новых возможностей для инноваций. Возможность компилировать приложения .NET в один файл .wasm действительно интересна, и мне не терпится увидеть, как это будет развиваться.

Проект yo-wasm и Wasi-Sdk — это отличные места для начала работы, и есть дополнительные ресурсы, чтобы узнать больше. Я бы посоветовал вам ознакомиться со следующими:

  • Ключевой доклад: WASI — новый вид системного интерфейса & что это значит для облачных приложений — Лин Кларк, Fastly
  • Wasm, WASI, Wagi: что это такое? | Fermyon Technologies (@FermyonTech)
  • Запуск .NET в WebAssembly | Fermyon Technologies (@FermyonTech)
  • Будущие возможности для .NET Core и WASI (WebAssembly on the Server)| OD108
  • Будущее Blazor и Web Assembly со Стивом Сандерсоном | The Azure DevOps Podcast, ep.202
  • Создание пулов узлов WebAssembly System Interface (WASI) в Azure Kubernetes Service (AKS) для запуска рабочей нагрузки WebAssembly (WASM) (предварительный просмотр)

Счастливого кодирования!

Оцените статью
devanswers.ru
Добавить комментарий