概要
dockerのコンテナは指定したコマンドがPID 1
で起動されており、使い方によってはシグナルハンドリングできないことがありますよ、という話です。
それによってプロセスをGracefulに終了できなかったりリソースリークが起きたりするので注意する必要があります。
環境
- docker v18.09.0
どんな問題が起きる?
こちらでとてもわかり易く説明されてます。
Dockerケースを要約すると、親、子、孫の3プロセスが起動している状態で
ケース | 何が起きる | 問題点 |
---|---|---|
親が死ぬ | 子も孫も強制的に死ぬ | 処理中リクエストを ハンドリングできない |
子が死ぬ | 孫は親に紐付けられるが、 親はそれを知らないので孫はゾンビになる |
リソースリーク |
という問題が起きます。
親、子だけのケースであれば前者が起きます。
こんな使い方の時は注意
特に以下のケースではこの問題が起きている可能性が高いので注意が必要です。
/bin/bash
などシェルでコンテナを実行している- nodejsアプリを
bin/www
でコンテナ実行している
どんな対応をすればいい?
直接バイナリを実行する場合はシグナルがそのバイナリに送られるので問題ないですが、そうでない場合は以下のような対応が必要になってきます。
docker runの場合
docker 1.13以降で--init
をつけるとPID 1
は/dev/init
という軽量init processを仕込んでくれます。
$ docker run --init --name test init:latest
コンテナ内部でps
してみると、こんな感じになります。
--initなし
bash-4.4# ps aux PID USER TIME COMMAND 1 root 0:00 {run.sh} /bin/bash ./run.sh 9 root 0:00 /main 16 root 0:00 /bin/bash 23 root 0:00 ps aux
--initあり
以下のように/dev/init
が挟まって適切にシグナルをハンドリングしてくれます。
bash-4.4# ps aux PID USER TIME COMMAND 1 root 0:00 /dev/init -- ./run.sh 8 root 0:00 {run.sh} /bin/bash ./run.sh 9 root 0:00 /main 16 root 0:00 /bin/bash 23 root 0:00 ps aux
docker-composeの場合
docker-compose 1.13以降で、docker-compose.ymlが
- v2なら2.2以上
- v3なら3.7以上
において以下のようにinit: true
を設定します。
version: '2.2' services: web: image: alpine:latest init: true
Compose file version 2 reference | Docker Documentation
ECSの場合
Task DefinitionにinitProcessEnabled
をつけます。
タスク定義パラメーター - Amazon Elastic Container Service
Kubernetesの場合
にあるように、Kubernetesはオーケストレーションツールであってコンテナランタイム側の対応をするつもりはないようです。
なのでDockerfileで
などを導入してそれらをENTRYPOINTにする必要があります。
その他
dumb-initとか対応してるdocker imageで--init
をつけると?
/ # ps aux PID USER TIME COMMAND 1 root 0:00 /dev/init -- docker-entrypoint.sh agent -retry-join consul-server-bootstrap -client 127.0.0.1 8 root 0:00 {docker-entrypoi} /usr/bin/dumb-init /bin/sh /usr/local/bin/docker-entrypoint.sh agent -retry-join consul-server-bootstrap -client 127.0.0.1 9 consul 0:00 consul agent -data-dir=/consul/data -config-dir=/consul/config -retry-join consul-server-bootstrap -client 127.0.0.1 27 root 0:00 /bin/ash 34 root 0:00 ps aux
こんな感じで
dumb-init -> consul ↓ /dev/init -> dumb-init -> consul
となるようです。動作としてはシグナルは伝播されて問題ありませんでした。