fbpx

Docker 24リリース! containerdイメージストア統合の実験的サポートでWASMを動かそう #docker #containerd #stargz #webassembly #wasm #wasi

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)を動かせるように設定しましょう。ここでは WasmEdgerunwasi を使います。過去の手順は「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 について調査していきたいと思います。

関連記事

Author

Chef・Docker・Mirantis製品などの技術要素に加えて、会議の進め方・文章の書き方などの業務改善にも取り組んでいます。「Chef活用ガイド」共著のほか、Debian Official Developerもやっています。

Daisuke Higuchiの記事一覧

新規CTA