Supervisorを使ってDockerで複数プロセスを起動

NO IMAGE

Apache httpdとTomcatの2プロセスを1コンテナで立ち上げる必要があり、その時にSupervisorを使用したので使い方をメモ。

前提

コンテナでアプリケーションを構築する際、1コンテナ1プロセスにするべきというのが一般論で、そうすることによって以下の点でメリットがあります。

  • プロセスが落ちるとコンテナも落ちるのでゾンビプロセスが生まれない
  • stdout / stderrのログをコンテナログとして出力できる

今回は、管理対象のコンテナ数を極力制限したい等の要件があり、冒頭に書いたように1コンテナ内に2つのプロセスを立ち上げる必要がありました。

まず試したこと

まず試したのは、以下のようにhttpdとtomcatを起動するシェルファイルを作成してコンテナ起動時に実行する方法です。

FROM tomcat:9.0.36-jdk11-corretto

# apache httpdのインストール & 標準出力にログを出力する設定
RUN yum install httpd -y \
  && ln -sf /dev/stdout /etc/httpd/logs/access_log \
  && ln -sf /dev/stderr /etc/httpd/logs/error_log

# httpdとtomcatを起動するシェルファイルを作成してコンテナ起動時に実行
RUN echo -e "#!/usr/bin/env bash\napachectl start\ncatalina.sh run" > ./startService.sh
RUN chmod o+x ./startService.sh
CMD ["./startService.sh"]

こうすることで、2つのプロセスを立ち上げることはできたのですが、httpdはバックグラウンドで実行されているため、標準出力に吐き出しているログをコンテナログとして収集することができませんでした。

Supervisorの導入

ということで、複数のプロセスをフォアグラウンドで動かすような仕組みが必要となり、Supervisorを導入しました。Supervisorの設定ファイル、Dockerfileはそれぞれ以下のように作成しました。

supervisor.conf

[supervisord]
nodaemon=true

[program:httpd]
command=apachectl -DFOREGROUND
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:tomcat]
command=/usr/local/tomcat/bin/catalina.sh run
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

Dockerfile

FROM tomcat:9.0.36-jdk11-corretto

# apache httpdのインストール & 標準出力にログを出力する設定
RUN yum install httpd -y \
  && ln -sf /dev/stdout /etc/httpd/logs/access_log \
  && ln -sf /dev/stderr /etc/httpd/logs/error_log

# supervisorインストール
RUN yum -y install python3 && pip3 install supervisor
# supervisorの設定をコピー
COPY supervisord.conf /etc/supervisor/
# プロセス起動
CMD ["supervisord"]

こうすることで、無事2つのプロセスの標準出力をコンテナログに吐き出すことができました。
この構成だけだと、ゾンビプロセスが残るリスクは抱えたままですが、実際のシステムではそこはELBのヘルスチェックに任せていて、ヘルスチェックに失敗するとコンテナごと潰すようなつくりにしています。