WebAssembly Runtime

wasm(WebAssembly)のランタイムについて、いろいろ調べてみました。
WebAssemblyは何度も扱ってきていますが、WATコード(WebAssembly Text)からコンパイルを試したことがありませんでした。まずは基本を押さえたいと思います。(参考:翔泳社「入門WebAssembly」)

環境) M2 Mac

myadd.wat

value 1,2をスタックに積んで、関数呼び出し。まさにアセンブラですね。

myadd.js

% node -v
v18.12.1
% npm -v
8.19.2
% npm install -g wat-wasm

% wat2wasm myadd.wat

  Contact Rick Battagline
  Twitter: @battagline
  https://wasmbook.com
  v1.0.43

no memory
Writing to myadd.wasm
WASM File Saved!

% node myadd.js 1 2
1 + 2 = 3

wat2wasmで、バイトコードに、そしてそれをnode.jsから呼び出しました。

次は、node.jsではなく、wasmtimeというランタイムを使って実行してみます。(brew でインストール)

引用元)https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-tutorial.md

demo.wat

% wasmtime -V
wasmtime-cli 10.0.1
% wasmtime demo.wat
hello world
% wat2wasm demo.wat

  Contact Rick Battagline
  Twitter: @battagline
  https://wasmbook.com
  v1.0.43

memory found
Writing to demo.wasm
WASM File Saved!
% wasmtime demo.wasm
hello world

先ほどのWATコードでは、実行はできますが標準出力に書かないためコードを変えています。
(watから直接実行もできるもよう)

ファイル確認

% file demo.wasm
demo.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)
% file myadd.wasm
myadd.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

次は、Rustのコードからコンパイルするため、環境をdockerで構築しました。
引用元) https://qiita.com/toshikisugiyama/items/168cdbf834156b1f1e70

docker-compose.yml

% docker compose run –rm rust

このコマンドで一気に環境を作り、コンテナのシェルの状態になります。

root@f4b90a7fb5a9:/projects# cargo new hello_cargo
  Created binary (application) hello_cargo package

root@f4b90a7fb5a9:/projects# ls
docker-compose.yml hello_cargo

root@f4b90a7fb5a9:/projects# cd hello_cargo/
root@f4b90a7fb5a9:/projects/hello_cargo# ls
Cargo.toml src

root@f4b90a7fb5a9:/projects/hello_cargo# cargo run
  Compiling hello_cargo v0.1.0 (/projects/hello_cargo)
  Finished dev [unoptimized + debuginfo] target(s) in 1.07s
  Running target/debug/hello_cargo
Hello, world!

デフオルトプロジェクトの状態で実行できることを確認できました。(これはwasmではない)

hello_cargo/src/main.rs

カレントフォルダとコンテナの/projectsが、マウントされているため、ファイルの編集は別コンソールで、できます。(コマンド実行だけコンテナからやればよいことにことに)

そして、この環境を使って、wasmtimeの例を動かしてみます。
引用元) https://wasmtime.dev/

root@f4b90a7fb5a9:/projects# rustup target add wasm32-wasi
info: downloading component ‘rust-std’ for ‘wasm32-wasi’
info: installing component ‘rust-std’ for ‘wasm32-wasi’
root@f4b90a7fb5a9:/projects# rustc hello.rs –target wasm32-wasi
root@f4b90a7fb5a9:/projects# wasmtime hello.wasm
bash: wasmtime: command not found

コンテナにはwasmtimeを入れていないので、カレントに戻り、

% wasmtime hello.wasm
Hello, world!

(hello.rsは、上記 hello_cargo/src/main.rs と全く同じ)
Rustコードをwasmにコンパイルして実行できることを確認しました。

そして次は、wasmをコンテナにして実行してみます。
引用元) https://developer.mamezou-tech.com/blogs/2023/01/25/using-wasm-on-docker/

% docker run -dp 8080:8080 –name=wasm-example –runtime=io.containerd.wasmedge.v1 –platform=wasi/wasm32 michaelirwin244/wasm-example
Unable to find image ‘michaelirwin244/wasm-example:latest’ locally
latest: Pulling from michaelirwin244/wasm-example
docker: operating system is not supported.
See ‘docker run –help’.

Use containerd for pulling and storing images -> on にします。

% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
029a5376af41 michaelirwin244/wasm-example “/hello_world.wasm” 14 seconds ago Up 9 seconds 0.0.0.0:8080->8080/tcp wasm-example
% docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
michaelirwin244/wasm-example latest 1b0714a5af55 37 seconds ago 4.14MB

% curl localhost:8080
Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to you%
% curl -X POST -d abcdefg localhost:8080
% curl -X POST -d abcdefg localhost:8080/echo
abcdefg%

うまく立ち上がり動作も確認できました。(POST /echo の場合はBodyをEcho)

でもこれではwasmかどうかわかりませんので、サーバの部分を単体で動かしてみます。
(引用元の情報を参考にダウンロード)

% git clone https://github.com/mikesir87/wasm-example.git

% cd wasm-example

コンテナでコマンド実行

root@bea36f5878ef:/projects/wasm-example# rustup target add wasm32-wasi
info: downloading component ‘rust-std’ for ‘wasm32-wasi’
info: installing component ‘rust-std’ for ‘wasm32-wasi’
root@bea36f5878ef:/projects/wasm-example# cargo build –target wasm32-wasi –release

カレントに戻りwasmtime実行

% wasmtime run –tcplisten 127.0.0.1:8080 target/wasm32-wasi/release/hello_world.wasm
Error: failed to run main module target/wasm32-wasi/release/hello_world.wasm

Caused by:
  0: failed to instantiate “target/wasm32-wasi/release/hello_world.wasm”
  1: unknown import: wasi_snapshot_preview1::sock_setsockopt has not been defined

うまく行かず。。。
Runtimeをwasmedgeに差し替えてチャレンジ。

% curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
Using Python: /Users/z/.pyenv/versions/miniforge3-4.10.3-10/bin/python3
INFO – Compatible with current configuration
INFO – Running Uninstaller
WARNING – Uninstaller did not find previous installation
WARNING – SHELL variable not found. Using zsh as SHELL
INFO – shell configuration updated
INFO – Downloading WasmEdge
|============================================================|100.00 %INFO – Downloaded
INFO – Installing WasmEdge
INFO – WasmEdge Successfully installed
INFO – Run:
source /Users/z/.zshenv

% wasmedge target/wasm32-wasi/release/hello_world.wasm
Server is now running

これで、さほどのPOST /echo のcurlアクセスもうまくいきました。(dockerのwasm runtimeはwasmtimeと違うようです)

wasm-example/src/main.rs

ここまでwasmの動かし方について、いろいろ試してみました。前回Goを試しましたがいろいろ調べてみるとRustが非常に向いていると感じました。(まだ関数コールをやる必要がありますが、これは次の機会に・・)
下記サイトに、Goとwasmの関係について、とても参考になる記事があります。

「GoのWASMがライブラリではなくアプリケーションであること」
https://www.kabuku.co.jp/developers/annoying-go-wasm

RustはOSすらないベアメタル環境でもプログラムを動作させることができます。様々なところで実行できるwasmだけに、こういった成り立ちの違いが大きく影響するのではと感じました。

About

Categories: 未分類 タグ: , ,