Ruby on Railsの開発環境をDockerで構築する方法(Rails 5.x)


この記事では、Docker を用いて Ruby on Rails(以下、rails)の 5.x 系における開発環境を構築する方法を紹介します。
※Rails 6.x 系で Docker 環境を作りたい場合は [こちら](https://qiita.com/tmasuyama/items/9663dd9caac932e0b1e7) をご覧ください。

## Docker で環境構築をするメリットとは？

通常、rails の初学者の方はマシンに直接インストールして開発環境を構築する人がほとんどだと思います。
しかし、環境の微妙な際（Ruby のバージョンや環境変数など）によってつまづいた場合、
そのトラブルシューティングには多くの時間を要してしまうかと思います。

そこで、Docker で仮想環境上に rails の環境を構築してあげることで
どのマシン上の開発環境でも等しい動作を行うことができるため、環境の差異によるエラーを避けることができます。
環境をいじりすぎた時には最悪一度リセットを出来るというのもメリットですね。

また、作成したアプリケーションを本番環境として外部へ公開しようとするときにも
開発環境と本番環境での違いを最小限に抑え、安定したアプリケーションとして稼働させることができます.

Docker で仮想環境を作って公開するなんて難しそうと思うかもしれませんが、
最近では AWS といったクラウドサービスでも Docker コンテナをそのまま実行できる ECS 等のサービスが整っているので
Docker で作った環境を公開するのも楽になってきています。

## 前提条件

マシンに Docker がインストールされていること

Docker をインストールしていない人は、公式サイトから Docker のインストーラをダウンロードしてインストールしておきましょう。
→[Docker 公式](https://www.docker.com/)

また、任意の作業フォルダを作成しておきます。
ここでは "rails-docker" というフォルダを作成し、その中で作業していくことにします。

```
$ mkdir rails-docker
$ cd rails-docker
```

## Docker 関連ファイルの準備

rails-docker 内に以下 4 つの空ファイルを準備しておきます。
VScode を利用しているなら新規ファイルの作成で作ったり、
Mac のターミナルから touch コマンドを使ってもよいです。

```
.
├── Dockerfile # 新規作成
├── Gemfile # 新規作成
├── Gemfile.lock # 新規作成
└── docker-compose.yml # 新規作成
```

### Docker ファイルの解説

Docker では、Dockerfile というファイルに基づいてコンテナのビルドが行われ、
Docker Image(コンテナの雛形)が作成されることになります。

まず Dockerfile の全文を記載します。
使用する Ruby のバージョンは 2.7.0 としています。

```Dockerfile
FROM ruby:2.7.0
RUN apt-get update -qq && apt-get install -y build-essential nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app
```

箇条書きとはなりますが、それぞれの意味を解説します。

- FROM ruby:2.7.0
  - 公開されている ruby インストール済みコンテナのうち、Ruby のバージョンが 2.7.0 であるものを引っ張ってきます。
- RUN apt-get update -qq && apt-get install -y build-essential nodejs
  - Rails の実行に必要なパッケージをインストールしています
- RUN mkdir /app
  - Rails のプロジェクトファイルを作成するアプリディレクトリを作成
- WORKDIR /app
  - 作業用のディレクトリを指定
- COPY Gemfile /app/Gemfile
  - 自分のマシン（PC）上にある Gemfile をコンテナの作業用ディレクトリに移動させ、コンテナから利用できるようにします
  - Gemfile.lock も同様
- RUN bundle install
  - Gemfile に記載されている gem を一括インストール
- COPY . /app
  - Docker ファイルが置いてあるフォルダのファイルすべてをコンテナ内の app ディレクトリにコピー
  - Rails の実行に必要なファイルをコンテナに含めるためにコピーしています

### Gemfile の解説

Ruby では Gemfile というファイルで環境で使いたい gem を定義することができます。

gem とは Ruby のライブラリのことをいいます。
gem は RubyGems と呼ばれる Ruby 用のパッケージ管理システムで管理されており、RubyGems が提供する gem コマンドを通じてインストール等ができます。

```Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.1'
```

また少し解説します。

- source 'https://rubygems.org'
  - gem のダウンロード元を指定
- gem 'rails', '5.2.1'
  - インストールする gem である rails というパッケージ名と、バージョンを指定
  - 今回は rails のバージョンは 5.2.1 を指定しています
  - どのバージョンを指定してもよいのですが rails 6 以降は webpacker, yarn が必要になるので注意してください
    - ここでは簡単に検証するため rails 5 系を使用

Gemfile があるディレクトリで "bundle install" コマンドを実行すると、
Gemfile の定義に従って、定義した gem をインストールすることができます。

先ほど解説した Docker ファイルでも、Gemfile をコンテナの作業用ディレクトリにコピーして
そのフォルダ内で bundle install を実行するように指定していましたね。

### Gemfile.lock の解説

実は Gemfile.lock は最初の時点では何も書き込む必要がありません。
これは直接編集するようなファイルではなく、
Gemfile に基づいて bundle install を実行した後に
インストールされた gem が Gemfile.lock に一覧として記述されるようになります。

使い方としては、Gemfile.lock を参照すればインストールされている gem とバージョンが分かり、
Gemfile.lock から bundle install を実行することもできるので
完全に同じ環境をもう一度作りたいときや、多人数で開発をするときに Gemfile.lock が使われます。

Gemfile だけでも良いのでは？と思った鋭い方に補足しますと、Gemfile では実はこういう書き方もできることが理由の一つになっています。

```Gemfile(例)
gem 'rails', '~> 5.2.1'
```

この場合、bundle install でインストールされる rails のバージョンは 5.2.1 以上であるものの
実際にインストールできる（公開されている）バージョンはその時点によって変わってきます。

しかし Gemfile.lock では Gemfile に従ってインストールしようとした時に実際にインストールされた gem 本体と具体的なバージョン、
付随して必要となるためにインストールされたパッケージまで記録されます。

少し整理すると Gemfile は「アプリで必要な gem の一覧」であり、
一方の Gemfile.lock は「Gemfile に従った結果、実際にインストールした gem の情報」が記述されることになります。

### docker-compose.yml の解説

この yml ファイルは Docker Compose で使用されます。

Docker Compose は、複数のコンテナで構成されるアプリケーションについて
Docker イメージのビルドや各コンテナの起動・停止といった管理を行うためのツールです。

Docker Compose では、Docker ビルドやコンテナ起動のオプションも含め、複数のコンテナのための定義を docker-compose.yml というファイルに記述し、
それを利用して Docker イメージのビルドやコンテナ起動をすることができます。

開発環境のように、Rails をそれ単体で動かすならば Dockerfile だけでもよいのですが
Rails を動かすためのアプリケーションサーバに加え、
実際に公開するときにはインターネットからのアクセスを受け付けるための Web サーバや、
またデータを保存・処理するためのデータベースサーバも用意することがあります。

```docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:
```

rails ではデータベースも必要になるため、Web サーバだけではなく MySQL を用いたデータベースサーバのコンテナも構築します。
ここでは詳解しませんが、web という欄の中の「depends_on」で rails が連携するデータベースサーバ（コンテナ）を名前で指定しています。

## rails の立ち上げ

### rails プロジェクトの作成 (rails new)

docker-compose.yml が置いてあるフォルダ（rails-docker フォルダ）で以下の docker-compose コマンドを実行します。

```
$ docker-compose run web rails new . --force --database=mysql
```

コマンドについて、オプション含め少し読み方を解説します ↓

- docker-compose: docker-compose というツールをつかって
- run: 以下のコマンドを実行します
- web: web コンテナで
- rails new: rails で新しいプロジェクトを作成する
- . : 現在のディレクトリに対して
- --force: 既存の file (ここでは Gemfile, Gemfile.lock) は上書きする形で
- --database=mysql: ただし rails のデータベースには MySQL を使用します

という意味を持っているのです。

この一行のコマンドを実行すると数分単位で処理に時間がかかるので、チョコレートでも食べながら気長に待ちましょう。

### build の実行

Gemfile に追記された gem のインストール、
および作成されたファイルをコンテナ内に取り込むため build を実行します。

```
$ docker-compose build
```

### データベース設定ファイルの編集

build が完了したら、rails で使用するデータベースファイルの設定を編集します。
config ディレクトリ内の **database.yml** というファイルが対象です。

```config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # 追加
  host: db # 変更
```

password は docker-compose.yml で指定したパスワードと合わせる必要があります。

```docker-compose.yml
...
    environment:
      MYSQL_ROOT_PASSWORD: password # ここと合わせる
...
```

また、host の欄は MySQL コンテナ名を設定しています。

### コンテナの起動

コンテナを起動するため、次のコマンドを実行します。

```
$ docker-compose up -d
```

docker-compose up がコンテナを docker-compose.yml に基づいて起動するコマンドであり、
オプションの「-d」によりバックグラウンドで起動させることができます。

### データベースの作成

いまはまだコンテナが起動しただけであり、データベースは作成されていないので
次のコマンドを実行してデータベースを作成します。

```
$ docker-compose run web bundle exec rails db:create
```

rails を実行している web コンテナで、rails db:create (=データベースの新規作成)を実行する処理となっています。

### rails 開発用サーバの起動確認

これで無事に rails の開発用サーバが起動したことになります。
ブラウザのアドレスバーに **localhost:3000** と入力し、起動を確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/60de5e98-a86d-d86a-975c-64ae127a2979.png)

rails ではお馴染みの画面が表示されれば完了です。

### コンテナの停止

開発用サーバを止めるため、コンテナを一括で停止するには以下のコマンドを実行します。

```
$ docker-compose down
```

また立ち上げたいときには docker-comopose up -d を実行しましょう。

## 最後に

これによって作られるファイルの一式は [Github](https://github.com/tmasuyama1114/rails-docker) にあげています。
フォルダ構成が分からなくなったり、自分の環境でうまくいっているか比較して確かめたい方はご参照ください。