クィックスタート: Compose と Rails

このクィックスタートガイドでは Docker Compose を使って、簡単な Rails/PostgreSQL アプリを設定し実行する手順を示します。 はじめるには Compose のインストール が必要です。

プロジェクトの定義

アプリのビルドに必要となる 4 つのファイルを作るところから始めます。 まずアプリケーションは、その依存パッケージも含め、すべてを Docker コンテナの内部にて実行するようにします。 そこでコンテナ内に含めるものが何であるのかは、正確に定義する必要があります。 これを行うのが Dockerfile というファイルです。 まずは Dockerfile を以下のようにします。

FROMruby:2.3.3RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejsRUN mkdir /myappWORKDIR /myappADD Gemfile /myapp/GemfileADD Gemfile.lock /myapp/Gemfile.lockRUN bundle installADD . /myapp

上の設定はイメージ内部にアプリケーション・コードを置きます。 そして Ruby、Bundler などの依存パッケージすべてをコンテナ内部においてビルドします。 Dockerfile の記述方法の詳細は Docker ユーザ・ガイドDockerfile リファレンス を参照してください。

次にブートストラップを行うファイル Gemfile を生成して、Rails をロードできるようにします。 このファイルは railsnew を行ったタイミングで書き換わります。

source'https://rubygems.org'gem'rails','5.0.0.1'

空のファイル Gemfile.lock を生成して Dockerfile のビルドができるようにします。

touch Gemfile.lock

最後に docker-compose.yml が取りまとめてくれます。 このファイルには、データベースとウェブという 2 つのアプリを含んだサービスが定義されています。 そしてそれぞれの Docker イメージをどう作るかが示されています。 (データベースは既存の PostgreSQL イメージにより動作します。 ウェブアプリはカレントディレクトリ内に生成されます。) また、リンクによってそれを結び合わせることが設定されていて、ウェブ・アプリのポートは外部に公開されています。

version:'3'services:db:image:postgresweb:build:.command:bundle exec rails s -p 3000 -b '0.0.0.0'volumes:-.:/myappports:-"3000:3000"depends_on:-db

ちなみに

このファイルの拡張子は .yml.yaml のどちらでも構いません。

プロジェクトのビルド

ここまでの 4 つのファイルを使って docker-compose run を実行し、Rails アプリのひながたを生成します。

docker-compose run web rails new . --force --database=postgresql

最初に Compose は Dockerfile を用いて web サービスに対するイメージをビルドします。 そしてこのイメージを利用して、新たに生成されたコンテナ内にて railsnew を実行します。 処理が完了すれば、できたてのアプリが生成されているはずです。

ファイル一覧を見てみます。

$ ls -l
total 64-rw-r--r-- 1 vmb staff 222 Jun 712:05 Dockerfile
-rw-r--r-- 1 vmb staff 1738 Jun 712:09 Gemfile
-rw-r--r-- 1 vmb staff 4297 Jun 712:09 Gemfile.lock
-rw-r--r-- 1 vmb staff 374 Jun 712:09 README.md
-rw-r--r-- 1 vmb staff 227 Jun 712:09 Rakefile
drwxr-xr-x 10 vmb staff 340 Jun 712:09 app
drwxr-xr-x 8 vmb staff 272 Jun 712:09 bin
drwxr-xr-x 14 vmb staff 476 Jun 712:09 config
-rw-r--r-- 1 vmb staff 130 Jun 712:09 config.ru
drwxr-xr-x 3 vmb staff 102 Jun 712:09 db
-rw-r--r-- 1 vmb staff 211 Jun 712:06 docker-compose.yml
drwxr-xr-x 4 vmb staff 136 Jun 712:09 lib
drwxr-xr-x 3 vmb staff 102 Jun 712:09 log
drwxr-xr-x 9 vmb staff 306 Jun 712:09 public
drwxr-xr-x 9 vmb staff 306 Jun 712:09 testdrwxr-xr-x 4 vmb staff 136 Jun 712:09 tmp
drwxr-xr-x 3 vmb staff 102 Jun 712:09 vendor

Linux 上で Docker を利用している場合、railsnew により生成されたファイルの所有者は root になります。 これはコンテナが root ユーザにより実行されているためです。 この場合は、生成されたファイルの所有者を以下のように変更してください。

sudo chown -R $USER:$USER .

Docker on Mac あるいは Docker on Windows を利用している場合、railsnew により生成されたファイルも含め、すべてのファイルに対しての所有権は、正しく設定されているはずです。

ここに新たな Gemfile が作成されたので、イメージを再ビルドすることが必要です。 (再ビルドが必要になるのは、今の時点、あるいは一般的には Gemfile や Dockerfile を修正したときだけです。)

docker-compose build

データベースの接続設定

アプリは実行可能ですが、実行するのはまだです。 デフォルトで Rails は localhost において実行されているデータベースを用います。 したがってここでは db コンテナを用いるように書き換える必要があります。 また postgres イメージにおいて設定されているデフォルトのデータベース名、ユーザ名を変更することも必要です。

config/database.yml の記述内容を以下のように書き換えます。

default:&defaultadapter:postgresqlencoding:unicodehost:dbusername:postgrespassword:pool:5development:<<:*defaultdatabase:myapp_developmenttest:<<:*defaultdatabase:myapp_test

docker-compose up によりアプリを起動します。

docker-compose up

正常に動作すれば、PostgreSQL による出力が確認できるはずです。 そしてすぐに、いつもの出力が続きます。

Starting rails_db_1 ...
Starting rails_db_1 ... doneRecreating rails_web_1 ...
Recreating rails_web_1 ... doneAttaching to rails_db_1, rails_web_1
db_1 | LOG: database system was shut down at 2017-06-07 19:12:02 UTC
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
web_1 |=> Booting Puma
web_1 |=> Rails 5.0.0.1 application starting in development on http://0.0.0.0:3000
web_1 |=> Run `rails server -h`for more startup options
web_1 | Puma starting in single mode...
web_1 | * Version 3.9.1 (ruby 2.3.3-p222), codename: Private Caller
web_1 | * Min threads: 5, max threads: 5web_1 | * Environment: development
web_1 | * Listening on tcp://0.0.0.0:3000
web_1 | Use Ctrl-C to stop

最後にデータベースを生成することが必要です。 別の端末から以下を実行します。

docker-compose run web rake db:create

コマンドから出力される結果は、たとえば以下のようになります。

vmb at snapair in ~/sandbox/rails
$ docker-compose run web rake db:create
Starting rails_db_1 ... doneCreated database 'myapp_development'Created database 'myapp_test'

Rails の「ようこそ」ページの確認

以上です。 Docker デーモンを通じて、アプリがポート 3000 番を使って実行されています。

Docker Desktop for Mac や Docker Desktop for Windows の場合は、ウェブ・ブラウザから http://localhost:3000 にアクセスすれば Rails のようこそページを確認できます。

Docker Machine を利用している場合は、docker-machineipMACHINE_VM を実行すると Docker ホストの IP アドレスを得ることができます。 これにポート番号をつけて利用します。 (<Docker-Host-IP>:3000

Rails の例

アプリケーションの停止

アプリケーションを停止するには、プロジェクト・ディレクトリにおいて docker-compose down を実行します。 この場合に用いる端末画面は、データベースを起動したときと同じものを用いるか、あるいはコマンド・プロンプトにアクセスできる別画面であっても構いません。 これがアプリケーションを適切に停止する方法です。

vmb at snapair in ~/sandbox/rails
$ docker-compose down
Stopping rails_web_1 ... doneStopping rails_db_1 ... doneRemoving rails_web_run_1 ... doneRemoving rails_web_1 ... doneRemoving rails_db_1 ... doneRemoving network rails_default

アプリケーションの停止はまた、docker-composeup を実行したシェルにおいて Ctrl-C を入力することでも実現できます。 ただしこの方法で停止した場合に、さらに再起動しようとすると、以下のようなエラーが発生するかもしません。

web_1 | A server is already
running. Check /myapp/tmp/pids/server.pid.

このエラーを解決するには、tmp/pids/server.pid を削除してから、再び docker-composeup を実行すれば、アプリケーションを再起動することができます。

アプリケーションの再起動

アプリケーションを再起動するには、以下を実行します。

  1. プロジェクト・ディレクトリにて docker-composeup を実行します。

  2. 以下のコマンドを別の端末から実行して、データベースを再起動します。docker-composerunwebrakedb:create

アプリケーションの再ビルド

Gemfile や Compose ファイルを編集して、いろいろと別の設定とした場合には、再ビルドが必要になります。 変更内容によっては docker-composeup--build だけで済む場合もあります。 しかし完全に再ビルドを行うには、docker-composerunwebbundleinstall を再度実行して、ホストにおける Gemfile.lock の変更と同期を取ることが必要になります。 その後に docker-composeup--build を実行します。

以下に示すのは前者、つまり完全な再ビルドは必要としない例です。 ローカルホスト側の公開ポートを 3000 から 3001 に変更する場合を取り上げます。 Compose ファイルにおいて、コンテナ側にて 3000 としているポートを新たなポート 3001 に変更します。 そしてこの変更を保存します。

ports: - "3001:3000"

再ビルドとアプリの再起動は docker-composeup--build により行います。 そしてデータベースの再起動は docker-composerunwebrakedb:create を実行します。

コンテナ内部において、アプリはそれまでと変わらないポート 3000 で稼動していますが、ローカルホスト上から Rails ようこそページにアクセスするのは http://localhost:3001 となります。

Compose ドキュメント

参考

Quickstart: Compose and Rails

https://docs.docker.com/compose/rails/