コンテナー内での複数サービス起動
コンテナーの主となる実行プロセスは、Dockerfile
の最終部分に指定されるENTRYPOINT
やCMD
です。
1 つのコンテナーには 1 つのサービスを割り当てるということにすれば、気にかける箇所が絞られるので、一般的にはこれが推奨されます。
ただそのサービスからは、複数のプロセスがフォークされることもあります(たとえば Apache ウェブサーバーでは複数のワーカープロセスが起動されます)。
マルチプロセスとなることは、まったく問題ありません。
一方で、アプリケーションが持ついくつもの役割を 1 つのコンテナーに持たせることは、Docker の優れた機能を利用する観点からは避けるべきです。
コンテナーを複数にするのであれば、ユーザー定義のネットワークや共有ボリュームを利用して接続します。
コンテナーのメインプロセスは、コンテナーそのものが起動させるプロセスすべてを管理するためにあります。
メインプロセスが十分に機能していないことが原因で、コンテナー終了時に子プロセスを適切に停止できないことがあります。
起動プロセスがこの手の事態に陥った場合は、コンテナー起動時に--init
オプションを指定してみてください。
この--init
フラグは、コンテナーのメインプロセスとして、非常に小さな初期化プロセスを埋め込みます。
この小さなプロセスが、コンテナー終了時の子プロセス停止を受け持つことになります。
子プロセスの扱いをこのようにするのは、本格的な初期化プロセス、たとえばsysvinit
、upstart
、systemd
に比べて、コンテナー内部のプロセスのライフサイクルを適切に扱うことができるからです。
1 つのコンテナー内に複数のサービスを起動させる必要があるなら、方法はいくつかあります。
-
実行するコマンドをすべてラッパースクリプトに含めます。 あらかじめテストやデバッグは行っておきます。 そしてこのラッパースクリプトを
CMD
として実行します。 以下は簡単な例です。 まずはラッパースクリプトを生成します。#!/bin/bash # 1つめのプロセスを起動 ./my_first_process & # 2つめのプロセスを起動 ./my_second_process & # いずれかが終了するのを待つ wait -n # 最初に終了したプロセスのステータスを返す exit $?
Dockerfile は以下のような記述とします。
# syntax=docker/dockerfile:1 FROM ubuntu:latest COPY my_first_process my_first_process COPY my_second_process my_second_process COPY my_wrapper_script.sh my_wrapper_script.sh CMD ./my_wrapper_script.sh
-
1 つのメインプロセスを起動させたら、そのまま起動し続ける場合です。 一時的に別のプロセスをいくつか起動する(そしておそらくはメインプロセスと通信を行う)とします。 この場合は bash のジョブ制御の機能を利用します。 まずはラッパースクリプトを生成します。
#!/bin/bash # ジョブ制御を有効にします。 set -m # 1つめのプロセスをバックグラウンドで実行します。 ./my_main_process & # ヘルパープロセスを実行します。 ./my_helper_process # この my_helper_process は自分の処理を開始して終了するためには、 # 1つめのプロセスの動きを知っておく必要があるかもしれません。 # ここで1つめのプロセスをフォアグラウンド実行に戻してそのままとします。 fg %1
# syntax=docker/dockerfile:1 FROM ubuntu:latest COPY my_main_process my_main_process COPY my_helper_process my_helper_process COPY my_wrapper_script.sh my_wrapper_script.sh CMD ./my_wrapper_script.sh
-
supervisord
のようなプロセスマネージャーを利用する場合です。 これは少々面倒な方法です。 これを行うためには、イメージ内にsupervisord
パッケージとその設定を含める必要があります。 (あるいはsupervisord
が含まれているイメージをベースとします。) さらにそのパッケージが管理する別のアプリケーションが必要になってきます。 その上でsupervisord
を起動させてプロセス管理を行います。 以下はこの手法を利用する Dockerfile です。supervisord.conf
、my_first_process
、my_second_process
の各ファイルは準備ができていて、Dockerfile と同一ディレクトリに存在しているとします。# syntax=docker/dockerfile:1 FROM ubuntu:latest RUN apt-get update && apt-get install -y supervisor RUN mkdir -p /var/log/supervisor COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY my_first_process my_first_process COPY my_second_process my_second_process CMD ["/usr/bin/supervisord"]