Railsアプリ開発用のDockerコンテナでunicornを起動するにはsupervisord + unicornherderが良い

  • 22
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

背景

  • Dockerコンテナでrailsの開発環境を作ろうとしています。
  • 想定している開発マシンはMacかWindowsです。
  • VagrantでCentOS7のVMを動かしてその上でDockerコンテナを作って開発します。
  • コンテナで使用するOSもCentOS7とします。
  • railsアプリのソースコードはMacやWindowsのファイルシステム上に置いて、ソースコードを編集したら、コンテナを再起動せずにアプリに反映できるようにします。
    • MacとVagrant上のVM間はVagrantのshared_folderをtypeをNFSで使用します。
      • vboxsfは遅いのでNFSを使用することにしました。
    • WindowsとVagrant上のVM間はVagrantのshared_folderをtypeをrsyncで使用します。
      • vboxsfが遅いのと、Windowsファイルシステム上のファイルではファイルパーミションを自由に変更できないため。
    • Vagrant上のVMとDockerコンテナ間は docker run -v でファイル共有します。

Dockerコンテナ内でサービスを起動する際の注意点

以下の2点に注意が必要です

  • ゾンビプロセスを回収する必要がある
  • docker run -link によって設定された環境変数を参照する必要がある

ゾンビプロセスを回収する必要がある

Baseimage-docker: A minimal Ubuntu base image modified for Docker-friendlinessの"What important system services am I missing?"の"A correct init process"に詳しい説明がありますので、ご参照ください。

ゾンビプロセス回収の必要性を理解していなかったときに、DockerfileのENTRYPOINTでmonitを起動してそこからunicornを起動するようにしてみたのですが、 monit restart unicorn とかでunicornを再起動するとゾンビプロセスが残ったままになってしまいました。
しかも docker exec -it コンテナ名 bash でコンテナに入って kill -9 しても消えない状態でした。

docker run -link によって設定された環境変数を参照する必要がある

ゾンビプロセスを回収するには systemd を動かせば良いのではと思い、Dockerfileで CMD ["/sbin/init"] を試してみました。確かにゾンビプロセスは回収されるようになったのですが、 docker run -link によって設定された環境変数が参照できないことに気づきました。

例えば、MySQLのコンテナを docker run -p 3306:3306 --name mysql ... として起動し、unicornのコンテナを docker run -link mysql:mysql ... として起動すると MYSQL_PORT_3306_TCP_ADDR といった環境変数が設定されます。

ところが、systemd用に *.service ファイルを作って、そこでこの環境変数の値を参照しても空になってしまいました。

ふと考えると、そもそもsystemdは子プロセスとして起動することは想定していないので、親プロセスから環境変数を引き継ぐようにはなっていないのではないかと思い当たりました。

Inherit environment variables in systemd Docker container - Unix & Linux Stack Exchangeによると、 init の引数に systemd.setenv=NAME=VALUE のように指定すれば環境変数を引き継げるようです。が、 docker run -link mysql:mysql ... で設定される環境変数は名前も値も動的なので、全て指定するのも大変です。

supervisordなら両方カバーしています

supervisordなら、ゾンビプロセスの回収もできますし、環境変数も引き継ぎます。dockerのサイトにUsing Supervisor - Docker Documentationという記事があるのは知っていたのですが、supervisordを選ぶのはこういう理由があったんですね。

supervisordからunicornを起動するならunicornherderが必要

これはRails - supervisord + unicornでhot restart (deploy) する - Qiitaの記事が詳しいのでご参照ください。

unicornをリロードする際はUSR2シグナルを送るのですが、別プロセスを起動して切り替えるので、supervisordから直接unicornだとまずいことになります。unicornherderを使えば解決します。

VagrantfileとDockerfileのサンプル

https://github.com/hnakamur/vagrant-docker-rails-development-example に置きましたので、よかったらご参照ください。ただし、Windowsでは未検証です。