Запускаем Linux в браузере. Часть 2

Сегодня поговорим о сборке образа через Docker и последующим запуском его в браузере.

Часть 2

Сборка v86

Склонируем репу себе:

git clone git@github.com:copy/v86.git
cd v86

И сразу создадим папочку по образы:

mkdir images

Для сборки самого v86 в WASM нам потребуется как минимум:

  • make
  • Rust с возможностью компилировать в wasm32-unknown-unknown
  • Версия clang совместимая с Rust
  • nodejs (требуется свежая, у меня v18.2.0 работает)

Если у вас всё ещё не стоит Rust, срочно исправляйте. Чтобы добавить возможность компилировать в wasm32-unknown-unknown выполните:

rustup target add wasm32-unknown-unknown

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

Все подготовительные работы завершены, давайте собирать:

make

Если всё прошло хорошо, должен появиться build/v86-debug.wasm

ls -la build/v86-debug.wasm
# -rwxr-xr-x  1 user  group  15446948 17 июн 15:47 build/v86-debug.wasm

Сборка образа Debian

Собирать образ будем через Docker, установите его.

Идём в папочку с образом:

cd tools/docker/debian

При использовании ветки master у меня возникала ошибка

WARNING: The requested image’s platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested

Если у вас появляется такая же (или похожая), исправить её очень просто. Нужно явно указать платформу linux/386 при сборке в файле build-container.sh

# diff --git a/tools/docker/debian/build-container.sh b/tools/docker/debian/build-container.sh
-docker build . --rm --tag "$IMAGE_NAME"
+docker build . --platform linux/386 --rm --tag "$IMAGE_NAME"
-docker create -t -i --name "$CONTAINER_NAME" "$IMAGE_NAME" bash
+docker create --platform linux/386 -t -i --name "$CONTAINER_NAME" "$IMAGE_NAME" bash

А в остальном всё просто, запускаем:

./build-container.sh

Если всё прошло гладко, последнее сообщение после сборки будет таким:

./../../../images/debian-9p-rootfs.tar, ./../../../images/debian-9p-rootfs-flat and ./../../../images/debian-base-fs.json created.

Собственно, файл images/debian-9p-rootfs.tar и папка images/debian-base-fs.json должны существовать.

Всё, этого достаточно для запуска нашего образа в браузере!

Стартуем

Нам потребуется добавить профиль с нашим образом и какой-нибудь веб сервер для отображения страницы. Начнём со второго.

Нам подойдёт любой вебсервер, готовый отдавать нам статику, я сейчас использую js’ный serve:

npm install -g serve

Теперь добавим профиль. Профили находятся в файле src/browser/main.js в переменной oses. Добавим в начало наш Debian:

var oses = [
    {
        id: "debian",
        name: "Debian",
        memory_size: 512 * 1024 * 1024,
        vga_memory_size: 8 * 1024 * 1024,
        bzimage_initrd_from_filesystem: true,
        cmdline: "rw init=/bin/systemd root=host9p console=ttyS0 spectre_v2=off pti=off",
        filesystem: {
            "baseurl": host + "debian-9p-rootfs-flat/",
            "basefs": { url: host + "debian-base-fs.json" }
        }
    },
    {
        id: "archlinux",
    ...

Сохраняем, идёт обратно в корень репы и запускаем наш веб сервер:

serve
#   ┌────────────────────────────────────────┐
#   │                                        │
#   │   Serving!                             │
#   │                                        │
#   │   Local:  http://localhost:3000        │
#   │                                        │
#   │   Copied local address to clipboard!   │
#   │                                        │
#   └────────────────────────────────────────┘

Идём смотреть на debian по адресу http://localhost:3000/debug?profile=debian

Загрузка займёт пару минут, наберитесь терпения. Если всё пойдёт хорошо, процесс загрузки будет выглядеть как-то так:

Сохраняем состояние после загруки

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

Для начала нужно дособрать необходимые зависимости (для этого нужна будет установленная java):

make all

Должен появится файл build/libv86.js

Идём обратно в папку с образом debian’а и сохраняемся.

cd tools/docker/debian/
./build-state.js

И просто ждите. Последнее сообщение будет выглядеть примерно так:

root@localhost:~# Saved as /user/v86/images/debian-state-base.bin

У меня охранённый state вышел на 130 метров, подъёмно:

ls -lah ../../../images/debian-state-base.bin
-rw-r--r--  1 user  group   130M 22 июн 22:56 ../../../images/debian-state-base.bin

Поравим немного наш профиль в src/browser/main.js:

var oses = [
    {
        id: "debian",
        name: "Debian",
        memory_size: 512 * 1024 * 1024,
        vga_memory_size: 8 * 1024 * 1024,
        state: {"url": host + "debian-state-base.bin" },
        filesystem: {
            "baseurl": host + "debian-9p-rootfs-flat/",
            "basefs": { url: host + "debian-base-fs.json" }
        }
    },
    ...

И снова идите смотреть http://localhost:3000/debug?profile=debian

Готово! Теперь этапа загрузки не должно быть и вас сразу должна встретить консоль.

Что дальше?

Самое очевидное - изменение образа в Dockerfile под свои нужны: ставьте и убирайте зависимости, или вообще используйте другие образы. Я, например, собрал себе slim-версию последнего Debian.

А в следующей части (которая выйдет кто знает когда) мы настроим интернет и будет полноценный (хоть и очень медленный) Linux в браузере!

До новых встреч!