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

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

プロジェクトの定義

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

FROM ruby:2.3.3
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

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

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

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: postgres
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

ちなみに

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

プロジェクトのビルド

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

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

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

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

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

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

sudo chown -R $USER:$USER .

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

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

docker-compose build

データベースの接続設定

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

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

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test

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

docker-compose up

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

Starting rails_db_1 ...
Starting rails_db_1 ... done
Recreating rails_web_1 ...
Recreating rails_web_1 ... done
Attaching 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: 5
web_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 ... done
Created 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-machine ip MACHINE_VM を実行すると Docker ホストの IP アドレスを得ることができます。 これにポート番号をつけて利用します。 (<Docker-Host-IP>:3000

Rails の例

アプリケーションの停止

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

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

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

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

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

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

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

  1. プロジェクト・ディレクトリにて docker-compose up を実行します。
  2. 以下のコマンドを別の端末から実行して、データベースを再起動します。 docker-compose run web rake db:create

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

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

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

ports: - "3001:3000"

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

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