この記事では、複数のDockerコンテナで構成される環境を構築するための設定例を具体的に解説します。ワークショップのフォローアップではありますが、一般的な事柄を扱いますので、ワークショップに参加されていない方にもお読み頂ける内容です。
前回の記事: JAWS DAYS 2017 ワークショップ Docker on Elastic Beanstalk 〜Days after tomorrow〜 (1)
春ですね
こんにちは。Emotion Techの子安です。ようやく暖かくなってきましたね。やっぱり春といえば桜ですかね!
恐縮です。
前回のつづき
さて、前回はテーマとする環境の構成を説明し、利用するコンテナ定義ファイル docker-compose.yml の枠組みを解説しました。更に web
app
db
コンテナのうち、 web
db
コンテナの設定を見ました。今回はアプリケーションそのものである app
コンテナを見ていきます。
各コンテナの設定 2
appコンテナ
app:
image: phusion/passenger-ruby23:0.9.20
environment:
APPLICATION_ENV: development
APPLICATION_ROLE: app
PASSENGER_APP_ENV: development
labels:
eb.workshop.role: app
networks:
- eb.workshop
depends_on:
- db
volumes:
- ./app/init/40_setup.sh:/etc/my_init.d/40_setup.sh:ro
- ./app/passenger/passenger.conf:/etc/nginx/sites-available/default:ro
- ./app/rails-app:/var/www/rails-app
Ruby on Railsのアプリを実行するappコンテナです。phusion/passenger-dockerイメージを利用しています。このイメージはさまざまな機能を持っていますが、まずは設定内容を見ましょう。
-
image
: phusion/passenger-dockerイメージを指定しています。 -
environment
: イメージ側でPASSENGER_APP_ENV
環境変数を読んでRailsの環境を切り替えてくれる機能があります。 -
volumes
: ここで3つのマウントを指定しています。コンテナ側のパスを見てください。-
/etc/my_init.d/40_setup.sh:ro
:/etc/my_init.d
配下に置いたスクリプトを初期化時に実行してくれる機能があります。実行権限を忘れずにつけるようにします。:ro
は読み取り専用の意味です。 -
/etc/nginx/sites-available/default:ro
: ここにnginxの設定ファイルが置かれています。 -
/var/www/rails-app
: Railsのアプリケーションをここに置きます。これは任意の場所で構いません。上記のnginx設定ファイルに記述しています。
-
phusion/passenger-docker
phusion/passenger-dockerは、Phusion社がメンテナンスしているDockerイメージです。このイメージは、さらに別のイメージ phusion/baseimage-docker をベースとして作られています。このphusion/baseimage-dockerには、いくつかの有用な機能が含まれています。
- 正しいinitプロセス:
/sbin/my_init
にinitプロセスを内蔵しています。本来initプロセスには、親プロセスのいなくなった子プロセス(孤児)を里親として引き受ける役割があります。加えてSIGTERM
を受け取った際に、他のサービスを終了させる機能を持ちます。 - スーパーバイザ: 軽量なスーパーバイザ runit を内蔵しています。
- ログマネージャ: syslogデーモン syslog-ng を内蔵しています。logrotateも設定済みです。
- cron: cronデーモンを内蔵しています。
重要なことは、これらの機能が協調動作するように設定されていることです。 /sbin/my_init
がrunitを立ち上げ、runitがsyslog-ngやcronを管理します。デフォルトのコンテナ起動コマンドが /sbin/my_init
に設定されていますので、
docker run phusion/baseimage
として起動することで、最小限のコンテナ化されたLinux(Ubuntu)環境を手に入れることができます。他にも、今回も利用している /etc/my_init.d
配下のスクリプトを初期化時に実行する機能、root以外でコマンドを実行するための setuser
コマンドなど、様々な機能や仕組みを備えています。詳しくはWebページを参照ください。
phusion/passenger-dockerは、このphusion/baseimage-dockerの上に、nginxやrubyのアプリケーションサーバである Phusion Passenger をインストールしてあります。nginxはrunitの配下に設定されていますので、すぐにスーパーバイズされたデーモンとして稼働させることができます。
コンテナ初期化スクリプト
可能なことはコンテナ自身に判断させるのが良い設計です。そのためにコンテナ起動時に実行するスクリプトを組み込むことがよく行われます。今回 app
コンテナで設定している初期化スクリプトの内容を見てみましょう。 /app/init/40_setup.sh を参照ください。
このスクリプトの主な役割は4つです。
- nginxを起動可能にする
- Railsアプリのセットアップ
- 環境変数の引き渡し
- DBマイグレーション
ハンズオンのため、本来はコンテナ初期化スクリプトに記述すべきでない処理もここに入っていますが、続けて詳しく説明します。
rm -f /etc/service/nginx/down
これはrunitの機能です。サービスを定義するディレクトリ(今回は /etc/service/nginx
)の直下に down
という名前のファイルがあると、自動起動しません。phusion/passenger-dockerイメージ側で配置されているものですが、自動起動してほしいのでファイルを削除しています。
chown -R app:app /var/www
cd /var/www/rails-app
setuser app bundle install --path=../vendor/bundle
if [ "$PASSENGER_APP_ENV" = 'production' ]; then
setuser app bin/rails assets:precompile
setuser app bundle install --path=../vendor/bundle --without test development --deployment --clean
fi
このあたりは実環境であればCIで、ビルドの一処理として適切に実施すべきものです。アプリケーションのファイルパーミッションを適切に設定し、ライブラリのインストールを行います。更にproductionモードであれば、アセットのプリコンパイルと不要なライブラリの削除を行います。
echo "passenger_env_var 'SECRET_KEY_BASE' '$SECRET_KEY_BASE';" >> /etc/nginx/conf.d/10_setenv.conf
echo "passenger_env_var 'RDS_HOSTNAME' '$RDS_HOSTNAME';" >> /etc/nginx/conf.d/10_setenv.conf
ここは環境変数をpassengerへ引き渡すための処理です。コンテナでは環境変数を扱う機会が多くなりますので、利用するミドルウェアに合わせて設定が必要です。
RAILS_ENV=$PASSENGER_APP_ENV setuser app bin/rails db:create db:migrate
こちらはDBのマイグレーションです。この処理も実環境であればコンテナ初期化スクリプトではなく、デプロイの手順の一貫として実施すべきものです。
次回へ
ここまでが app
コンテナの設定でした。長くなりましたので、つづきは次回にしたいと思います。次回はElastic Beanstalkの設定ファイル、Dockerrun.aws.jsonを解説する予定です。
次回の記事: JAWS DAYS 2017 ワークショップ Docker on Elastic Beanstalk 〜Days after tomorrow〜 (3)