コンテナで`systemctl`を叩いたら`Failed to get D-Bus connection: No such file or directory`と言われた

うっかり（でもない）`Docker`をアップデートしたら、これまで動いていたコンテナの`Apache`が動かなくなって四苦八苦した際の備忘録です。

結論としては、**コンテナで`systemctl`コマンドを使うのをやめました。**


以下環境での話です。

```sh
# Dockerを動かしている環境
WSL2 (Ubuntu 20.04.5 LTS）
# Dockerのバージョン
Docker version 23.0.3, build 3e7cbfd
# docker-composeのバージョン
docker-compose version 1.29.2, build 5becea4c
```

`Docker Desktop for Windows`を使用していましたが、ある日それ自体がエラーで起動しなくなり、アンイストールして最新の`Docker Desktop for Windows`をインストールし直したら、それまで動いていたWebサーバ(Apache)コンテナが動かなくなったのでムキーッ:grimacing:となりCLIに移行してみたものの同様の事象は解消されず、解決を試みたという話です。

ちなみにこの仮想環境は前任者の方が作成したもので、自分は今回初めてじっくり読み込んだ感じです（そのため言い回しが推量になっている箇所があります）。

## ディレクトリ構成とソースコード

以下のような構成でした。
実際にはMySQLコンテナとアプリケーションのソースコードを配置するディレクトリもありましたが、今回の説明ではそちらは割愛。

```sh
├── app
│   ├── Dockerfile
│   ├── httpd
│   │   ├── conf
│   │   │   └── httpd.conf
│   │   └── conf.d
│   │       └── project.conf
│   └── index.html
└── docker-compose.yml
```

### docker-compose.yml

`docker-compose.yml`の設定は以下の通り。
コンテナ内で`systemctl`コマンドを使用するために、コンテナを特権モードで実行するように指定されていました（`privileged: true`）。

```yml:docker-compose.yml
version: "3"
services:
  app:
    ports:
      - 8000:80
    container_name: test_app
    build: ./app
    # コンテナを特権モードで実行する
    privileged: true
    command: /sbin/init
```

### Dockerfile

上記`test-app`コンテナの`Dockerfile`は以下。
実際のDockerfileではPHPのインストール等を行っていましたが、今回の本筋ではないため最小限にしています。

ざっくり言うと、Apacheをインストールし、起動させるようにしています。

```docker:Dockerfile
FROM amazonlinux:2

RUN yum update -y && \
    yum install -y \
    # 確認用にpsコマンドを使用するためインストール
    procps \
    # Apacheのインストール
    httpd
    
# Apache設定ファイルの配置
COPY httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf
COPY httpd/conf.d/project.conf /etc/httpd/conf.d/project.conf

# 動作確認用のindex.htmlを配置
COPY ./index.html /var/www/html/index.html

# サービス自動起動有効
RUN systemctl enable httpd.service

RUN yum clean all && rm -rf /var/cache/yum/*

# Apache start
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```

<details><summary>確認用のindex.html</summary>

確認用の`index.html`はHello World!を出力するだけのものです。

```html:index.html
<html>
    <body>
        Hello World!
    </body>
</html>
```
</details>

## 発生した事象
コンテナのビルドも起動もエラーなく完了しますが、ブラウザで`http://localhost:8000`へアクセスしても「このページは動作していません」とだけ表示され、想定の画面が表示されません。

コンテナのApacheエラーログを確認しますが、そもそもエラーログが出力されていません。

Apacheが動いていないのでは？と思い状態を確認しようと`systemctl`コマンドを叩いたら、見慣れないエラーメッセージに遭遇しました。

```sh
$ systemctl status httpd
Failed to get D-Bus connection: No such file or directory
```

ちなみに`ps`コマンドの結果は以下です。

```sh
bash-4.2# ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0  40604  3456 ?        Ss   02:50   0:00 /sbin/init
root           7  0.2  0.0  11700  2924 pts/0    Ss   02:51   0:00 bash
root          13  0.0  0.0  49808  3280 pts/0    R+   02:51   0:00 ps aux
```

### Dockerとsystemd
そもそも`systemctl`とは`systemd`システムおよびサービスマネージャーを操作するためのコマンドです。`systemd`を簡単に言うとシステムの管理をしてくれるやつ。OSが最初に生成するプロセスであり（`systemd`のPIDは1）、全てのプロセスの創始。きちんと説明できる自信がないので概要of概要に止めておきます（勉強しよ...）。

ただし、`Docker`では`systemd`を利用することができないということです。何故？の部分に触れている記事等が少なかったのですが、以下では2点挙げられています。

> **理由1: cgroupsの壁**
> まず、Systemdは、LinuxのcgroupsというKernel提供の機能に依存しているのですが、通常のDocker containerはそもそもcgroupsの機能を使って隔離された環境で動作するため、cgroups自体を操作する権限が限定されてしまいます。

> **理由2: initの壁**
> そもそもDockerコンテナはinitから起動しない（initがない）ので、initプロセスに依存するスクリプトは軒並み動きません。serviceコマンドで操作できないサービスは、たいていこれが原因です。
> daemon化を前提とするサービスの多くがこの影響を受けます。PID 1のinitプロセスを前提としてdaemon化するプログラムは動作しません。 


https://techracho.bpsinc.jp/hachi8833/2018_09_04/61176

そして「コンテナで`systemctl`コマンドを使う」ための方法として記事等でよく挙げられているのが、**コンテナを特権モードで実行する**です。

先述のソースコードで言えば、`docker-compose.yml`内の以下がそれにあたります。

```yml:docker-compose.yml（抜粋）
    # コンテナを特権モードで実行する
    privileged: true
    command: /sbin/init
```

### 「コンテナを特権モードで実行する」とは

自分もこの「コンテナを特権モードで実行する」が何のか知らなかったのですが、調べてみるとそれは**コンテナ（プロセス）にホストの特権(root)ユーザーと同等の権限を持たせる**ということが分かりました。

これだけでもうなんか（セキュリティ的に）アカン匂いがする...:innocent:

（そして「コンテナ　特権」とかでググると危険性を指摘する記事が多いので察する。）

そもそも特権コンテナは`systemctl`コマンドを使うために設定されていたので、`systemctl`コマンドを利用せずに（特権コンテナにもせずに）`Apache`を起動する方法に切り替えようと思いました。

## ソースコードを修正

### docker-compose.ymlの修正

`docker-compose.yml`からコンテナを特権モードで実行させる箇所の記述を削除します。

```diff_yaml:docker-compose.yml
- # コンテナを特権モードで実行する
- privileged: true
- command: /sbin/init
```
### Dockerfileの修正

`Dockerfile`からは`systemctl`を使用している箇所を削除します。

`Apache`の起動は`CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]`の箇所でできるため追記は不要です。

```diff_docker:Dockerfile
- # サービス自動起動有効
- RUN systemctl enable httpd.service
```

<details><summary>最終的なソースコード</summary>

```yml:docker-compose.yml
version: "3"
services:
  app:
    ports:
      - 8000:80
    container_name: test_app
    build: ./app
```

```docker:Dockerfile
FROM amazonlinux:2

RUN yum update -y && \
    yum install -y \
    # 確認用にpsコマンドを使用するためインストール
    procps \
    # Apacheのインストール
    httpd
    
# Apache設定ファイルの配置
COPY httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf
COPY httpd/conf.d/project.conf /etc/httpd/conf.d/project.conf

# 動作確認用のindex.htmlを配置
COPY ./index.html /var/www/html/index.html

RUN yum clean all && rm -rf /var/cache/yum/*

# Apache start
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```
</details>

動作確認用に配置した`index.html`がブラウザから確認できました:cherry_blossom:

![screenshot_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961694/940d6021-07b2-6470-dbb7-fc05adba9038.jpeg)

`ps`コマンドからも`httpd`プロセスが確認できました:cherry_blossom:

```sh
bash-4.2# ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.1 249200  9120 ?        Ss   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache         7  0.0  0.1 486984  8336 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache         8  0.0  0.0 290448  6876 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache        10  0.0  0.0 290312  6292 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache        17  0.0  0.0 290312  6292 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache        37  0.0  0.0 290312  6292 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
apache        53  0.0  0.0 290312  6300 ?        Sl   02:55   0:00 /usr/sbin/httpd -D FOREGROUND
root          59  0.5  0.0  11700  2880 pts/0    Ss   03:07   0:00 bash
root          65  0.0  0.0  49808  3344 pts/0    R+   03:07   0:00 ps aux
```

## まとめのようなひとりごと

なぜそれまで動いていたコンテナの`Apache`が動かなくなったのか？のなぜ、については解明できていないのですが、調べを進める内に現状のコンテナの作りがあまり良いものではないものだということが分かりました。

たしかに同プロジェクトの運用環境では`Amazon EC2`インスタンスの`Amazon Linux 2`上に`Apache`や`MySQL`を動かしているため`systemctl`での起動が必要です。
しかしコンテナの考え方では、1つのコンテナで動かすのは1つのプロセスの想定なので、複数のプロセスを管理するための`systemd`を必要としないのだなと思いました。

https://zenn.dev/karamawanu/articles/7428686c2217c8

そう考えると運用環境もコンテナで動くようにしたほうがいいのかな（専門外だが一回やってみたい感がある）、そもそも読み込むイメージが`amazonlinux`ではなく`httpd`イメージにすることはできないのか、とか色々思うところがありました。もっと良い提案ができるだけの知識を身に付けたいです。

Dockerを中心としたコンテナ技術や仮想環境についてはまだまだ勉強中ですが、Linux周りのこともまだまだ...勉強します。

#### 参考サイト　
- [第14章 systemctl によるシステムサービス管理 Red Hat Enterprise Linux 8 | Red Hat Customer Portal](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/configuring_basic_system_settings/managing-system-services-with-systemctl_configuring-basic-system-settings)

- [systemd｜大塚商会](https://mypage.otsuka-shokai.co.jp/contents/business-oyakudachi/words/systemd.html)

- [【LPICレベル1】弱点「systemdによるサービスとターゲットの制御」を克服する (1/3)|HRzine](https://hrzine.jp/article/detail/4)

- [Dockerコンテナを特権モードで実行することが危険な理由](https://www.trendmicro.com/ja_jp/research/20/a/why-it-is-dangerous-to-run-Docker-containers-in-privileged-mode.html)

- [コンテナを突き破れ！！ ～コンテナセキュリティ入門基礎の基礎～（Kubernetes Novice Tokyo #11 発表資料）](https://www.slideshare.net/nttdata-tech/container-security-kubernetes-novice-tokyo-11-nttdata)