はじめに
こんにちは。3-shakeで技術顧問を務めている、うたもく(@utam0k)です。
今回は「nerdctl」について紹介します。nerdctlはDocker CLIやPodmanと同じようなコマンド操作で「containerd」を利用するためのCLIツールです。containerdはCNCF Graduatedのプロジェクトで活発に開発が進められているコンテナランタイムです。そのため、他のコンテナランタイムにはない様々な独自機能があります。
しかし、nerdctlが登場する以前は、Dockerなどではリリースサイクルの違いなどの理由から、これらの魅力的な独自機能を利用することが難しいという側面がありました。containerdが魅力的な独自機能を追加したとしても、Dockerなどの他コミュニティとの対話、パッチ、リリース待ちが必要であり、時間を要していました。過去の例を振り返ると、Rootlessコンテナ機能はその良い例と言えるでしょう。
そこで、containerdのメンテナやコミュニティを中心として開発されているのがnerdctlです。nerdctlは、どうやらメジャー、マイナーバージョンはcontainerdのリリースバージョンに合わせてリリースが行われているようです。そのため、containerdの新機能をすぐに試せます。最近の大きなリリースとして2024年11月に「containerd v2.0.0」がリリースされました。nerdctlも同日に「nerdctl v2.0.0」をリリースしています。やはり同一のコミュニティで開発されているというのは大きな利点です。
ちなみに、nerdはcontainerdから来ているようです。
nerdctlを試してみる
まずは、公式のドキュメントに従ってインストールします。以下のようにversionコマンドで自分のコンテナランタイムを取り巻く環境が分かります。また、infoコマンドでもcontainerdのserver/clientの様々な情報を確認できます。
$ sudo nerdctl version
Client:
Version: v2.0.2
OS/Arch: linux/amd64
Git commit: 1220ce7ec2701d485a9b1beeea63dae3da134fb5
buildctl:
Version: v0.11.6
GitCommit: 2951a28cd7085eb18979b1f710678623d94ed578
Server:
containerd:
Version: v2.0.1
GitCommit: 88aa2f531d6c2922003cc7929e51daf1c14caa0a
runc:
Version: 1.2.3
GitCommit: v1.2.3-0-g0d37cfd4
$ sudo nerdctl info
Client:
Namespace: default
Debug Mode: false
Server:
Server Version: v2.0.1
Storage Driver: overlayfs
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
Plugins:
Log: fluentd journald json-file none syslog
Storage: native overlayfs
Security Options:
apparmor
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.8.0-48-generic
Operating System: Ubuntu 24.04.1 LTS
OSType: linux
Architecture: x86_64
CPUs: 16
Total Memory: 62.38GiB
Name: rootbranch
ID: 1de4411a-a06e-428e-a4de-2770be07d438
サブコマンドの一覧を見ると、様々なコマンドがあることが分かります。Dockerで見慣れたもの、そうでないものもあると思います。nerdctlの公式のドキュメントにはDocker CLIと互換があるものの一覧が用意されています。気になる方はチェックしてみてください。
$ nerdctl help
...
Usage: nerdctl [flags]
helpers.Management commands:
apparmor Manage AppArmor profiles
builder Manage builds
container Manage containers
image Manage images
ipfs Distributing images on IPFS
...
Commands:
attach Attach stdin, stdout, and stderr to a running container.
build Build an image from a Dockerfile. Needs buildkitd to be running.
commit Create a new image from a container's changes
completion Generate the autocompletion script for the specified shell
compose Compose
cp Copy files/folders between a running container and the local filesystem.
create Create a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
...
さて、コンテナを動かしてみましょう。
$ sudo nerdctl run --name test -it --rm alpine
/ # echo "Hello, nerdctl!"
Hello, nerdctl!
/ # exit
Rootlessコンテナ
nerdctlの注目すべき特徴として、様々なRootlessコンテナの実験的な機能が入っている点があります。Rootlessコンテナとは、一般にコンテナの実行に特権が必要ないことを指します。
公式ドキュメントに従ってセットアップを行います。実際に動かしてみると、Rootlessコンテナでのコンテナ内から外部への通信を中継する slirp4netnsなど、Rootlessコンテナに必要なツールを動かしたり、cgroupsの設定がされているのが分かると思います。
$ containerd-rootless-setuptool.sh install
[INFO] Checking RootlessKit functionality
[INFO] Checking cgroup v2
...
[INFO] Use `nerdctl` to connect to the rootless containerd.
[INFO] You do NOT need to specify $CONTAINERD_ADDRESS explicitly.
# Rootless と Rootful では環境が異なっていることがあります。
$ nerdctl version
Client:
Version: v2.0.2
OS/Arch: linux/amd64
Git commit: 1220ce7ec2701d485a9b1beeea63dae3da134fb5
buildctl:
Version: v0.11.6
GitCommit: 2951a28cd7085eb18979b1f710678623d94ed578
Server:
containerd:
Version: v2.0.1
GitCommit: 88aa2f531d6c2922003cc7929e51daf1c14caa0a
runc:
Version: 1.2.3
GitCommit: v1.2.3-0-g0d37cfd4
$ systemctl --user show containerd.service --property MainPID
MainPID=2638845
$ pstree -Asa 2638845
systemd --system --deserialize=76
`-systemd --user
`-rootlesskit --state-dir=/run/user/1000/containerd-rootless --net=slirp4netns --mtu=65520 ...
|-exe --state-dir=/run/user/1000/containerd-rootless --net=slirp4netns --mtu=65520 ...
| |-containerd
| | `-21*[{containerd}]
| `-8*[{exe}]
|-slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 2638861 tap0
`-8*[{rootlesskit}]
ここまでは、最近のDockerでも比較的簡単にセットアップできます。nerdctlではもっと最先端なRootlessコンテナに関わる機能が利用できます。ここではbypass4netnsを動かしてみます。bypass4netnsはRootlessコンテナの「コンテナからの外向きの通信が遅い」という弱点を克服するための実験的なOSSです。仕組みや詳細についてはNTT Open SourceのブログやContainer Runtime Meetup #6を参照ください。
nerdctlではbypass4netnsの環境をセットアップするスクリプトが含まれているため、簡単に環境を用意できます。
$ containerd-rootless-setuptool.sh install-bypass4netnsd
...
$ systemctl --user status bypass4netnsd.service
● bypass4netnsd.service - bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers)
Loaded: loaded (/home/utam0k/.config/systemd/user/bypass4netnsd.service; enabled; preset: enabled)
Active: active (running) since Sat 2024-12-28 16:18:15 JST; 2min 16s ago
Main PID: 2640236 (bypass4netnsd)
Tasks: 5 (limit: 76565)
Memory: 5.4M (peak: 6.3M)
CPU: 6ms
CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/bypass4netnsd.service
└─2640236 /usr/local/bin/bypass4netnsd
Dec 28 16:18:15 rootbranch systemd[3305]: Started bypass4netnsd.service - bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers).
Dec 28 16:18:15 rootbranch bypass4netnsd[2640236]: time="2024-12-28T16:18:15+09:00" level=info msg="SocketPath: /run/user/1000/bypass4netnsd.sock"
Dec 28 16:18:15 rootbranch bypass4netnsd[2640236]: time="2024-12-28T16:18:15+09:00" level=info msg="bypass4netns executable path: /usr/local/bin/bypass4netns"
Dec 28 16:18:15 rootbranch bypass4netnsd[2640236]: time="2024-12-28T16:18:15+09:00" level=info msg="Starting to serve on /run/user/1000/bypass4netnsd.sock"
nerdctl/bypass4netns=trueというアノテーションを付けてコンテナを起動することで、bypass4netnsを使ったコンテナが起動します。あまりにも普通に起動するので、ここではslirp4netnsと比較して、実際にbypass4netnsがどのくらい速いのかをテストしてみましょう。
# Terminal-1: rootless container without bypass4netns
$ nerdctl run --name client-wo-bypass4netns -it --rm alpine
/ # apk add --no-cache iperf3
...
Executing busybox-1.37.0-r8.trigger
OK: 7 MiB in 16 packages
/ # iperf3 -c $HOST_IP -t 3
...
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 208 MBytes 1.74 Gbits/sec 0 68.4 KBytes
[ 5] 1.00-2.00 sec 209 MBytes 1.75 Gbits/sec 0 68.4 KBytes
[ 5] 2.00-3.00 sec 208 MBytes 1.74 Gbits/sec 0 68.4 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-3.00 sec 624 MBytes 1.74 Gbits/sec 0 sender
[ 5] 0.00-3.00 sec 621 MBytes 1.74 Gbits/sec receiver
iperf Done.
# Terminal-1: rootless container with bypass4netns
$ nerdctl run --name client-with-bypass4netns -it --rm --annotation nerdctl/bypass4netns=true alpine
/ # apk add --no-cache iperf3
...
Executing busybox-1.37.0-r8.trigger
OK: 7 MiB in 16 packages
/ # iperf3 -c $HOST_IP -t 3
...
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 8.53 GBytes 73.2 Gbits/sec 0 1.62 MBytes
[ 5] 1.00-4.00 sec 128 KBytes 350 Kbits/sec 0 1.75 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-4.00 sec 34.1 GBytes 73.3 Gbits/sec 0 sender
[ 5] 0.00-4.00 sec 34.1 GBytes 73.2 Gbits/sec receiver
iperf Done.
# Terminal-2: Host側
$ iperf3 -s
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
...
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 205 MBytes 1.72 Gbits/sec
[ 5] 1.00-2.00 sec 208 MBytes 1.74 Gbits/sec
[ 5] 2.00-3.00 sec 209 MBytes 1.75 Gbits/sec
[ 5] 3.00-3.00 sec 128 KBytes 1.62 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-3.00 sec 621 MBytes 1.74 Gbits/sec receiver
-----------------------------------------------------------
Server listening on 5201 (test #2)
-----------------------------------------------------------
...
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 8.53 GBytes 73.2 Gbits/sec
[ 5] 1.00-2.00 sec 8.49 GBytes 73.0 Gbits/sec
[ 5] 2.00-3.00 sec 8.56 GBytes 73.5 Gbits/sec
[ 5] 3.00-4.00 sec 8.55 GBytes 73.4 Gbits/sec
[ 5] 4.00-4.00 sec 4.00 MBytes 28.6 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-4.00 sec 34.1 GBytes 73.2 Gbits/sec receiver
-----------------------------------------------------------
Server listening on 5201 (test #3)
-----------------------------------------------------------
iperf3 の結果:
- slirp4nets(default): 1.74 Gbits/sec
- bypass4netns: 73.3 Gbits/sec
- rootful: 80.3 Gbits/sec // 誌面の都合でコマンド結果は載せていません
上記の結果から一目で分かる通り、bypass4netnsはrootfulのネイティブのパフォーマンスにかなり近づいています。nerdctlであれば、このような魅力的で実験的な機能を簡単に素早く試すことができます。
他にも、nerdctlでは以下のような機能が独自にかつ簡単に使うことができます。
- いろいろな種類のSnapshotterのlazy-pulling
- IPFSを用いたP2Pのコンテナイメージの配布
- FreeBSDのjailのサポート
- 暗号化イメージ
- KubernetesのDebuggingのための機能
- OCI Runtime Specレベルの情報も確認できるinspectコマンド
おわりに
筆者は、今回紹介したような新しい機能をたくさん入れ込んだ実験環境があるというのは、とても良いことだと考えています。これらがあることで、 containerdと近いリリースサイクルで新しい機能をユーザーに早く提供することが可能になります。また、ユーザーに使ってもらえる環境は開発者へのモチベーションにつながると共に、フィードバックがもらえるようになるというとても良い側面もあります。
2025年はnerdctlを使って、お手元のコンテナ環境を操作してみるのはいかがでしょうか。
- この記事のキーワード