Dockerでsupervisorを使う時によくハマる点まとめ

morimorihoge です。最近格ゲー部に入部してGGXrd REV 2を始めました。高校時代にGGXをやっていたときと感覚が違いすぎてまだ全然ですが、チマチマ練習中です。 Dockerにはinitプロセスがないよ問題とsupervisor さて、Dockerコンテナはそのままではsystemdやsysvstat経由で起動を管理するサービス(nginxとかpostgresqlとかの永続系サービス)がうまく動きません。 これはDockerの設計思想によりinitプロセスがいないことが原因で、この辺りは Docker and the PID 1 zombie reaping problem にいい感じでまとまっています。 もしsystemdが使いたければDockerではなくsystemd-nspawnを使うのが楽でしょう、という話になるのですが、Dockerでinitプロセスを扱う試みもあるので、Dockerをできるかぎり軽量VMとして透過的に利用したいということなら以下のサイトなどが参考になりそうです。 参考: Dockerコンテナに使える「正しい」軽量init process(PID 1)まとめ では世の中のDockerユーザはこのinitプロセスがない問題をどう解決しているかというと、 supervisor というスーパーバイザ機能のみを提供する軽量プログラムを利用するのが一般的に思えます。Ubuntu系containerであれば apt-get install supervisor でインストールできます。 この辺りは以前社内勉強会で話したので別記事で解説しようと思います。 なお、本記事のDocker環境は普通のUbuntu 16.04LTSコンテナで、aptでパッケージインストールしたものです。 Dockerにおけるよくあるsupervisor設定のミス supervisor は非常に簡易な設定でプロセス起動管理ができるのでありがたいのですが、注意しないとハマります。 [supervisord] セクションで nodaemon=true にする これをtrueにしないとdaemonモードで起動します(こちらがデフォルト)。 daemonモードで起動してしまうと、Container立ち上げ時にすぐプロセスを手放してしまいContainerが終了します。 supervisorを設定したけどいざdocker runしたら一瞬でcontainerが止まってしまったという場合は大体これが原因です 。 [supervisord] nodaemon = true 参考: supervisordセクションの公式ドキュメント [program:x] セクションで autorestart を使う場合には注意する [program:#{PROGRAM_NAME}] セクションには command で実行したいコマンドを書ける上に autorestart という便利そうな設定があります。 これは当該プロセスが落ちていた場合に自動的に再起動してくれるオプションなのですが、 気軽に使うと死にます 。 もし command に service コマンド経由や /etc/init.d 以下のスクリプト経由でサービス起動するような設定を書いていて autorestart を有効にした場合、 延々とプログラムが再起動し続けます 。 外部から見ると繋がったり繋がらなかったりしてチャタリングしているように見えるので、まともなサービスはできません。気をつけましょう。 とりあえず、あまり深い理解をせずに気軽に使いたければ、 autorestartは使わず、autostartだけ設定し、再起動が必要になったらserviceコマンドやinitスクリプトで手動立ち上げするか、またはcontainerごとrestartする(supervisordが立ち上がり直すのでautostartが起動する) ことをオススメします。詳細は後述。 supervisorの設定ファイルを弄ったら reread update restart supervisorの設定は通常 /etc/supervisor にあり、こちらの設定を弄ることになりますが、この設定はsupervisor実行中には動的に読み込まれません。 設定更新時にsupervisorプロセス自体を再起動しても良いのですが、Docker Containerの起動時にsupervisordをrunプロセスに指定していた場合、supervisorが死ぬのは困ります。 というわけで、supervisordを落とさずに設定を読み込むのは以下の手順です。 supervisorctl reread supervisorctl update supervisorctl restart #{新しく追加したサービス} reread すると設定に変更があれば標準出力に表示されますが、この状態ではまだ反映されていないので、 update で反映します。その後、動作中のサービスであれば restart することで新しい設定で動作するようになります。 ※ぐぐった中では reread restart するだけで良いという記事が多々ありましたが、手元の環境(supervisor 3.2.0) では update の必要がありました。 autorestartチャタリング問題についてもう少し詳しく autostartは使うな、だけだとあんまりなので、もう少し詳しく解説します。 autorestartが正しく動く条件として、supervisorが正しく監視対象のプロセスを捕捉できている必要があります。今現在supervisorが監視対象のプロセスを捕捉できているかは、 supervisorctl status で調べることができます。 # supervisorctl status nginx EXITED May 29 07:11 AM postgresql RUNNING pid 13398, uptime 0:25:43 sshd RUNNING pid 8, uptime 3 days, 14:37:22 この結果を見ると、Nginxは落ちていてPostgreSQLとSSHdが起動しているように見えます。 ps コマンドでも確認してみましょう。 # ps ax 8 ? S 0:00 /usr/sbin/sshd -D 7382 ? Ss 0:00 nginx: master process /usr/sbin/nginx 7383 ? S 0:10 nginx: worker process 13398 ? S 0:00 /usr/lib/postgresql/9.6/bin/postgres -D /var/lib/postgresql/9.6/main -c config_file=/etc ※(抜粋) あれ? Nginxは起動しています ね。これはどういうことでしょうか? supervisorの設定を見てみると、 [program:nginx] command=service … Continue reading Dockerでsupervisorを使う時によくハマる点まとめ