はじめに
※今回の記事の多くはChatGPTと壁打ちした内容になります。
ところどころ明確な情報ではないのでご注意ください。
皆さん、Dockerでコンテナをビルドする際にDockerfileのCMD
でサービスの立ち上げをする際に、よくフォアグラウンドで実行しないとコンテナが停止されるという記事を見ませんか。
実際、バックグラウンドで実行するとコンテナがうまく立ち上がらないといったことがあります。
では、なぜこのようなことが起きるのでしょうか。
なんでコンテナが停止するのか?
通常のLinux環境ではsystemdやinitなどのプロセスマネージャーが導入されており、これらが子プロセスの管理を行ってくれています。なので、例えば、php-fpm.service
を立ち上げる際は以下のように親プロセスであるsystemd
からmaster processであるPID5705のphp-fpmを立ち上げてさらにfork()して子プロセス(PID5706以降)を作ります。
※PID5706以降についてはPPID(Parent Process ID)が5705となっていますね。
$ top
top - 20:09:29 up 4:36, 4 users, load average: 0.03, 0.02, 0.00
Tasks: 175 total, 1 running, 103 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.2 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 s
KiB Mem : 2027692 total, 292312 free, 477608 used, 1257772 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1392012 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 123504 5600 4060 S 0.0 0.3 0:06.36 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.03 kthreadd
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0+
$ ps -eo pid,ppid,cmd | grep php-fpm | grep -v grep
5705 1 php-fpm: master process (/etc/php-fpm.conf)
5706 5705 php-fpm: pool www
5707 5705 php-fpm: pool www
5708 5705 php-fpm: pool www
5709 5705 php-fpm: pool www
5710 5705 php-fpm: pool www
5711 5705 php-fpm: pool www
5712 5705 php-fpm: pool www
5713 5705 php-fpm: pool www
5714 5705 php-fpm: pool www
5715 5705 php-fpm: pool www
という前段はここまでにして肝心のコンテナでの動作ですね。
コンテナをフォアグラウンドで実行した際のプロセスは以下のようになります。
$ docker exec -it {コンテナID/コンテナ名} /bin/bash
# ps -eo pid,ppid,comm
PID PPID COMMAND
1 0 php-fpm
6 1 php-fpm
7 1 php-fpm
8 1 php-fpm
9 1 php-fpm
10 1 php-fpm
11 1 php-fpm
12 1 php-fpm
13 1 php-fpm
14 1 php-fpm
15 1 php-fpm
37 0 bash
60 37 ps
# ps
PID USER TIME COMMAND
1 root 0:19 php-fpm: master process (/usr/local/etc/php-fpm.conf)
6 nginx 0:00 php-fpm: pool www
7 nginx 0:00 php-fpm: pool www
8 nginx 0:00 php-fpm: pool www
9 nginx 0:00 php-fpm: pool www
10 nginx 0:00 php-fpm: pool www
11 nginx 0:00 php-fpm: pool www
12 nginx 0:00 php-fpm: pool www
13 nginx 0:00 php-fpm: pool www
14 nginx 0:00 php-fpm: pool www
15 nginx 0:00 php-fpm: pool www
37 root 0:00 /bin/bash
61 root 0:00 ps
PID1で固定化されてコンテナが停止することはございません。
現在
CMD ["/usr/local/sbin/php-fpm", "-F"]
バックグラウンドでの実行
CMD ["/usr/local/sbin/php-fpm"]
それでは実際にどのような処理が行われているかをChatGPTに聞いてみましょう。
※良い確認方法が思いつかなかったです。
ChatGPTに聞いた結果
イメージ図で比較
🔸 通常 Linux(init あり)
[user bash (PID 1000)]
|
php-fpm (PID 1001)
|
fork()
|
master (PID 1002) ← 親が終了 → init (PID 1) が新しい親になる
🔸 コンテナ(init なし)
[Docker ENTRYPOINT] (PID 1)
|
php-fpm
|
fork()
|
master (PID ≠ 1) ← でも PID 1 終了 → Docker は「全体終了」とみなす
※本記事における「init」は、主にsystemdを指すものとします。
通常 Linux(init あり)
➀user bash(Linuxにおける実行コマンドなど)が任意のプロセスID(例では1000)で立ち上がる
➁別のPID(例では1001)のphp-fpmがfork()で子プロセスを作成
➂別のPIDのmaster processで立ち上がる
➃親(➁のphp-fpmのこと)が終了してPID1であるsystemdが親(親プロセスのこと)としてみなされる
コンテナ(init なし)
➀/usr/local/sbin/php-fpmがPID1になる
➁php-fpmがfork()で子プロセスを作成
➂別のPIDのmaster processで立ち上がる
➃PID1である➀が終了⇒PID1を見ているDockerはプロセス終了とみなしてコンテナを停止
まとめ
この機会にプロセスに関する理解が深まり、とても良かったと思います。
Dockerは導入している企業も多く、汎用性も高い技術なのでプロセスとDockerコンテナの関連性はしっかり固めておきたいです。
最後までお読みいただき、ありがとうございました!