🦍

自作Wasm Runtimeをcontainerdで動かしてみた

2023/09/18に公開

はじめに

以前に、RustでWasm Runtimeを実装したという記事を書きました。

https://zenn.dev/skanehira/articles/2023-04-23-rust-wasm-runtime

それ以来しばらく放置していたのですが、先日開催されたWebAssembly night #11に参加してモチベーションが上がってきたので、以前から試そうと思っていた自作Wasm Runtimeをコンテナランタイムと連携して動かすのを実際にやってみました。

この記事は詳しい説明はせず、概ねどんなことをやったのかの記録となっています。
また、筆者はコンテナランタイムに疎いので雰囲気で書いているところもあるので、間違いなどがありましたらコメントなどで教えていただければと思います。

成果物

実装はこちらにおいてあります。

https://github.com/skanehira/containerd-shim-chibiwasm

こんな感じで動きます。

skanehira@pi1:~/work$ ls -la /usr/local/bin/
total 118208
drwxr-xr-x  2 root root     4096 Sep 18 12:46 .
drwxr-xr-x 10 root root     4096 Feb 18  2023 ..
-rwxr-xr-x  1 root root 40118648 Jun  3 08:06 containerd
-rwxr-xr-x  1 root root  6422528 Jun  3 08:06 containerd-shim
-rwxr-xr-x  1 root root 15901680 Sep 18 12:46 containerd-shim-chibiwasm-v1
-rwxr-xr-x  1 root root  8060928 Jun  3 08:06 containerd-shim-runc-v1
-rwxr-xr-x  1 root root 11534336 Jun  3 08:06 containerd-shim-runc-v2
-rwxr-xr-x  1 root root 18939904 Jun  3 08:06 containerd-stress
-rwxr-xr-x  1 root root 20054016 Jun  3 08:06 ctr
skanehira@pi1:~/work$ cat Dockerfile 
FROM scratch
COPY ./hello.wasm /hello.wasm
ENTRYPOINT [ "/hello.wasm" ]
skanehira@pi1:~/work$ sudo ctr images list
REF                                 TYPE                                    DIGEST                                                                  SIZE      PLATFORMS                   LABELS 
docker.io/library/hello-wasm:latest application/vnd.oci.image.index.v1+json sha256:fd9c651890a70a636941e5083fc4b914f677aa5f22e7fafa5abcbdeae625023e 503.0 KiB linux/arm64,unknown/unknown -      
skanehira@pi1:~/work$ sudo ctr run --rm --runtime=io.containerd.chibiwasm.v1 docker.io/library/hello-wasm:latest hello-wasm
Hello, World!
skanehira@pi1:~/work$ 

containerd-shim-wasm

去年にDockerWasm対応を発表されてました。
通常のLinuxコンテナの代わりにWasmを実行できるといった内容でした。

https://www.docker.com/blog/docker-wasm-technical-preview/

記事内にある次の図を見ると、コンテナを直接作成するruncに代わってwasmedgeといったWasm Runtimeを使っていました。
そして、containerdruncの橋渡し役であるcontainerd-shimcontainerd-shim-wasmに代わっていました。

つまり、自作Runtimeに対応したcontainerd-shim-wasmを用意すれば、オレオレWasm Runtimeを動かせそうということがわかります。

ちなみに、--runtimeで指定したランタイムio.containerd.wasmedge.v1/usr/local/binなどPATHが通っている場所にあるcontainerd-shim-wasmtime-v1バイナリにマッピングされます。
バイナリがなければエラーになります。
つまり、containerd-shim-chibiwasm-v1という名前で配置すればio.containerd.chibiwasm.v1というランタイム名になるとういことですね。

runwasi

では、containerd-shim-xxxはどうやって用意すればいいのか?という話は次のブログを読めば大体わかります。

https://bokuweb.github.io/undefined/articles/20230224.html

簡潔にいうとrunwasiを使います。
使用するクレートは次の2つになります。

containerdshimの間ではttrpcを使って通信するようですが、そこの処理はcontainerd-shimクレートがやっているっぽい(未確認)です。
なので、Instanceトレイトを満たすように、コンテナの起動や停止、削除といった処理を実装するだけで動くようになっています。

今回はほぼrunwasiが提供しているcontainerd-shim-wasmtimeの実装をそのまま使いました。

https://github.com/skanehira/containerd-shim-chibiwasm/blob/fc2bd5cb6224c5f90950e8287811d4fd3abcf7f6/src/lib.rs#L124-L162

やっていることはスレッドでコンテナを作成、起動して、終了待ちをしています。

ここで「runcの代わりにWasm Runtimeを使うのに結局コンテナを作るの?」と疑問に思ったんのですが、どうやらコンテナを作成してその中でWasm Runtimeを使ってWasmを実行するようです。

次の処理はlibcontainerというクレートを使ってコンテナを作成していて、with_executorChibiwasmExecutorを指定しています。

https://github.com/skanehira/containerd-shim-chibiwasm/blob/fc2bd5cb6224c5f90950e8287811d4fd3abcf7f6/src/lib.rs#L211-L233

ChibiwasmExecutorlibcontainerExecutorトレイトを実装していて、その中で自作したWasm Runtimeを使ってコンテナ内にあるWasmバイナリを読み取って実行しています。

https://github.com/skanehira/containerd-shim-chibiwasm/blob/fc2bd5cb6224c5f90950e8287811d4fd3abcf7f6/src/executor.rs#L21-L80

実装はこれで大体終わりで、あとはバイナリをビルドしてPATHが通った場所に配置して--runtime=io.containerd.chibiwasm.v1を指定すれば動きます。

skanehira@pi1:~/work$ sudo ctr run --rm --runtime=io.containerd.chibiwasm.v1 docker.io/library/hello-wasm:latest hello-wasm
Hello, World!

さいごに

実際に自作Wasm Runtimecontainerdで動かせるようにしてみて、コンテナが作られないと勘違いしていたことがわかってよかったです。
そして思ったよりもコンテナランタイムのこと何もわからないことがわかったので、機会があれば深掘りしていきたいと思っています。

ちなみに、k8sやDockerで試していないのですが、contianerdで動くので基本的に動くと思います。

Discussion