Docker+Wasmを試してみた(Docker Engineのビルドから)
はじめに
DockerでWasmを実行できるDocker+Wasmがテクノロジープレビューとして発表されました。公式ドキュメントにはDocker Desktopのバイナリしか公開されていませんでしたが、GitHubリポジトリにWasm対応のDocker Engineをインストールする方法がありました。
個人アカウントのリポジトリですが、Docker社の人がCloud Native Wasm Day North America向けにつくったリポジトリのように思われます。
本記事は、上記の方法でWasm対応のDocker Engineをインストールして試した結果のまとめになります。
環境
- ホストOS:Ubuntu 22.04.1
作業ログ
以下を参考にインストールを進めます。
Docker+Wasmのインストール
前提条件
以下がインストールされていること
- Docker
- Docker Compose
本記事では上記ソフトウェアのインストールは割愛します。
nakkoh@dockerwasm:~$ docker -v
Docker version 20.10.21, build baeda1f
nakkoh@dockerwasm:~$ docker compose version
Docker Compose version v2.12.2
wasmEdgeのインストール
以下の図は、Docker+Wasmのコンポーネントを表しています。
図右下の緑の箱がwasmを実行するためのコンポーネントで、wasmEdgeとwasmEdge用のcontainerd shimが必要です。
nakkoh@dockerwasm:~$ curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all -p /usr/local
...
var? wasmedge-tensorflow-lite
0.11.2 0.11.2
Installation of wasmedge-tensorflow-lite-0.11.2 successfull
WasmEdge binaries accessible
containerd-wasm-shimのインストール
ちなみにですが、containerd-wasm-shimはkrustletの開発元であるDeis Labsが開発しているようです。 shimをWasmEdgeの開発元であるSecond Stateがフォークしたもののようです。
nakkoh@dockerwasm:~$ wget https://github.com/second-state/runwasi/releases/download/v0.3.2/containerd-shim-wasmedge-v1-v0.3.2-linux-amd64.tar.gz
...
nakkoh@dockerwasm:~$ tar -zxvf containerd-shim-wasmedge-v1-v0.3.2-linux-amd64.tar.gz
containerd-shim-wasmedge-v1
nakkoh@dockerwasm:~$ sudo mv containerd-shim-wasmedge-v1 /usr/local/bin/
dockerdのビルド & インストール
dockerdのビルド
nakkoh@dockerwasm:~$ git clone https://github.com/rumpl/moby.git && cd moby && git checkout wasmedge && make binary
Cloning into 'moby'...
remote: Enumerating objects: 345026, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 345026 (delta 0), reused 3 (delta 0), pack-reused 345019
Receiving objects: 100% (345026/345026), 184.11 MiB | 5.35 MiB/s, done.
Resolving deltas: 100% (229111/229111), done.
Branch 'wasmedge' set up to track remote branch 'wasmedge' from 'origin'.
Switched to a new branch 'wasmedge'
-bash: make: command not found
makeがなくて失敗。
makeをインストールしてから、再度ビルドを実行。
nakkoh@dockerwasm:~/moby$ sudo apt install make
...
nakkoh@dockerwasm:~/moby$ make binary
docker build --build-arg=GO_VERSION -f "Dockerfile" --output=bundles/ --target=binary --build-arg VERSION --build-arg DOCKER_GITCOMMIT --build-arg PRODUCT --build-arg PLATFORM --build-arg DEFAULT_PRODUCT_LICENSE --build-arg PACKAGER_NAME .
...
=> exporting to client 1.1s
=> => copying files 201.47MB
Docker+Wasmの要件として、Containerd Image Store (Beta)を有効にする必要があります。
イメージとファイルシステム管理に、containerdのsnapshotterを使うオプションのようです。
/etc/docker/daemon.json
{
"features": {
"containerd-snapshotter": true
}
}
Dockerデーモンをバックグラウンドで起動
nakkoh@dockerwasm:~/moby$ nohup sudo -b sh -c "./bundles/binary-daemon/dockerd -D -H unix:///tmp/docker.sock --data-root /tmp/root --pidfile /tmp/docker.pid"
nohup: ignoring input and appending output to 'nohup.out'
インストール済のdockerデーモンも起動しているため、dockerデーモンが2つ動作していることになります。
サンプルアプリの実行
Dockerコンテキストの作成と変更
通常のDockerデーモンとWasm対応版のDockerデーモンを一緒に起動しているため、Docker CLIでWasm対応版の方を操作するには新たにdockerコンテキストを作成する必要があります。
nakkoh@dockerwasm:~$ docker context create wasm --docker "host=unix:///tmp/docker.sock"
wasm
Successfully created context "wasm"
nakkoh@dockerwasm:~$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
wasm unix:///tmp/docker.sock
コンテキストの変更
nakkoh@dockerwasm:~$ docker context use wasm
wasm
Wasmアプリ(サーバープログラムでない)の実行
指定した文字列を返すプログラムを実行する。
nakkoh@dockerwasm:~$ docker run --runtime=io.containerd.wasmedge.v1 rumpl/wasmtest echo 'hello from wasm'
Unable to find image 'rumpl/wasmtest:latest' locally
7cbb9105cdaf: Download complete
dce2b2760aba: Download complete
004a1e2d62d7: Download complete
WARNING: The requested image's platform (wasi/wasm) does not match the detected host platform (linux/amd64/v2) and no specific platform was requested
hello from wasm
exiting
Wasmを実行できた!
また、wasmモジュールの一覧もコンテナイメージと同様の方法で確認できた。
nakkoh@dockerwasm:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rumpl/wasmtest latest 7cbb9105cdaf 49 minutes ago 505kB
Wasmアプリ(echoサーバー)の実行
今度は、以下を参考にサーバープログラムを実行する
nakkoh@dockerwasm:~$ 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
2a58923a21cb: Download complete
130eeaf02640: Download complete
e049f00c5289: Download complete
8debd860a04d808ea2b8ede5ed262a36501101208285b4963ecd32b48cc0a6e7
nakkoh@dockerwasm:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8debd860a04d michaelirwin244/wasm-example "hello_world.wasm" 7 seconds ago Up 6 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp wasm-example
httpでアクセスしてみる。
nakkoh@dockerwasm:~$ curl localhost:8080
Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to younakkoh@dockerwasm:~$
nakkoh@dockerwasm:~$ curl -X POST -d "hello!" localhost:8080/echo
hello!
wasmでサーバープログラムを実行することができた。
Docker ComposeでWasmアプリを実行
以下を参考に実施する。
以下のcomposeファイルを使用する。
services:
app:
image: michaelirwin244/wasm-example
platform: wasi/wasm32
runtime: io.containerd.wasmedge.v1
ports:
- 8080:8080
アプリ自体は上で実行したechoサーバーと同じ。
先程実行したwasmアプリを削除する。
nakkoh@dockerwasm:~$ docker rm -f 8debd860a04d
8debd860a04d
nakkoh@dockerwasm:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker composeでアプリを起動
nakkoh@dockerwasm:~$ docker compose -f echo-server/docker-compose.yaml up -d
[+] Running 1/1
⠿ Container echo-server-app-1 Started 0.2s
nakkoh@dockerwasm:~$ docker compose -f echo-server/docker-compose.yaml ps
NAME COMMAND SERVICE STATUS PORTS
echo-server-app-1 "hello_world.wasm" app running 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
nakkoh@dockerwasm:~$ curl localhost:8080
Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to younakkoh@dockerwasm:~$
multi-serviceアプリの実行
Wasmとコンテナのワークロードが混在したアプリにも対応している。
gitリポジトリをcloneする。
nakkoh@dockerwasm:~$ git clone https://github.com/second-state/microservice-rust-mysql.git
...
nakkoh@dockerwasm:~$ cd microservice-rust-mysql/
以下のcomposeファイルを使用する。
services:
client:
image: nginx:alpine
ports:
- 8090:80
volumes:
- ./client:/usr/share/nginx/html
server:
image: demo-microservice
build:
context: .
platforms:
- wasi/wasm32
ports:
- 8080:8080
environment:
DATABASE_URL: mysql://root:whalehello@db:3306/mysql
RUST_BACKTRACE: full
restart: unless-stopped
runtime: io.containerd.wasmedge.v1
db:
image: mariadb:10.9
environment:
MYSQL_ROOT_PASSWORD: whalehello
serverがwasmで動き、nginxとmariadbがコンテナで動作するアプリのようである。
serverはビルドから実施される。
先程のアプリと同じ8080番ポートを使うので、事前にアプリを削除する必要がある。
nakkoh@dockerwasm:~/microservice-rust-mysql$ docker compose -f ~/echo-server/docker-compose.yaml down
[+] Running 2/2
⠿ Container echo-server-app-1 Removed 0.1s
⠿ Network echo-server_default Removed 0.0s
composeファイルからアプリを起動
nakkoh@dockerwasm:~/microservice-rust-mysql$ docker compose up -d
...
[+] Running 3/3
⠿ Container microservice-rust-mysql-db-1 Started 0.9s
⠿ Container microservice-rust-mysql-client-1 Started 0.9s
⠿ Container microservice-rust-mysql-server-1 Started 0.6s
nakkoh@dockerwasm:~/microservice-rust-mysql$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
microservice-rust-mysql-client-1 "/docker-entrypoint.…" client running 0.0.0.0:8090->80/tcp, :::8090->80/tcp
microservice-rust-mysql-db-1 "docker-entrypoint.s…" db running 3306/tcp
microservice-rust-mysql-server-1 "order_demo_service.…" server running 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
ビルドが走るため時間がかかったが、アプリが起動したようである。
イメージを確認
nakkoh@dockerwasm:~/microservice-rust-mysql$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-microservice latest 6b8ad69b0139 9 minutes ago 3.06MB
mariadb 10.9 bb39098029f4 18 minutes ago 124MB
nginx alpine 2452715dd322 18 minutes ago 10.2MB
michaelirwin244/wasm-example latest 2a58923a21cb 4 hours ago 1.57MB
rumpl/wasmtest latest 7cbb9105cdaf 5 hours ago 505kB
ブラウザからhttp://localhost:8090にアクセスする。
Add an order
に値を入力し、orderを追加する。
追加したorderが表示されるようになった。
Wasmモジュールのビルドとプッシュ
Rustのhello-worldをビルドしてみる。
nakkoh@dockerwasm:~/hello$ tree .
.
├── Dockerfile
└── src
└── hello.rs
1 directory, 2 files
src/hello.rs
fn main() {
println!("Hello World!");
}
Dockerfile
FROM rust:1.65
COPY src ./src
RUN rustup target add wasm32-wasi
RUN rustc ./src/hello.rs --target wasm32-wasi
FROM scratch
COPY ./hello.wasm /hello.wasm
ENTRYPOINT [ "hello.wasm" ]
ビルドする。
nakkoh@dockerwasm:~/hello$ docker buildx build --platform wasi/wasm32 -t nakkoh/hello .
[+] Building 39.8s (11/11) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 256B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/rust:1.65 3.1s
=> [auth] library/rust:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 110B 0.0s
=> [stage-0 1/4] FROM docker.io/library/rust:1.65@sha256:b0f2a9e48df82f009fda8ae777119e7983104a1b4dc47026653b6cdaf447d14b 30.7s
=> => resolve docker.io/library/rust:1.65@sha256:b0f2a9e48df82f009fda8ae777119e7983104a1b4dc47026653b6cdaf447d14b 0.0s
=> => sha256:a027b53f293bcf73812c9d074bc8e0da83c4752c6d7d8b0891d60245b804fdcb 157.29MB / 158.46MB 36.6s
=> => extracting sha256:a027b53f293bcf73812c9d074bc8e0da83c4752c6d7d8b0891d60245b804fdcb 4.2s
=> [stage-0 2/4] COPY src ./src 0.2s
=> [stage-0 3/4] RUN rustup target add wasm32-wasi 5.1s
=> [stage-0 4/4] RUN rustc ./src/hello.rs --target wasm32-wasi 0.2s
=> [stage-1 1/1] COPY --from=0 ./hello.wasm /hello.wasm 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => exporting manifest sha256:2b384a1565fa1c81cf9d25717c04ca630ad13185434ac855026c9fa0474253f7 0.0s
=> => exporting config sha256:345d594325b1677723258788f820d1741463468c845ac62b11215dfaea482241 0.0s
=> => naming to docker.io/nakkoh/hello:latest 0.0s
=> => unpacking to docker.io/nakkoh/hello:latest 0.0s
nakkoh@dockerwasm:~/hello$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-microservice latest 6b8ad69b0139 3 hours ago 3.06MB
mariadb 10.9 bb39098029f4 4 hours ago 124MB
nginx alpine 2452715dd322 4 hours ago 10.2MB
michaelirwin244/wasm-example latest 2a58923a21cb 7 hours ago 1.57MB
nakkoh/hello latest 2b384a1565fa 19 seconds ago 502kB
rumpl/wasmtest latest 7cbb9105cdaf 8 hours ago 505kB
ビルドしたwasmモジュールを実行
nakkoh@dockerwasm:~/hello$ docker run --runtime=io.containerd.wasmedge.v1 nakkoh/hello
WARNING: The requested image's platform (wasi/wasm32) does not match the detected host platform (linux/amd64/v2) and no specific platform was requested
Hello World!
Docker Hubにプッシュ
nakkoh@dockerwasm:~/hello$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: nakkoh
Password:
...
Login Succeeded
nakkoh@dockerwasm:~/hello$ docker push nakkoh/hello
Using default tag: latest
345d594325b1: Pushed
880ce0c71f28: Pushed
2b384a1565fa: Pushed
latest: digest: sha256:2b384a1565fa1c81cf9d25717c04ca630ad13185434ac855026c9fa0474253f7, size: 5266
所感
コンテナと同じ操作で、wasmの実行、ビルド、プッシュできるので、気軽にwasmを使うことができます。
コンテナとwasmのワークロードが混在するアプリもつくることができるので、ユースケースに合わせてコンテナとwasmを選択するといった開発もできます。
Dockerがwasm対応したことで今後、よりwasmが注目されるようになると思うので、引き続き動向を追っていきたいなと思います。
Discussion