立ち上げたDockerが終了するのが遅い
gcc
のイメージを使ってdocker
コンテナをデタッチで立ち上げたが、終了するのが遅いのでそれを解消した。
結論
- コマンドは
bash
ではなく、cat
を使うとよさそう。 -
init
プログラムをPID1で実行しよう。
課題
次のようなdocker-compose.yml
ファイルを作成して、docker compose up -d
を実行して、コンテナ(?)を立ち上げた。
services:
gcc:
image: gcc
container_name: hoge
tty: true
command: "bash"
そのあと、docker compose exec -it gcc bash
でコンテナにアクセスして、作docker compose down
でコンテナを終了しようとしたら、10秒ほどかかる。なぜに!?
10秒もかかっていると、CIや自動化でイライラしそうなので、今のうちに解決したい。
docker コンテナ 終了しない
やdocker 終了 遅い コンテナ
などで調べると、次のようなことが原因らしい。
原因1 - bash
docker
は、docker compose down
やdocker <container名> stop
を行ったときに対象のコンテナにSIGTERM
を送信する。しかし、bash
はSIGTERM
が送信されても新しいプロンプトを返すだけで、終了はしない。SITERM
がタイムアウトになり、docker
はSIGKILL
を送信して強制終了する。そのため、時間がかかっていたようである。
tty
は、疑似端末を割り当てるために必要、、、らしい。勉強不足だが、これを付けるとフォアグラウンドではなくデタッチドでもコンテナが終了しない。
bash
がSIGTERM
を送信されても、終了しないことはkill -s SIGTERM $$
(現在のシェルのプロセスにSIGTERM
を送信する)などで確認可能。あとは、公式リファレンスとか探すと書いてあるかも。知らんけど。
init
& PID1
原因2 - PID1のプロセスだけは明示的に、SIGTERM
を処理しないと終了処理が走らないらしい。killコマンドが制限しているのか、一体何が制限しているのかは不明。
また、Linux系は最初にinit
というプログラムが実行される。docker
コンテナだとそれをすっ飛ばして、コマンドを実行する。それによって、本来init
プログラムが正常にSIGTERM
を処理していたところ、それがなくてタイムアウトまで終了しないようである。
原因まとめ
PID1でinit
以外のプログラムやSIGTERM
を処理しないプログラムがあると、終了しない。init
のサブプロセスとしてbash
を実行していたとしても、SIGTERM
を無視するため終了しない。
解決策
docker
はdocker-init
というプログラムがデフォルトでインストールされているそう。docker run
では--init
, docker-compose.yml
ではinit
を追加すれば、普通のOSのような処理を色々してくれる。ref.docker-run#init: https://docs.docker.jp/engine/reference/run.html#init
bash
はSIGTERM
を無視してしまうので、cat
コマンドを使う。
cat
コマンドの採用理由は、入力を待機してくれること、大抵のLinuxに入っていること、処理負荷が少なそうなこと、メモリ消費量が比較的少ないこと、があげられる。
メモリ消費量に関しては、手元の環境では796kbほどだった。(思ってたより多かった)
sh
: 936kb,bash
: 3484kb (top
コマンドのRES
値を参照した)
結果
問題なく終了するdocker-compose.yml
services:
gcc:
image: gcc
container_name: hoge
tty: true
init: true
command: "cat"
終了処理
まとめ
強制終了のため10.3sかかっていた終了処理が、0.3sにまで短くなった。
このやり方が色々問題が発生しないかは疑問が残るが、目的は達成できてよかった。
おまけ - docker run
bash
起動
docker run -itd --rm --init --name hoge gcc bash
終了(計測込み)
$ time docker stop hoge
hoge
real 0m10.694s
user 0m0.000s
sys 0m0.000s
cat
起動
docker run -itd --rm --init --name hoge gcc cat
終了(計測込み)
$ time docker stop hoge
hoge
real 0m0.602s
user 0m0.000s
sys 0m0.046s
Discussion