PerlerのRuby日記

Rubyとか

Ruby 3.2 で WASI の WebAssembly を Docker で動かす

www.ruby-lang.org
docs.docker.com

Ruby 3.2 がリリースされて、WebAssembly や WASI が動くようになったのと、Docker Desktop に WebAssembly ランタイム(WasmEdge)が統合されたりしたので両方やってみたメモ。

公式 README

ruby.wasm/README.md

依存

Dependencies: wasi-vfs, wasmtime

wasi-vfs

Ruby の WebAssembly は Ruby 本体の wasm ファイルも必要になるらしい。wasi-vfs を使ってその Ruby 本体とスクリプトを合体するとのこと。

なので、まずはそれを可能にするツールである wasi-vfs をインストールする。macOS なので手っ取り早く Homebrew 使ってしまった。

$ brew tap kateinoigakukun/wasi-vfs https://github.com/kateinoigakukun/wasi-vfs.git
$ brew install kateinoigakukun/wasi-vfs/wasi-vfs

が、Rust での cargo install が走るので普通にバイナリの Zip を解凍する方が早そうだった。

Wasmtime

WASI ランタイムの実装のひとつである Wasmtime も先にインストールする。今のところ、Wasmtime はランタイムの五強の中で僅差で一番使われている位置にいるらしい。

ref. https://blog.scottlogic.com/2022/06/20/state-of-wasm-2022.html

$ brew install wasmtime

Ruby で WASI の WebAssembly を動かす

README どおりやってみる。

$ curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-head-wasm32-unknown-wasi-full.tar.gz
$ tar xfz ruby-head-wasm32-unknown-wasi-full.tar.gz
$ mv head-wasm32-unknown-wasi-full/usr/local/bin/ruby ruby.wasm

$ mkdir src
$ echo "puts 'Hello'" > src/my_app.rb

$ wasi-vfs pack ruby.wasm --mapdir /src::./src --mapdir /usr::./head-wasm32-unknown-wasi-full/usr -o my-ruby-app.wasm

$ wasmtime my-ruby-app.wasm /src/my_app.rb
Hello

できた。my-ruby-app.wasm は、約 32.8 MB となって、やはり Rust などで出す wasm よりもちょっと大きい印象。

Ruby で WASI の WebAssembly を Docker で動かす

作った my-ruby-app.wasm を Docker Desktop で動かしてみる。

Docker Desktop の v4.15.0 から WASI ランタイムの実装の1つである WasmEdge が同梱されたが、まだデフォルトでは有効になっていないらしく、設定の「Features in development」から「Use containerd for pulling and storing images」のチェックボックスにチェックを入れて再起動する。

※ 注意メッセージにあるとおり、現在は、WebAssembly が扱えるようになる代わり、既存の所持イメージやコンテナが消えてしまう。消えたように見えるが、実際には消えていなくて、再度チェックボックスのチェックを外して再起動すればちゃんと残っている

Dockerfile
FROM scratch
COPY ./my-ruby-app.wasm /my-ruby-app.wasm
ENTRYPOINT ["my-ruby-app.wasm"]
Docker ビルド
$ docker buildx build \
    --platform wasi/wasm32 \
    -t wasi-docker:ruby_wasm .
Docker 実行
$ docker container run --rm \
    --runtime=io.containerd.wasmedge.v1 \
    --platform=wasi/wasm32 \
    wasi-docker:ruby_wasm \
    /src/my_app.rb
Hello

できた。Gemfile で色々ライブラリを使ったときはどうなるんだろう。