Docker Compose でローカルの Rails 開発環境を作る

  • 159
    Like
  • 3
    Comment
More than 1 year has passed since last update.

ローカルの Rails の開発環境を直接OSに構築してしまうと、
仕事で別のバージョンの DB が必要になったケースなどで非常に苦労するので
何らかの仮想マシン上に開発環境を構築するほうが楽だと思う。

Vagrant と何かしらのプロビジョニングツールを使う方法がベターだが、
Docker Compose を試しに使ってみたら便利だった。

Docker Compose なに?

Docker における複数コンテナの管理を docker-compose.yml という1ファイルでできるようにするツールです。

詳しくは https://docs.docker.com/compose

Vagrant と比べたメリット

  • 設定ファイルが短い。

例えば Vagrant + ansible の場合、Ruby とか PostgreSQL とかのインストール方法を自分で書く必要がありますが、
docker-compose ならコンテナを取得するだけでいいのですごく楽です。

デメリット

  • 資料すくない
  • Mac だとやっぱり不安定な感じ。Linux使おう。 最近はmac上のdocker-machineでも元気に動きます

Rails の開発環境

https://docs.docker.com/compose/rails/ に Rails の開発環境の作り方があるので、これをベースにします。
次のことをやります。

  • Node.js と phantom.js をいれる
  • Rails console 上で日本語入力できるように ENV LANG C.UTF-8 を指定
  • bundle install した gem をキャッシュする

Dockerfile

FROM ruby:2.2.3
ENV LANG C.UTF-8
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs npm nodejs-legacy
RUN npm install -g phantomjs-prebuilt
RUN gem install bundler

ENV APP_HOME /myapp
RUN mkdir $APP_HOME
WORKDIR $APP_HOME

ADD Gemfile* $APP_HOME/

ENV BUNDLE_GEMFILE=$APP_HOME/Gemfile \
  BUNDLE_JOBS=2 \
  BUNDLE_PATH=/bundle

ADD . $APP_HOME

docker-compose.yml

db:
  image: postgres
web:
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  volumes:
    - .:/myapp
  ports:
    - "3000:3000"
  links:
    - db
  volumes_from:
    - bundle
  environment:
    - DB_USERNAME=postgres
    - DB_PASSWORD=
    - DB_HOST=db
bundle:
  image: myapp_web
  volumes:
    - /bundle

使っている感じ、環境変数は dotenv 等で設定するより docker-compose.yml で設定するほうが無難そうです。

bundle install で取得した gem をキャッシュする

https://docs.docker.com/compose/rails/ の場合、 bundle installbundle update のたびに全 gem を取得するので時間がかかります。
上記の docker-compose.yml にあるように bundle path を別の volume に切り出すことでキャッシュできます。

docker-compose run web bundle install
docker-compose run web bundle update

Rails new

上記の Dockerfiledocker-compose.yml を使って Rails プロジェクトを作成します。
(https://docs.docker.com/compose/rails/ と同じです)

まず、次のファイルを同じディレクトリに置きます。

  • Gemfile
  • Dockerfile
  • docker-compose.yml

Gemfile の内容:

source 'https://rubygems.org'
ruby '2.2.3'

gem 'rails'

次のコマンドを実行します。

docker-compose build
docker-compose run web bundle install
docker-compose run web bundle exec rails new . --force --database=postgresql --skip-bundle

これでホストOSに ruby さえ入れずに rails new できました。

生成されたファイルが root ユーザーの所有になってしまうので chown で自分の所有に変えます。
(これ改善方法あれば教えてください。)

database.ymlhost: db を指定します:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: <%= ENV['DB_HOST'] %>

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

これで DB も使えるようになるので次のコマンドを実行します。

docker-compose run web bundle exec rake db:setup

Rails server を起動:

docker-compose up

docker-compose run web bundle exec rails s でも起動できますが、ホストOSのポートとDocker中のポートを結びつける必要があるので
docker-compose up を使います。

テスト実行:

docker-compose run web bundle exec rake spec
docker-compose run web bundle exec rake test

[小ネタ] docker-compose up 時の rails server のログ

Linuxで docker-compose up したとき以前起動した時の rails server のログが無駄に表示されるので邪魔なときは
次のコマンドで消してからサーバーを起動します。
(この現象はなぜか Mac では発生しません)

docker-compose rm web
docker-compose up

雑感

こんな感じでちょっとの設定ファイルを用意すれば rails を動かす環境を作れます。
ホストOSに余計なものが入らないのは快適ですね。
プロジェクトで他の人が docker-compose を使いたくない場合も database.yml だけリポジトリ内で工夫すれば使えます。

若干困っていること

  • rails generate 等のコマンドを docker-compose 経由で実行した時に生成されるファイルが root 権限になるのでユーザー権限で作りたい(Linuxでのみ発生)
  • rails server の古いログを docker-compose up 時に表示しないようにしたい
    • 以前立ち上げた docker が残っているので、 docker-compose stop すると消せます
  • rails console で日本語が使えない コメント欄で解決方法を教えて頂きました。ありがとうございます!!
  • rails server 起動中に byebug が使えない (byebug -R をうまく使えればいけそう)
    • docker-compose up ではなく docker-compose run --service-ports web bundle exec rails s -b 0.0.0.0 でサーバーを起動すればデバッガが使えます。

解決方法ご存じの方がいれば教えてください :pray: