Docker 24リリース! containerdイメージストア統合の実験的サポートでWASMを動かそう #docker #containerd #stargz #webassembly #wasm #wasi
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
2023年5月17日に Docker 24.0.0 が正式リリースされ、引き続き 2023年5月29日にバグフィックスリリースである v24.0.1 がリリースされました。
「あれ、まだ2024年じゃないけど?」と思われた方もいるかもしれません。Docker 23.0.0から、YY.MM.zz という年月バージョン番号ポリシーから セマンティックバージョニング に変更されているため、このような大きな数字になっています。
v24.0.0 での目玉機能は、containerdイメージストア統合の実験的サポート と思われます。この実験的機能を有効にすることでイメージの格納・プッシュ・プルに、Docker独自のイメージストアではなく、containerdのイメージストアを利用できるようになります。以前24ベータ版で試用してみましたが、本稿では v24.0.1 正式版でcontainerdイメージストア統合の実験的サポートを有効にしてみます。
注意: 本稿の内容は実験であり、本番環境では利用できません。また、開発中のソフトウェアを多数利用しているため、今後動作が変更される可能性があります。
事前準備
Virtualbox に RockyLinux 9 を準備して、こちらで実験環境を作っていきます。
Docker 24.0.1 は正式リリースされたので 通常のインストール手順 でインストール可能です。テスト版レポジトリの設定など特殊な手順は必要ありません。
[vagrant@node1 ~]$ docker version Client: Docker Engine - Community Version: 24.0.1 API version: 1.43 Go version: go1.20.4 Git commit: 6802122 Built: Fri May 19 18:07:44 2023 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 24.0.1 API version: 1.43 (minimum version 1.12) Go version: go1.20.4 Git commit: 463850e Built: Fri May 19 18:06:05 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.21 GitCommit: 3dce8eb055cbb6872793272b4f20ed16117344f8 runc: Version: 1.1.7 GitCommit: v1.1.7-0-g860f061 docker-init: Version: 0.19.0 GitCommit: de40ad0 [vagrant@node1 ~]$
インストール直後はDocker独自のイメージストアを利用しています。
[vagrant@node1 ~]$ docker system info (略) Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 24.0.1 Storage Driver: overlay2 Backing Filesystem: xfs (略)
containerdイメージストアへの切り替え
では、Docker独自のイメージストアから、containerdのイメージストアに切り替えてみましょう。24ベータ版 と同様に、containerd/stargz-snapshotter の手順に従います。
Dockerデーモンの設定を変更します。
[vagrant@node1 ~]$ cat | sudo tee -a /etc/docker/daemon.json { "features": { "containerd-snapshotter": true }, "storage-driver": "stargz" } [vagrant@node1 ~]$
containerdの設定を変更します。
[vagrant@node1 ~]$ sudo cp -a /etc/containerd/config.toml config.toml.orig [vagrant@node1 ~]$ cat | sudo tee /etc/containerd/config.toml version = 2 # Plug stargz snapshotter into containerd [proxy_plugins] [proxy_plugins.stargz] type = "snapshot" address = "/run/containerd-stargz-grpc/containerd-stargz-grpc.sock" [vagrant@node1 ~]$
fuseをインストールします。ここではインストール済みです。
[vagrant@node1 ~]$ sudo yum install -y fuse Last metadata expiration check: 0:11:06 ago on Thu 25 May 2023 06:40:57 AM UTC. Package fuse-2.9.9-15.el9.x86_64 is already installed. Dependencies resolved. Nothing to do. Complete! [vagrant@node1 ~]$ sudo modprobe fuse [vagrant@node1 ~]$
stargz-snapshotterの本稿執筆時点最新のバージョンv0.14.3バイナリとsystemdユニットファイルをインストールします。
[vagrant@node1 ~]$ sudo tar -C /usr/local/bin/ -xvf stargz-snapshotter-v0.14.3-linux-amd64.tar.gz containerd-stargz-grpc ctr-remote stargz-store [vagrant@node1 ~]$ sudo curl -L https://raw.githubusercontent.com/containerd/stargz-snapshotter/v0.14.3/script/config/etc/systemd/system/stargz-snapshotter.service -o /etc/systemd/system/stargz-snapshotter.service [vagrant@node1 ~]$ sudo chcon system_u:object_r:systemd_unit_file_t:s0 /etc/systemd/system/stargz-snapshotter.service [vagrant@node1 ~]$ sudo systemctl enable --now stargz-snapshotter Created symlink /etc/systemd/system/multi-user.target.wants/stargz-snapshotter.service → /etc/systemd/system/stargz-snapshotter.service. [vagrant@node1 ~]$
containerdとDockerデーモンを再起動します。
[vagrant@node1 ~]$ sudo systemctl restart containerd [vagrant@node1 ~]$ sudo systemctl restart docker [vagrant@node1 ~]$
イメージストアが切り替わったかどうか確認しましょう。
[vagrant@node1 ~]$ docker system info (略) Server Version: 24.0.1 Storage Driver: stargz driver-type: io.containerd.snapshotter.v1 Logging Driver: json-file (略)
ストレージドライバが stargz 、ドライバタイプが io.containerd.snapshotter.v1 になっていれば切り替え完了です。
イメージストアの確認
実際にイメージをプルして確認してみましょう。
まず、Dockerとcontainerdのどちらでもイメージが存在しないことを確認します。
[vagrant@node1 ~]$ docker image ls -a REPOSITORY TAG IMAGE ID CREATED SIZE [vagrant@node1 ~]$ sudo ctr --namespace moby image ls REF TYPE DIGEST SIZE PLATFORMS LABELS [vagrant@node1 ~]$
Dockerで nginx:1.22 イメージをプルしてみます。
[vagrant@node1 ~]$ docker image pull nginx:1.22 fc5f5fb75747: Download complete 908106471267: Download complete 0f8498f13f3a: Download complete 2a9f38700bb5: Download complete ef2fc869b944: Download complete ac713a9ef2cc: Download complete fd071922d543: Download complete f1f26f570256: Download complete fd03b214f774: Download complete docker.io/library/nginx:1.22 [vagrant@node1 ~]$
Dockerとcontainerdの両方でイメージを確認してみましょう。
[vagrant@node1 ~]$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nginx 1.22 fc5f5fb75747 18 seconds ago 211MB [vagrant@node1 ~]$ sudo ctr --namespace moby image ls REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/library/nginx:1.22 application/vnd.docker.distribution.manifest.list.v2+json sha256:fc5f5fb7574755c306aaf88456ebfbe0b006420a184d52b923d2f0197108f6b7 54.4 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x - [vagrant@node1 ~]$
Dockerでプルした nginx:1.22 イメージが、containerdのイメージストアでも見えているので、切り替えが正常に完了しています。
DockerでWASM/WASIを動かす設定
では、DockerでWASI (WebAssembly System Interface)を動かせるように設定しましょう。ここでは WasmEdge と runwasi を使います。過去の手順は「DockerでWASMを動かそう」をご覧ください。
まず、WasmEdgeをインストールします。本稿執筆時点のWasmEdge最新版 0.12.1 では runwasi との組み合わせがうまく動かないので、少しバージョンの古い 0.11.2 をインストールします。詳細は過去記事「KubernetesでWASMを動かそう」をご覧ください。
[vagrant@node1 ~]$ curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2 (略) WasmEdge Successfully installed Run: source /home/vagrant/.bashrc [vagrant@node1 ~]$ sudo cp -a .wasmedge/lib/libwasmedge.so* /usr/local/lib/ [vagrant@node1 ~]$ sudo -E sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/libwasmedge.conf' [vagrant@node1 ~]$ sudo ldconfig [vagrant@node1 ~]$ ldd ./.wasmedge/bin/wasmedge linux-vdso.so.1 (0x00007ffe6c988000) libwasmedge.so.0 => /usr/local/lib/libwasmedge.so.0 (0x00007f3becacb000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f3bec8a4000) libm.so.6 => /lib64/libm.so.6 (0x00007f3bec7c9000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f3bec7ae000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3bec7a9000) libc.so.6 => /lib64/libc.so.6 (0x00007f3bec5a0000) librt.so.1 => /lib64/librt.so.1 (0x00007f3bec599000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f3bec594000) libz.so.1 => /lib64/libz.so.1 (0x00007f3bec57a000) /lib64/ld-linux-x86-64.so.2 (0x00007f3bef75b000) [vagrant@node1 ~]$ ./.wasmedge/bin/wasmedge --version ./.wasmedge/bin/wasmedge version 0.11.2 [vagrant@node1 ~]$
runwasi をインストールします。本稿執筆時点では runwasi のビルド済みバイナリが配布されていないため(参照tar.gz files included in releases are empty)、過去記事「DockerでWASMを動かそう」でビルドしたバイナリを利用します。ビルド方法の詳細はそちらをご覧ください。
$ git clone https://github.com/containerd/runwasi $ cd runwasi $ git checkout containerd-shim-wasm/v0.1.2 $ docker image build -t runwasi . (略) $ docker image save runwasi | tar xf - $ tar xvf XXXXX/layer.tar containerd-shim-wasmedge-v1 containerd-shim-wasmedged-v1 containerd-shim-wasmtime-v1 containerd-shim-wasmtimed-v1 containerd-wasmedged containerd-wasmtimed wasi-demo-app $
[vagrant@node1 ~]$ sudo cp containerd-* /usr/bin/ [vagrant@node1 ~]$ sudo ldd /usr/bin/containerd-shim-wasmedge-v1 linux-vdso.so.1 (0x00007ffe065f7000) libwasmedge.so.0 => /usr/local/lib/libwasmedge.so.0 (0x00007f47dda1e000) libc.so.6 => /lib64/libc.so.6 (0x00007f47dd815000) /lib64/ld-linux-x86-64.so.2 (0x00007f47e0a47000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f47dd7fa000) librt.so.1 => /lib64/librt.so.1 (0x00007f47dd7f5000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f47dd7f0000) libm.so.6 => /lib64/libm.so.6 (0x00007f47dd715000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f47dd70e000) libz.so.1 => /lib64/libz.so.1 (0x00007f47dd6f4000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f47dd4cd000) [vagrant@node1 ~]$
これでDockerでWASM/WASIを動かす準備ができました。
runwasiのテスト
では動作テストとして、Running a Wasm application with docker run のサンプル WASM アプリケーションを実行してみましょう。
[vagrant@node1 ~]$ docker container 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 fb4e36b5f8158f12717a38d626488b5ef01fcca89aa2563b4be0634a9b3aec1c [vagrant@node1 ~]$ curl localhost:8080 ; echo Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to you [vagrant@node1 ~]$ curl -d 'Hello, world!' localhost:8080/echo ; echo Hello, world! [vagrant@node1 ~]$ docker container rm -f wasm-example wasm-example [vagrant@node1 ~]$
問題なくサンプル WASM アプリを実行することができました。動作も問題ないようです。
WASMのDockerイメージの作成
前項では準備済みのWASMのDockerイメージを使いましたが、自作もしてみましょう。
まずはWASMバイナリを作成する必要があります。過去記事「RubyでWebAssemblyを試してみよう」で作成した hello.wasm をDockerイメージにしてみましょう。WASMバイナリの詳細な作成手順はそちらをご覧ください。
% mkdir src % echo 'puts "Hello, world!"' > src/hello.rb % export WASI_VFS_VERSION=0.2.0 % curl -LO "https://github.com/kateinoigakukun/wasi-vfs/releases/download/v${WASI_VFS_VERSION}/wasi-vfs-cli-x86_64-unknown-linux-gnu.zip" % unzip wasi-vfs-cli-x86_64-unknown-linux-gnu.zip % curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-3_2-wasm32-unknown-wasi-full.tar.gz % tar xf ruby-3_2-wasm32-unknown-wasi-full.tar.gz % curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v7.0.0/wasmtime-v7.0.0-x86_64-linux.tar.xz % tar xf wasmtime-v7.0.0-x86_64-linux.tar.xz % ./wasi-vfs pack ./3_2-wasm32-unknown-wasi-full/usr/local/bin/ruby --mapdir /src::./src --mapdir /usr::./3_2-wasm32-unknown-wasi-full/usr -o hello.wasm % file ./hello.wasm ./hello.wasm: WebAssembly (wasm) binary module version 0x1 (MVP) %
次にこの hello.wasm をDockerイメージとします。過去記事「DockerでWASMを動かそう」の手順は、実は間違っていました。あらためて本稿でWASMをDockerイメージとする手順を見ていきます。
まず新しくディレクトリを作り、その中に hello.wasm と次のDockerfileを配置します。
FROM scratch COPY hello.wasm /hello.wasm ENTRYPOINT [ "hello.wasm", "/src/hello.rb" ]
ここでDockerfileをビルド…する前に準備が必要です。過去記事「DockerでWASMを動かそう」では、この準備が抜けていました。linux/amd64 で wasm/wasi32 をビルドしようとしているので、マルチプラットフォームイメージのビルド設定が必要だったようです。
では、マルチプラットフォームイメージのビルド準備をしていきましょう。現在のビルダーを一覧表示します。
[vagrant@node1 hello]$ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS default * docker default default running v0.11.6 linux/amd64, linux/amd64/v2 [vagrant@node1 hello]$
wasm/wasi32 をビルドするためのビルダーを作成します。ここでは wasmbuilder という名前をつけています。
[vagrant@node1 hello]$ docker buildx create --name wasmbuilder --driver docker-container --bootstrap [+] Building 15.9s (1/1) FINISHED => [internal] booting buildkit 15.9s => => pulling image moby/buildkit:buildx-stable-1 14.5s => => creating container buildx_buildkit_wasmbuilder0 1.3s wasmbuilder [vagrant@node1 hello]$
wasmbuilder を作成できたことを確認します。
[vagrant@node1 hello]$ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS wasmbuilder docker-container wasmbuilder0 unix:///var/run/docker.sock running v0.11.6 linux/amd64, linux/amd64/v2, linux/386 default * docker default default running v0.11.6 linux/amd64, linux/amd64/v2 [vagrant@node1 hello]$ docker buildx inspect wasmbuilder Name: wasmbuilder Driver: docker-container Last Activity: 2023-05-25 07:36:48 +0000 UTC Nodes: Name: wasmbuilder0 Endpoint: unix:///var/run/docker.sock Status: running Buildkit: v0.11.6 Platforms: linux/amd64, linux/amd64/v2, linux/386 [vagrant@node1 hello]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c8556b04e6cd moby/buildkit:buildx-stable-1 "buildkitd" 2 minutes ago Up 2 minutes buildx_buildkit_wasmbuilder0 [vagrant@node1 hello]$
PLATFORMSに wasm/wasi32 は載っていませんが、これでいいようです。wasmbuilder をビルダーとして使用するように切り替えます。
[vagrant@node1 hello]$ docker buildx use wasmbuilder [vagrant@node1 hello]$
では、Dockerイメージをビルドしてみましょう。ここでビルドコマンドに「--load」というオプションを付与する必要があります。
[vagrant@node1 hello]$ docker buildx build --platform wasi/wasm32 --load -t daihiguchi/hellowasm . [+] Building 6.0s (6/6) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 182B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load build context 0.0s => => transferring context: 93B 0.0s => CACHED [1/1] COPY hello.wasm /hello.wasm 0.0s => exporting to docker image format 5.9s => => exporting layers 3.8s => => exporting manifest sha256:15f74db4faf0675e838ddd3531b871bd34243d78 0.0s => => exporting config sha256:4bef0b7a7115ad6135e46accc5a28bda692850efde 0.0s => => sending tarball 2.1s => importing to docker 0.0s [vagrant@node1 hello]$
ビルドに成功しました! 別途ビルダーを作成していない過去記事「DockerでWASMを動かそう」では、
=> [1/1] COPY hello.wasm /hello.wasm 0.3s => ERROR exporting to image 4.5s ERROR exporting to image (略) ------ > exporting to image: ------ ERROR: failed to solve: no match for platform in manifest sha256:6f6933e0f8dc102e51c1c7036060a20d325efce8c69dce85628aecae5ce8ebd5: not found
というエラーになっていましたが、正常に export できました。
[vagrant@node1 hello]$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE daihiguchi/hellowasm latest 15f74db4faf0 21 seconds ago 74MB nginx 1.22 fc5f5fb75747 36 minutes ago 211MB michaelirwin244/wasm-example latest 2a58923a21cb 28 minutes ago 6.31MB moby/buildkit buildx-stable-1 d6fa89830c26 6 minutes ago 246MB [vagrant@node1 hello]$ sudo ctr --namespace moby image ls REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/daihiguchi/hellowasm:latest application/vnd.docker.distribution.manifest.v2+json sha256:15f74db4faf0675e838ddd3531b871bd34243d78edc628d7afc6211726c2f65c 17.2 MiB wasi/wasm32 - docker.io/library/nginx:1.22 application/vnd.docker.distribution.manifest.list.v2+json sha256:fc5f5fb7574755c306aaf88456ebfbe0b006420a184d52b923d2f0197108f6b7 54.4 MiB linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/mips64le,linux/ppc64le,linux/s390x - docker.io/michaelirwin244/wasm-example:latest application/vnd.docker.distribution.manifest.v2+json sha256:2a58923a21cb3d45bc4a254120356c15869519603563609eacd8a39b54869b00 1.5 MiB wasi/wasm32 - docker.io/moby/buildkit:buildx-stable-1 application/vnd.oci.image.index.v1+json sha256:d6fa89830c26919acba23c5cafa09df0c3ec1fbde20bb2a15ff349e0795241f4 72.8 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/riscv64,linux/s390x,unknown/unknown - [vagrant@node1 hello]$
dockerコマンド、ctrコマンドの両方から作成できたDockerイメージが問題なく見えています。
作成したWASMのDockerイメージを使ってコンテナを実行
早速Dockerコンテナとして実行してみましょう。
[vagrant@node1 hello]$ docker container run --rm --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 daihiguchi/hellowasm Hello, world! [vagrant@node1 hello]$
無事、想定通りに動作しました!
まとめ
本稿では正式リリースされたDocker 24.0.1を使って、実験的サポートであるcontainerdイメージストア統合を有効化し、さらにWASM/WASIのDockerイメージの作成とコンテナの実行を行ってみました。
実験的サポートとはいえcontainerdイメージストア統合がDockerの正式リリースに組み込まれたことで、この動きは今後加速してくと考えられます。それに合わせてDockerにおけるWASM/WASIの実験や活用についても広がっていくことが期待されます。
クリエーションラインでは引き続き WebAssmbly と Docker について調査していきたいと思います。