仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

containerd + nerdctlを使ってみた

containerdはKubernetesに対応するコンテナランタイムの一つです。 containerdにはctrというCLIインターフェースがあり、これを使ってコンテナの実行やイメージのPullなどができるのですが、Dockerのそれとはコマンド操作に互換性はありません。

しかしnerdctlを使うと、ほぼDockerと変わらない操作性でコンテナの運用ができるようになります。 実際Rancher Desktopでランタイムをcontainerdにすると、nerdctlを使って同じようにコンテナ操作ができるので手っ取り早く試してみたい方はRancher Desktopをインストールして試してみてください。

rancherdesktop.io

では早速、containerd + nerdctl環境のセットアップをしていきましょう。

セットアップの流れ

環境について

OSはインストール済みであり、その上で環境を構築していく前提です。 Linux kernelが古すぎると動かないようなので、少なくともLinux kernel 5.4以降が使えるOSでお試しください。 Ubuntuなら20.04以降、RHELならバージョン9以降でしょうか。

ちなみにRHELなどではfirewalldの壁をうまく越えられなかったので、systemctl disable firewalld && systemctl stop firewalldをしています。ここは今後の課題です。

containerd + nerdctlの導入

最初はcontainerdをインストールします。Docker Engineのパッケージリポジトリーにcontainerd.ioパッケージがあるのでそれをインストールします。

CLIとしてはnerdctl を使わせていただきます。 使い方はnerdctlのリポジトリーのdocsディレクトリーに用意されています。

Linux kernel 5.4以降が必要っぽいです。そのほか、必要なコンポーネントをセットアップします。 今回はUbuntu 20.04とRHEL9で試しました。RHEL8では動作しませんでした。

まず、nerdctlをダウンロードして展開します。

$ wget "https://github.com/containerd/nerdctl/releases/download/v1.4.0/nerdctl-1.4.0-linux-amd64.tar.gz"
$ tar zvxf nerdctl-1.4.0-linux-amd64.tar.gz
$ mv containerd-rootless-setuptool.sh  containerd-rootless.sh nerdctl ~/.local/bin

rootlessでセットアップすることにします。OSが要件を満たしていないとエラーが表示されるので対処します。

$ containerd-rootless-setuptool.sh install
[INFO] Checking RootlessKit functionality
[rootlesskit:parent] error: failed to setup UID/GID map: newuidmap 4412 [0 1000 1 1 100000 65536] failed: : exec: "newuidmap": executable file not found in $PATH
[ERROR] RootlessKit failed, see the error messages and https://rootlesscontaine.rs/getting-started/common/ .

Ubuntuの場合、newuidmapコマンドはuidmapパッケージに含まれます。

インストールします。

$ sudo apt-get install uidmap

RHEL9の場合はsudo dnf provides newuidmapで検索して、shadow-utilsパッケージが入っていると良いことが分かります。 入っていないことはないと思いますが、確認してみてください。

もう一度実行します。

$ containerd-rootless-setuptool.sh install
[INFO] Checking RootlessKit functionality
...
[INFO] Installed "containerd.service" successfully.
[INFO] To control "containerd.service", run: `systemctl --user (start|stop|restart) containerd.service`
[INFO] To run "containerd.service" on system startup automatically, run: `sudo loginctl enable-linger ubuntu`
[INFO] ------------------------------------------------------------------------------------------
[INFO] Use `nerdctl` to connect to the rootless containerd.
[INFO] You do NOT need to specify $CONTAINERD_ADDRESS explicitly.

次に最低要件であるCNI Pluginを用意します。

$ sudo mkdir -p /opt/cni/bin/
$ wget "https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz"
$ cd /opt/cni/bin/
$ sudo tar zvxf ~/temp/cni-plugins-linux-amd64-v1.3.0.tgz

セットアップ後、nerdctlを使って、containerdでコンテナの実行ができました。

$ nerdctl run docker.io/hello-world
...
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

イメージのビルドもできるようにする

イメージビルドをしたい場合はこちら にまとまっているので、これに従って設定します。

こうでしょうか。

$ wget "https://github.com/moby/buildkit/releases/download/v0.12.0/buildkit-v0.12.0.linux-amd64.tar.gz"
$ tar zvxf buildkit-v0.12.0.linux-amd64.tar.gz
$ mv bin/*  ~/.local/bin

$ CONTAINERD_NAMESPACE=default containerd-rootless-setuptool.sh install-buildkit-containerd

あとはDockerfileを作ってビルドするだけです。

$ nerdctl build -t foo cont-img/
[+] Building 3.3s (6/6) FINISHED                                                                                                                     
 => [internal] load build definition from Dockerfile                                                                                            0.0s
 => => transferring dockerfile: 148B                                                                                                            0.0s
 => [internal] load metadata for docker.io/redhat/ubi9-micro:9.2                                                                                2.3s
 => [internal] load .dockerignore                                                                                                               0.0s
 => => transferring context: 2B                                                                                                                 0.0s
 => [1/2] FROM docker.io/redhat/ubi9-micro:9.2@sha256:57ac8525717f02853b992b0fab41752d4120e5d85163acd8ab696c8a94a715b5                          0.6s
 => => resolve docker.io/redhat/ubi9-micro:9.2@sha256:57ac8525717f02853b992b0fab41752d4120e5d85163acd8ab696c8a94a715b5                          0.0s
 => => sha256:940034fae708a1fe0ee6ff6929fffd48c235a6da185812ea4b31bab58815b6cf 7.68MB / 7.68MB                                                  0.3s
 => => extracting sha256:940034fae708a1fe0ee6ff6929fffd48c235a6da185812ea4b31bab58815b6cf                                                       0.2s
 => [2/2] RUN echo hello                                                                                                                        0.2s
 => exporting to image                                                                                                                          0.1s 
 => => exporting layers                                                                                                                         0.1s
 => => exporting manifest sha256:bc0ff57910d7fb2c3356f1dc4bf56de71c3206f4d7a2c509b8f5c3ac729dbfc7                                               0.0s
 => => exporting config sha256:4216954b146981bfc8a71a8e9848e33e3cbb54e78a8fb638d9be2235219b45b2                                                 0.0s
 => => naming to docker.io/library/foo:latest                                                                                                   0.0s
 => => unpacking to docker.io/library/foo:latest                                                                                                0.0s

$ nerdctl image ls foo
REPOSITORY    TAG       IMAGE ID        CREATED           PLATFORM       SIZE        BLOB SIZE
foo           latest    bc0ff57910d7    43 seconds ago    linux/amd64    28.5 MiB    7.3 MiB

いくつかDocker Hubに上がっているイメージを使ってみましたが、特に問題なく利用できました。 今回rootlessで使っているのでrootlessで動かしている場合の制限事項については考慮が必要ですが、特に問題なく動作することを手元の環境で確認しています。