この記事はDocker Advent Calendar 2019の21日目の記事です。
Dockerが内部で使用しているHigh-levelランタイムのcontainerdをコンテナ内で起動して動かしてみた話です。
コンテナ内で動かす方法に関してはcontainerdのリポジトリにそのやり方が記載されていますが、その通りにやっても私の環境では一部上手くいかなかったのでその解決策も含めて紹介できればと思います。
環境
- OS: ubuntu 16.04
- golang: go1.13
- Docker: 19.03.5
- containerd: v1.3.0-203-g97712c8a 97712c8ad73dd302d5d226e0384b2d86e5de2989
ソースの取得
containerdを動かすに当たってソースからバイナリを作成するのでローカルにソースを取得しておきます。
contaierdの他にlow-levelランタイムであるruncも今回は一緒にビルドするので合わせて取得します。
取得方法はgo get -u github.com/containerd/containerdとgo get -u github.com/opencontainers/runcを実行すればOKです。
Dockerイメージの作成
ソースの取得が終わったら次にcontainerdを動かすコンテナのDockerイメージを作成します。
containerdはGo言語を使用して作られているので、Dockerイメージのgolangをベースに、ビルドするのに必要なモジュールをインストールしていきます。
必要なモジュールはB-Tree FileSystem用のbtrfs-toolsとSeccomp用のlibseccomp-devの二つです。
FROM golang:latest
RUN apt-get update \
&& apt-get install -y btrfs-tools libseccomp-dev
あとはdocker build -t containerd/build .でDockerイメージを作成すればコンテナ用のDockerイメージの準備は完了です。
コンテナの起動
上記で作成したDockerイメージを使ってコンテナを起動します。
docker run -it --privileged \
-v /var/lib/containerd \
-v ${GOPATH}/src/github.com/opencontainers/runc:/go/src/github.com/opencontainers/runc \
-v ${GOPATH}/src/github.com/containerd/containerd:/go/src/github.com/containerd/containerd \
-e GOPATH=/go \
-w /go/src/github.com/containerd/containerd containerd/build bash
containerdの起動には特権が必要になるので--privilegedオプションをつけ、起動に必要なフォルダと上記で取得したソースをマウントした上で起動しています。
そのほかのオプションはGOPATHの設定とコンテナ起動時のディレクトリを指定しています。
公式のやり方ではbashではなくshを起動しているのですが、個人的にbashの方が慣れているので変えています。
ソースのビルド
次はコンテナ内でcontainerdとruncをビルドしていきます。
それぞれMakefileが用意されているのでそれを利用します。
// containerdのフォルダに移動。
// コンテナ起動時にこのフォルダがカレントディレクトリになっているはずなので実行しなくても大丈夫
$ cd /go/src/github.com/containerd/containerd
$ make && make install
// エラー!
vendor/github.com/containerd/btrfs/btrfs.go:38:25: fatal error: btrfs/ioctl.h: No such file or directory
# include <btrfs/ioctl.h>
^
compilation terminated.
make: *** [bin/containerd] Erreur 2
実はこの状態でビルドするとエラーとなります。containerdが依存しているcontaienrd/btrfsというモジュールがあり、そのモジュールからbtrfsがないと言われるのが原因です。
Dockerイメージを作る際にbtrfs-toolsをインストールしましたが、どうもこれでは駄目なようでbtrfs-toolsの代わりにlibbtrfs-devをインストールすればビルドが通りました。
FROM golang:latest
RUN apt-get update \
&& apt-get install -y libbtrfs-dev libseccomp-dev
公式に記載されているやり方と異なるので問題がある可能性もありますが、一旦これでDockerイメージを作成しなおしてコンテナを起動すればビルドは通るようになります。
あとはcontainerdと同様にruncもビルドしてやれば準備完了です。
cd /go/src/github.com/opencontainers/runc
make BUILDTAGS='seccomp apparmor' && make install
containerdの起動
make installした段階でcontainerdのバイナリがPATHの通っているディレクトリに配置されますのでそれを起動すればcontainerdが動きます。
$ containerd // バックグラウンドで起動したい場合は containerd &
$ INFO[2019-12-21T13:56:32.716026618Z] starting containerd ...
$ INFO[2019-12-21T13:56:32.760340925Z] loading plugin ...
// 以下ログが出力される
これでやっとcontainerdが動かせました!
あとは好きなようにいじりたおせばOKですね。
まとめ
簡単ですがコンテナ内でcontainerdを動かすやり方を紹介させてもらいました。
そもそも何故動かそうと思ったかというと、個人的にコンテナランタイムの開発に挑戦していてDockerで動かしてみたら上手く動かず原因を探っていくとcontainerdとのやりとりに問題がありそうだという事が分かったので、containerdを動かして見ようと思ったのがきっかけでした。
ただ起動するだけでなく構成を記述した設定ファイルを渡す事もできるようなので、その辺りも公式に情報があるのでよければそちらも見てみて下さい。