Feedforce Developer Blog

フィードフォース開発者ブログ

続・Rails 5.2 開発環境を Docker で構築する

どうも、バックエンドエンジニアのサトウリョウスケです ✌︎('ω')✌︎

前回の記事では Docker を使って Rails 5.2 の環境構築をしました。 現在も引き続き Docker についてのお話をします。

developer.feedforce.jp

その後も幾つか手を加え続けておりまして、現在この記事を書いている時点で v1.3.0 になりました 🎉 明らかに初回のナンバリングを間違えていた感がありますが、少しずつインクリメントさせていく楽しみを実感できて良いです 笑

前回からの変更点について

さて、前回の記事は v1.0.0 時点のものでしたが、ここで v1.3.0 になった現在の Dockerfile を見てみましょう。

# Dockerfile
FROM ryz310/rails-on-docker

なんと!たったの1行ぽっちです!\\\٩( 'ω' )و ////

何言ってんだコイツと思われそうですが、これはどういう事かというと、大部分を base/Dockerfile に移動したためです。

# base/Dockerfile
FROM ruby:2.5
MAINTAINER ryz310@gmail.com

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

WORKDIR /myapp
ENV BUNDLE_JOBS=32

ONBUILD ADD Gemfile /myapp/Gemfile
ONBUILD ADD Gemfile.lock /myapp/Gemfile.lock
ONBUILD RUN bundle install
ONBUILD ADD . /myapp

この base/Dockerfile のイメージは 僕のDocker Hub に置いてあります。

ONBUILD が付いたコマンドはこのイメージを継承したイメージで実行されるため、先ほどの Dockerfile には FROM しかありませんが、ビルドの際には以下の 4 つのコマンドが実行される事になります。

ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

感覚としては、 base/Dockerfile で Rails の起動に必要なサーバー環境を構築して、 Dockerfile で Rails そのものを構築していくような感じです。 Rails の構築には RDS イメージなども必須となってきますので、それについては docker-compose.yml と組み合わせて構築していきます。

# docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    ports:
      - "3306:3306"
  web:
    build: .
    image: web_image
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      DB_HOST: db
  spring:
    image: web_image
    command: bundle exec spring server
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
    tty: false
    stdin_open: false
    environment:
      DB_HOST: db
volumes:
  mysql_data:
  bundle:

ここも v1.0.0 の頃からいくつか変更がありまして、例えば webspring で同じ内容になるように v1.0.0 では YAML のエイリアスを使っていたのですが、 docker image で共有する方法に変えました。この定義の記述について少し補足します。

web の定義で build: .image: web_image と言う記述がありますが、これは Dockerfile をビルドして web_image というタグをつける、と言う振る舞いになります。一方、 spring の定義の image: web_image では web_image というタグが付いたイメージを使用する、という振る舞いになります。この辺はなんだかややこしいですね 😓

また、 bundle:/usr/local/bundle を volume に指定する事で、bundle install の内容を永続化するようにしてあります。これにより、$ docker-compose run --rm web bundle install というコマンドが有効になってくるので、Gemfile を更新した際に一から Build する必要がなくなります。 同様に、 MySQL も mysql_data:/var/lib/mysql を volume に指定する事で、テーブルの内容を永続化するようにしています。

まとめ

ONBUILD を使用する事で、他の Rails アプリでも同じイメージを転用できるようになったのが一番の改善点ではないかと思います。

ただ、Rails アプリ側の事情で何か $ apt-get install を加えたくなった場合にどうするのか、という課題感があります。base/Dockerfile は汎用的な環境構築を意識しているので、あまり一般的でないインストールは行いたくありません。理想としては「子イメージ」で $ apt-get install させて、「孫イメージ」で今回のように Rails の構築をする構成が実現できれば良いのではないかと思いますが、 ONBUILD を「子イメージ」でスキップさせるとか出来るんでしょうか?

次回はこの辺について少し調べていければ、と思っています。