Systemdを使えるCentOSをDockerコンテナで立ててみた

# はじめに
CentOSのコンテナはデフォルトだとSystemdは使えませんが、
[DockerHub](https://hub.docker.com/_/centos)のページでSystemdをアクティブにする方法が記載されているので試してみました。

# 実行環境
OS：MacOS Monterey 12.4
Docker：Docker version 20.10.14
Docker Desktop for Mac：version 4.7.1
Docker Image：CentOS 7

# CentOS7のDockerイメージを取得

```shell
% docker pull centos:7
```

# Systemdベースのイメージを作成
## Dockerfileを作成
DockerHubのページにサンプルが記載されているので、参考にDockerfileを作成します。

```shell
% vim ~/workspace/docker/centos/systemd-base/Dockerfile
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
```

## イメージをビルドする
Dockerfileを元にイメージをビルドします。

```shell
% docker build --rm -t centos-systemd ~/workspace/docker/centos/systemd-base/
[+] Building 0.1s (6/6) FINISHED                                                    
 => [internal] load build definition from Dockerfile                           0.1s
 => => transferring dockerfile: 37B                                            0.0s
 => [internal] load .dockerignore                                              0.0s
 => => transferring context: 2B                                                0.0s
 => [internal] load metadata for docker.io/library/centos:7                    0.0s
 => [1/2] FROM docker.io/library/centos:7                                      0.0s
 => CACHED [2/2] RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in   0.0s
 => exporting to image                                                         0.0s
 => => exporting layers                                                        0.0s
 => => writing image sha256:ddbe5f1f9b13355b0558d857948f089860b0e4393ec6a40b9  0.0s
 => => naming to docker.io/library/centos-systemd                              0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
```

ビルド後、dockerコマンドでイメージを一覧すると確認できます。

```shell
% docker images -a
REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
centos-systemd   latest    ddbe5f1f9b13   2 days ago     204MB
centos                7         eeb6ee3f44bd   8 months ago   204MB
```

# コンテナを起動
## 失敗1
DockerHubのページを参考に以下のコマンドでコンテナを起動します。

```shell
% docker run --name centos-systemd-container -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d centos-systemd
f27733e900c6cc99ed9aa3e046c72773cf87cef580b8b8c27d5610d39b35e4f6
```

起動したコンテナでSystemdを使用できるか確認してみます。

```shell
sh-4.2# systemctl list-units --type=service
Failed to get D-Bus connection: Operation not permitted
```

権限がなくてD-Bus接続の取得に失敗したようです。

[dockerドキュメント](http://docs.docker.jp/v17.06/engine/reference/run.html)で権限に関して調べてみると、
Dockerコンテナはデフォルトだと権限が無く、デバイスに対して接続できない状態にあるため、特権コンテナにする必要があるようです。

そのため「privileged」オプションを付与して特権コンテナとして立ち上げてみます。

## 失敗2

```shell
% docker run --name centos-systemd-container --privileged -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d centos-systemd
e3de98766ea9b4a181eb9fde99040c0093514e25bb0e72f55bd412717b2e8422
```

```shell
sh-4.2# systemctl list-units --type=service
Failed to get D-Bus connection: No such file or directory
```

今度はファイル・ディレクトリが見つからないものがあったらしく失敗しました。
メッセージで検索をかけていると、[こちら](https://github.com/docker/for-mac/issues/6073)にたどり着きました。

DockerDesktopがcgroupv2を使用するようになったため、systemdもcgroupv2をサポートしている必要があり、少なくともsystemd247以上のバージョンが必要みたいです。

自身の環境を確認してみます。

```shell
sh-4.2# journalctl --version
systemd 219
+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN
```

バージョンが足りていませんでした。
同ページによるとDockerDesktopにcgroupv1を使用させるパラメータがあるようなので設定してみます。
設定ファイルは~/Library/Group Containers/group.com.docker/settings.jsonです。

```
  "deprecatedCgroupv1": true, // trueに変更します
```

settings.jsonを変更したら再起動してもう一度試してみます。

## 成功

```shell
sh-4.2# systemctl list-units --type=service
UNIT                         LOAD   ACTIVE SUB     DESCRIPTION
systemd-journald.service     loaded active running Journal Service
systemd-tmpfiles-setup.service loaded active exited  Create Volatile Files and D
ir

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

2 loaded units listed. Pass --all to see loaded but inactive units, too
.
To show all installed unit files use 'systemctl list-unit-files'.
```

無事、systemctlコマンドが反応してくれるようになりました。


# 参考文献
https://hub.docker.com/_/centos

http://docs.docker.jp/v17.06/engine/reference/run.html

https://github.com/docker/for-mac/issues/6073