systemd in docker container without --privileged


----
**2016-08-23 追記**

docker-engineが1.12.1にバージョンアップして少し修正が入った。

- [docker-engine 1.12.1 Releasenote](https://github.com/docker/docker/blob/master/CHANGELOG.md)

> Security
> - Allow systemd to run with only --cap-add SYS_ADMIN rather than having to also add --cap-add DAC_READ_SEARCH or disabling seccomp filtering #25567

- 関連issue/PR
    - https://github.com/docker/docker/pull/25567
    - https://github.com/docker/docker/issues/25516

しかしseccompのプロファイルで実際に変更されている部分を確認してもmount/umount等は追加されていないため、seccompが有効なホストOS + docker-engineのバージョンの組み合わせで使っている場合は未だ`--security_opt seccomp:unconfined`が必要。`--cap-add SYS_ADMIN`オプションを渡した時のみseccompの追加設定が不要になる修正っぽい。

Docker for Macやdocker-machineのboot2dockerでは`--security_opt seccomp:unconfined`が不要になり`--cap-add SYS_ADMIN`だけでOKになった。



----

Dockerコンテナ内でsystemdを動かすときに`--privileged`が必要なのか不要なのかググっても全然はっきりしないので色々実験して調べてみた。

- どのような場合でも `--privileged` は **不要**
    - 代わりに `--cap-add sys_admin` を使う
- Hostでsystemdが動いている場合は `--cap-add sys_admin` は **不要**
- docker-engineを公式レポジトリからパッケージインストールしていて、なおかつHostがseccompに対応している場合は `--security-opt seccomp:unconfined` が **必要**
- 考えるのが面倒くさい → `--privileged` でどうぞ
    - これならどのパターンでも確実に動く


## コンテナ起動コマンド具体例
### pattern 1

Host: Docker for Mac
docker-engine: 1.12.0

```bash
docker run -it --rm --cap-add sys_admin --security-opt seccomp:unconfined centos/systemd:latest
```

- ホストにsystemdが無いパターン。docker-machineのboot2dockerでも同じはず。
- systemdは動いていないが、seccompは有効っぽい
- Dockerfile内で`VOLUME [ "/sys/fs/cgroup" ]`されていない場合は`-v /sys/fs/group`が必要



### pattern 2
Host: CentOS 7
docker-engine: 1.12.0 or newer (from docker official repo)

```bash
docker run -it --rm -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /run --security-opt seccomp:unconfined centos/systemd:latest
```

- CentOS 7はdocker-engine 1.12以降でseccomp有効
- `-v /run`が必要
    - DockerHubのcentosのページの説明では "There have been reports that if you're using an Ubuntu host, you will need to add -v /tmp/$(mktemp -d):/run in addition to the cgroups mount" と記載があるがCentOS 7のホストでも必要だった


### pattern 3
Host: CentOS 7
docker-engine: 1.11 or older (from docker official repo)

```bash
docker run -it --rm -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /run centos/systemd:latest
```

- ホストにsystemdがあり、なおかつseccompが無効なので殆ど何もオプションが要らないパターン
    - DockerHubのcentosのページに記載されているのが正にこのパターン。というかこのパターンの時にしかサイトに記載されているコマンドでは起動出来ない。 **なのでハマる。**

### pattern 4
Host: Fedora 23
docker-engine: 1.10.3-24.gitf476348.fc23 (from fedora repo)

```bash
docker run -it --rm -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /run centos/systemd:latest
```

- ホストにsystemdあり
- seccomp有効だがdocker-engineにfedoraのパッチが当たっていてsystemd起動に必要な操作がseccompのデフォルトプロファイルに対して追加で許可されているため`--security-opt seccomp:unconfined`が不要


## 現時点でわかったことメモ

そもそも`--privileged`と`--cap-add sys_admin`で何がどれくらい違うのか不明だが、`--privileged`の方がより強力っぽいので`--cap-add sys_admin`の方を使ったほうが良さそう。まあ書いたとおり何が違うのかちゃんと調べてなくて不明なのであまり気にしてもしょうがないかもしれない。

続いて、Hostでsystemdが動いている場合は`-v /sys/fs/cgroup:/sys/fs/cgroup:ro`してあげることで上記の`--cap-add sys_admin`は不要となるようだ。逆に考えると、Host側でsystemdが動いていない場合には`/sys/fs/cgroup`の配下の何かが足りないことが原因で、コンテナを`--cap-add sys_admin` **しないで起動** した時にコンテナの中のsystemdが何かCAP_SYS_ADMINが必要な操作(恐らくマウント)を実行しようとして失敗しているような感じ。失敗時の出力から察するに必要なのは`/sys/fs/cgroup/systemd`？

Docker for Macやboot2dockerでホストに使われているOSではsystemdが動いていないので、この上で動かす場合は必ず`--cap-add sys_admin`が必要になる。

これに加えて更に1.10から追加されたseccompの仕組みが関わってくる。seccompはcapで与えた権限をさらにマスクする感じで動く。`--security-opt seccomp:unconfined`を指定すると、seccompのマスクを完全に無効化する。これはdocker-engine 1.9以下の時の挙動と全く同じ。dockerのデフォルトのseccompのプロファイルではmount/umountがマスクされて使えないようになっているので、恐らくこれがコンテナ内でのsystemdの起動を妨げている。

ややこしいのが、seccompの対応はホストOSとdocker-engineに依存しており、最初にdocker-engineに実装されたのはCHANGELOGから1.10だということがわかるが、CentOS 7のホストで対応したのは1.12から。なのでCentOS 7なら1.11でも未だseccompは使われておらず、したがって`--security-opt seccomp:unconfined`の指定は不要。またdocker公式のパッケージではなくてディストリのパッケージでdocker-engineをインストールした場合、この部分に手が加わっていることがある。具体的にはFedora 23のdocker-1.10では、デフォルトのseccompでmount/unmountが許可されるように編集されていて[^1]、Fedora 23のホストでFedora 23のレポジトリからインストールしたdocker-engineを使う場合は1.10以降でも`--security-opt seccomp:unconfined`の指定は不要。

[^1]: https://github.com/projectatomic/docker/commit/5d7232ea6a03b8a784c0935e3969311ab8f857a8

あとsystemd.conf 2015の発表で[これ](https://youtu.be/zVy1lQqJJj8)は参考になった。