Edited at

docker-compose で Rails の開発環境を作る

More than 3 years have passed since last update.


docker-compose で Rails の開発環境を作る

docker-compose (fig) を利用して Rails の開発環境を作ってみます。個人的には Docker を本番環境で運用するのはまだちょっと怖いなーという感じなのですが、開発環境やテスト環境でならもう全然使えるレベルかなと思います。例として Rails 4.2 + PostgreSQL 9.4 の環境セットアップ。Docker の基本的な操作はひととおり抑えているものとします。

こちらの記事を参考にしてます。

この記事で作ったプロジェクトはこっち。


コンテナ戦略

原則 1 Container 1 Service に従います。従って超基本構成なら


  • Rails コンテナ

  • DB コンテナ

となります。後から Redis を追加したいとなった場合は、


  • Rails コンテナ

  • DB コンテナ

  • Redis コンテナ

となります。1コンテナで複数のサービスを動作させるのは基本的にはやらない。


Rails の Dockerfile を準備する

Ruby が初めから入ってるイメージを選ぶと無駄がないです。以前は CentOS 等のイメージを持ってきてあれこれセットアップして…みたいなのでしたが今は色んなオフィシャルコンテナが用意されてるのでとても簡単ですね。こんな感じです。

FROM ruby:2.2.2

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev postgresql-client

RUN mkdir /app

WORKDIR /tmp
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install

ADD . /app
WORKDIR /app

/tmp に Gemfile をコピーしてるのは bundle install を高速化するというやつですね。Docker 1.1 から ADD キャッシュが入ったので、Gemfile が変更されなければ再ビルドをしても、高速にセットアップすることが出来ます。Dockerfile はリポジトリのルートにおいておくのが良いかと。


docker-compose でオーケストレーション

docker-compose.yml を同じくリポジトリのルートに準備。復数のコンテナを同時に利用できるよう設定を行います。

db:

image: postgres
expose:
- "5432"
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app
ports:
- "3000:3000"
links:
- db

DB コンテナの Dockerfile は用意しませんでしたが、ここではオフィシャルの postgres イメージをそのまんま使ってます。ポート版は 5432 なので、これはそのまま expose (コンテナ外へポート開放) してます。

Rails コンテナの Dockerfile は先ほど準備したものを build: . で指定、links によって DB コンテナを同時に起動するようにしています。Rails コンテナは Docker 外から接続させたいので expose ではなく posts を利用してます。expose と ports はこんな感じ。


  • expose: Docker 内の他のコンテナ向けにポートを開放

  • ports: Docker 外にポートを開放、Docker 内の他のコンテナからもアクセス可能



    • portsDockerホストポート:Dockerコンテナポート で対応してます



オーケストレーションはこれだけでOKですが、DB は別コンテナになるので Rails の database.yml を書き換えておきます。

development: &default

username: postgres
host: db

db となってるのはコンテナ名ですね。


コンテナ起動

後は docker-compose コマンドを利用してコンテナを起動するだけです。

docker-compose build

まずコンテナをビルドします。その後、DB の作成処理などが必要になるので、

docker-compose run web bin/rake db:create db:migrate db:seed

などとして Migration を掛けます。 web を対象にコマンドを実行していますが、DB コンテナにリンクしているため同時にDBコンテナも起動します。終わったら

docker-compose up

基本的にはこれだけで2つのコンテナが上がってくると思います。Rails コンテナのコマンドに rails server を指定してるので docker-compose up するとサーバーのログがそのまま出ると思います。この状態で localhost:3000 にアクセスすると Rails が起動していることが確認できるはず。(boot2docker 使ってる場合は boot2docker ip で出てくるIPに変える)

この状態ができれば、リポジトリのファイルが Rails コンテナとリンクしているため、ローカルのファイルを編集すれば、コンテナ上のアプリケーションに反映されます。つまりいつも通り開発ができるということですね。


コンテナ起動後の操作

Migration を行いたいなどの場合、起動中のコンテナに対する操作は行わず、 docker-compose run を利用して別途コンテナを起動する形になります。


  • 各種操作の対応表

ローカル開発時
Docker Compose

rails g model Member
docker-compose run web rails g model Member

rake db:migrate
docker-compose run web rake db:migrate

rails dbconsole
docker-compose run web rails dbconsole

RAILS_ENV=test bundle exec rake db:setup
docker-compose run -e RAILS_ENV=test web bundle exec rake db:setup

従来のローカル開発に比べてちょっとテンポ悪くなるところもあるんですが、依存するミドルウェアが多い等のコンテナが沢山あるような環境であるほど恩恵を受けられると思いますよ。


他の開発メンバーに環境を配る

Dockerfiledocker-compose.yml をリポジトリに含めておけば、リポジトリを clone してもらって、docker 動くようにしてから

$ docker-compose build

$ docker-compose run web bundle exec rake db:setup
$ docker-compose up

を叩いてもらうだけです。ruby や mysql をインストールみたいなのも必要ないですしね。ただ、メンバーが Docker 動く環境を持ってないとつらいですね…


その他

雑感とかTipsとか。


ローカル開発環境を完全に捨てることはまだ難しい

rails new する時とか、ちょっとこの gem 試したいなー、の時とか Docker 外の環境を利用することはゼロではないので、完全にコンテナベースとするのはまだ難しい印象です。やり方が悪いのかもしれませんが。

ただ、メイン開発メンバーでない限り例えば、デザイナーさんに環境を渡して開発してもらう、等の場合にはかなりの威力を発揮すると思います。ちょっとコマンド叩いてもらうだけでアプリケーション起動しますからね。


インフラ構築にストレスが無い

docker-compose.yml にちょろっと掛けば Redis やら Memcached やらすぐに利用できるようになるのメッチャ快適です。しかもアプリケーション固有のバージョンを指定して利用できますからバグの再現性なども高く快適です。


Gemfile の更新がちょっとストレス

仕方ないとはいえ、Gemfile を更新するとイメージを再ビルドすることになってしまいます。コンテナ再構築時には、1から bundle install することになるので結構な時間がかかります。こういうテクニックも考えられますが、まあそこまでやるかなあ…という気はしますね。

# Rails 等基本的な Gemfile をまとめて install することでちょっと時間を短縮

RUN gem install rails pg rspec guard factory_girl ....
# アプリケーション本体の bundle install
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install


docker-compose コマンド長い!

元は fig というツールだったので私の場合はエイリアスを割り当てててます。

alias fig='docker-compose'

fig build

fig up
fig run web rails console

とかですね。