はじめに
こんにちは。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の様々な情報を確認できます。
05 | Git commit: 1220ce7ec2701d485a9b1beeea63dae3da134fb5 |
08 | GitCommit: 2951a28cd7085eb18979b1f710678623d94ed578 |
13 | GitCommit: 88aa2f531d6c2922003cc7929e51daf1c14caa0a |
16 | GitCommit: v1.2.3-0-g0d37cfd4 |
24 | Server Version: v2.0.1 |
25 | Storage Driver: overlayfs |
26 | Logging Driver: json-file |
27 | Cgroup Driver: systemd |
30 | Log: fluentd journald json-file none syslog |
31 | Storage: native overlayfs |
37 | Kernel Version: 6.8.0-48-generic |
38 | Operating System: Ubuntu 24.04.1 LTS |
42 | Total Memory: 62.38GiB |
44 | ID: 1de4411a-a06e-428e-a4de-2770be07d438 |
サブコマンドの一覧を見ると、様々なコマンドがあることが分かります。Dockerで見慣れたもの、そうでないものもあると思います。nerdctlの公式のドキュメントにはDocker CLIと互換があるものの一覧が用意されています。気になる方はチェックしてみてください。
05 | helpers.Management commands: |
06 | apparmor Manage AppArmor profiles |
08 | container Manage containers |
10 | ipfs Distributing images on IPFS |
14 | attach Attach stdin, stdout, and stderr to a running container. |
15 | build Build an image from a Dockerfile. Needs buildkitd to be running. |
16 | commit Create a new image from a container's changes |
17 | completion Generate the autocompletion script for the specified shell |
19 | cp Copy files/folders between a running container and the local filesystem. |
20 | create Create a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS. |
21 | diff Inspect changes to files or directories on a container's filesystem |
22 | events Get real time events from the server |
23 | exec Run a command in a running container |
さて、コンテナを動かしてみましょう。
1 | $ sudo nerdctl run --name test -it --rm alpine |
2 | / # echo "Hello, nerdctl!" |
Rootlessコンテナ
nerdctlの注目すべき特徴として、様々なRootlessコンテナの実験的な機能が入っている点があります。Rootlessコンテナとは、一般にコンテナの実行に特権が必要ないことを指します。
公式ドキュメントに従ってセットアップを行います。実際に動かしてみると、Rootlessコンテナでのコンテナ内から外部への通信を中継する slirp4netnsなど、Rootlessコンテナに必要なツールを動かしたり、cgroupsの設定がされているのが分かると思います。
01 | $ containerd-rootless-setuptool.sh install |
02 | [INFO] Checking RootlessKit functionality |
03 | [INFO] Checking cgroup v2 |
05 | [INFO] Use `nerdctl` to connect to the rootless containerd. |
06 | [INFO] You do NOT need to specify $CONTAINERD_ADDRESS explicitly. |
08 | # Rootless と Rootful では環境が異なっていることがあります。 |
13 | Git commit: 1220ce7ec2701d485a9b1beeea63dae3da134fb5 |
16 | GitCommit: 2951a28cd7085eb18979b1f710678623d94ed578 |
21 | GitCommit: 88aa2f531d6c2922003cc7929e51daf1c14caa0a |
24 | GitCommit: v1.2.3-0-g0d37cfd4 |
26 | $ systemctl --user show containerd.service --property MainPID |
29 | systemd --system --deserialize=76 |
31 | `-rootlesskit --state-dir=/run/user/1000/containerd-rootless --net=slirp4netns --mtu=65520 ... |
32 | |-exe --state-dir=/run/user/1000/containerd-rootless --net=slirp4netns --mtu=65520 ... |
34 | | | `-21*[{containerd}] |
36 | |-slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 2638861 tap0 |
ここまでは、最近のDockerでも比較的簡単にセットアップできます。nerdctlではもっと最先端なRootlessコンテナに関わる機能が利用できます。ここではbypass4netnsを動かしてみます。bypass4netnsはRootlessコンテナの「コンテナからの外向きの通信が遅い」という弱点を克服するための実験的なOSSです。仕組みや詳細についてはNTT Open SourceのブログやContainer Runtime Meetup #6を参照ください。
nerdctlではbypass4netns
の環境をセットアップするスクリプトが含まれているため、簡単に環境を用意できます。
01 | $ containerd-rootless-setuptool.sh install-bypass4netnsd |
03 | $ systemctl --user status bypass4netnsd.service |
04 | ● bypass4netnsd.service - bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers) |
05 | Loaded: loaded (/home/utam0k/.config/systemd/user/bypass4netnsd.service; enabled; preset: enabled) |
06 | Active: active (running) since Sat 2024-12-28 16:18:15 JST; 2min 16s ago |
07 | Main PID: 2640236 (bypass4netnsd) |
08 | Tasks: 5 (limit: 76565) |
09 | Memory: 5.4M (peak: 6.3M) |
11 | CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/bypass4netnsd.service |
12 | └─2640236 /usr/local/bin/bypass4netnsd |
14 | Dec 28 16:18:15 rootbranch systemd[3305]: Started bypass4netnsd.service - bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers). |
15 | 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" |
16 | 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" |
17 | 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がどのくらい速いのかをテストしてみましょう。
01 | # Terminal-1: rootless container without bypass4netns |
02 | $ nerdctl run --name client-wo-bypass4netns -it --rm alpine |
03 | / # apk add --no-cache iperf3 |
05 | Executing busybox-1.37.0-r8.trigger |
06 | OK: 7 MiB in 16 packages |
07 | / # iperf3 -c $HOST_IP -t 3 |
09 | [ ID] Interval Transfer Bitrate Retr Cwnd |
10 | [ 5] 0.00-1.00 sec 208 MBytes 1.74 Gbits/sec 0 68.4 KBytes |
11 | [ 5] 1.00-2.00 sec 209 MBytes 1.75 Gbits/sec 0 68.4 KBytes |
12 | [ 5] 2.00-3.00 sec 208 MBytes 1.74 Gbits/sec 0 68.4 KBytes |
13 | - - - - - - - - - - - - - - - - - - - - - - - - - |
14 | [ ID] Interval Transfer Bitrate Retr |
15 | [ 5] 0.00-3.00 sec 624 MBytes 1.74 Gbits/sec 0 sender |
16 | [ 5] 0.00-3.00 sec 621 MBytes 1.74 Gbits/sec receiver |
20 | # Terminal-1: rootless container with bypass4netns |
21 | $ nerdctl run --name client-with-bypass4netns -it --rm --annotation nerdctl/bypass4netns=true alpine |
22 | / # apk add --no-cache iperf3 |
24 | Executing busybox-1.37.0-r8.trigger |
25 | OK: 7 MiB in 16 packages |
26 | / # iperf3 -c $HOST_IP -t 3 |
28 | [ ID] Interval Transfer Bitrate Retr Cwnd |
29 | [ 5] 0.00-1.00 sec 8.53 GBytes 73.2 Gbits/sec 0 1.62 MBytes |
30 | [ 5] 1.00-4.00 sec 128 KBytes 350 Kbits/sec 0 1.75 MBytes |
31 | - - - - - - - - - - - - - - - - - - - - - - - - - |
32 | [ ID] Interval Transfer Bitrate Retr |
33 | [ 5] 0.00-4.00 sec 34.1 GBytes 73.3 Gbits/sec 0 sender |
34 | [ 5] 0.00-4.00 sec 34.1 GBytes 73.2 Gbits/sec receiver |
40 | ----------------------------------------------------------- |
41 | Server listening on 5201 (test #1) |
42 | ----------------------------------------------------------- |
44 | [ ID] Interval Transfer Bitrate |
45 | [ 5] 0.00-1.00 sec 205 MBytes 1.72 Gbits/sec |
46 | [ 5] 1.00-2.00 sec 208 MBytes 1.74 Gbits/sec |
47 | [ 5] 2.00-3.00 sec 209 MBytes 1.75 Gbits/sec |
48 | [ 5] 3.00-3.00 sec 128 KBytes 1.62 Gbits/sec |
49 | - - - - - - - - - - - - - - - - - - - - - - - - - |
50 | [ ID] Interval Transfer Bitrate |
51 | [ 5] 0.00-3.00 sec 621 MBytes 1.74 Gbits/sec receiver |
52 | ----------------------------------------------------------- |
53 | Server listening on 5201 (test #2) |
54 | ----------------------------------------------------------- |
56 | [ ID] Interval Transfer Bitrate |
57 | [ 5] 0.00-1.00 sec 8.53 GBytes 73.2 Gbits/sec |
58 | [ 5] 1.00-2.00 sec 8.49 GBytes 73.0 Gbits/sec |
59 | [ 5] 2.00-3.00 sec 8.56 GBytes 73.5 Gbits/sec |
60 | [ 5] 3.00-4.00 sec 8.55 GBytes 73.4 Gbits/sec |
61 | [ 5] 4.00-4.00 sec 4.00 MBytes 28.6 Gbits/sec |
62 | - - - - - - - - - - - - - - - - - - - - - - - - - |
63 | [ ID] Interval Transfer Bitrate |
64 | [ 5] 0.00-4.00 sec 34.1 GBytes 73.2 Gbits/sec receiver |
65 | ----------------------------------------------------------- |
66 | Server listening on 5201 (test #3) |
67 | ----------------------------------------------------------- |
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を使って、お手元のコンテナ環境を操作してみるのはいかがでしょうか。