2021年3月2日火曜日

Dockerのコンテナ停止時にExit 137になる問題を解消する

現在、自宅環境には以下のコンテナを起動させて運用をしている。

  • プロキシ用コンテナ : Squid
  • DNS用コンテナ : Unbound
  • メール用コンテナ : Postfix

この中でSquidとPostfixにおいて、docker stopdocker-compose stopなどで停止処理した際に、停止はするもののExit 137というExitコードになる事象が発生した
※以下★箇所。

# docker-compose stop
Stopping centos-postfix ... done
Stopping centos-unbound ... done
Stopping centos-squid   ... done

# docker-compose ps
     Name                   Command                State     Ports
------------------------------------------------------------------
centos-postfix   /startup.sh                      Exit 137 ←★
centos-squid     /bin/sh -c /usr/sbin/squid ...   Exit 137 ←★
centos-unbound   /usr/sbin/unbound -d             Exit 0  

調べたところ、SquidとPostfixのコンテナで、それぞれExit 137となる原因が違っていた。

今回は、Docker停止時にExit 137になる原因の説明と解消方法を記載する。

環境

  • DockerホストOS : CentOS 8.2
  • Docer : 19.03.14
  • Docker Compose : 1.27.4

Dockerのコンテナ停止時にExit 137になる理由

そもそもコンテナがExit 137で停止する理由について記載する。

Dockerのデフォルト設定ではコンテナ停止を行う際に、まずPID 1のプロセスに対してSIGTERMのシグナルを送信しプロセス終了を促す。Dockerは10秒待機し、それでもプロセスが終了しない場合は、SIGKILLシグナルにて強制終了を行う。

Exit 137SIGKILLによるプロセスの終了を実施した際に出力されるExitコードとなる。

SquidコンテナのExit 137の原因と解消方法

SquidのコンテナがExit 137となる理由は、Squidのキャッシュをディスクに書き込みするための待機時間としてデフォルトで30秒待機してから停止が完了するためである。Dockerは10秒でSIGKILLにて強制終了をしてしまうため、通常のSIGTERMによる停止処理が間に合わない。

そのため、解消方法としては、Docker側のコンテナ停止処理時のタイムアウトを30秒より多い時間に延長するか、Squid側の待機時間を10秒未満とするか、どちらかの手法で対応できる。今回は後者にて対応する。

Squidの停止処理の待機時間は、shutdown_lifetimeというパラメータで設定できるので、デフォルトの30秒から5秒に変更する。
※参考:squid : shutdown_lifetime configuration directive

具体的にはsquid.confに以下を追加すればよい。

shutdown_lifetime 5 seconds

設定変更した内容でコンテナを再作成し、docker stopコマンドでコンテナを停止してみたところ、以下の通り、Exit 0で正常に停止できていることがわかる。

# docker stop centos-squid
centos-squid

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                          NAMES
bb34a12ed7bc        centos-squid:1      "/usr/sbin/squid -N …"   13 hours ago        Exited (0) 5 seconds ago                                                  centos-squid

PostfixコンテナのExit 137の原因と解消方法

Postfixのコンテナでは、maillogにメール送受信のログを出力させるためにrsyslogを起動させている。この際に、以下のようなstartup.shというラッパースクリプトを作成して、rsyslogとPostfixの起動を実現していた。

#!/bin/bash

/usr/sbin/rsyslogd
/usr/sbin/postfix start-fg

上記スクリプトでプロセスを起動した際のコンテナにおけるpsの結果を以下に記載する。Postfixの一部プロセスのPID/PPIDが1以外の番号で動作していることがわかる。

# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 05:46 ?        00:00:00 /bin/bash /startup.sh
root           7       1  0 05:46 ?        00:00:00 /usr/sbin/rsyslogd
root           9       1  0 05:46 ?        00:00:00 /bin/sh /usr/libexec/postfix
root          76       9  0 05:46 ?        00:00:00 /usr/libexec/postfix/master
postfix       77      76  0 05:46 ?        00:00:00 pickup -l -t unix -u
postfix       78      76  0 05:46 ?        00:00:00 qmgr -l -t unix -u
postfix       79      76  0 05:46 ?        00:00:00 smtpd -n smtp -t inet -u -o
postfix       81      76  0 05:46 ?        00:00:00 tlsmgr -l -t unix -u
root          85       0  5 05:52 pts/0    00:00:00 bash
root          98      85  0 05:52 pts/0    00:00:00 ps -ef

前述したとおり、Dockerは、PID 1のプロセスに対してSIGTERMのシグナルを送信するが、PID/PPIDが1以外のプロセスが存在することにより停止処理が失敗することが、Exit 137となる原因となる。

本事象を解消させるために、ラッパースクリプトのPostfixの起動コマンドにexecを付与することで解消する (★箇所)。execコマンドを使うことで、すべてのプロセスが、もとのラッパースクリプトと同じPID/PPID、すなわちPID/PPIDが1で動作するようになる。

#!/bin/bash

/usr/sbin/rsyslogd
exec /usr/sbin/postfix start-fg ★

実際にコンテナでpsを実行した結果は以下の通りとなる。Postfix関連のプロセスはすべてPID/PPIDが1となっている。

# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 05:51 ?        00:00:00 /usr/libexec/postfix/master
root           8       1  0 05:51 ?        00:00:00 /usr/sbin/rsyslogd
postfix       76       1  0 05:51 ?        00:00:00 pickup -l -t unix -u
postfix       77       1  0 05:51 ?        00:00:00 qmgr -l -t unix -u
postfix       78       1  0 05:51 ?        00:00:00 smtpd -n smtp -t inet -u -o
postfix       79       1  0 05:51 ?        00:00:00 proxymap -t unix -u
postfix       80       1  0 05:51 ?        00:00:00 tlsmgr -l -t unix -u
root          81       0  4 05:52 pts/0    00:00:00 bash
root          95      81  0 05:52 pts/0    00:00:00 ps -ef

設定変更した内容でコンテナを再作成し、docker stopコマンドでコンテナを停止してみたところ、以下の通り、Exit 0で正常に停止できていることがわかる。

# docker stop centos-postfix
centos-postfix

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                          NAMES
f4050d7cdc6d        centos-postfix:1    "/startup.sh"            3 minutes ago       Exited (0) 3 seconds ago                                                  centos-postfix

参考

0 件のコメント:

コメントを投稿

人気の投稿