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


こんにちは、Masuyama です。

今回は docker-compose を用いて
Rails 6 系のアプリを Docker ベースで構築する方法をチュートリアル形式で解説します。

この記事で解説するチュートリアルの流れは以下の通りです。

0. 前提条件の確認
1. 必要なファイルを準備
2. コンテナイメージのビルド
3. Rails プロジェクトを作成
4. データベースの準備
5. 必要なパッケージをインストール
6. コンテナを起動
7. ブラウザで動作確認
8. コンテナを削除

チュートリアルを通して学ぶことで、
Rails を Docker ベースで動かすために必要なファイル、そして流れを掴めるようになります。

初心者向けに、手順には適宜説明を加えているので安心してください。

## チュートリアル

### 0. 前提条件の確認

今回のチュートリアルを実施していくにあたり、
開発に使用する PC に Docker をインストールしておきます。

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

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

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

なお、基本的には Mac や Linux (AWS Cloud9 の人もコレ) を想定して
mkdir, cd, touch といったコマンドを書いていることがありますが
Windows の方は適宜読み替えていただければと思います。

### 1. 必要なファイルを準備

#### 空ファイルの準備

まずは rails-docker ディレクトリローカルの中に
以下の 5 つの空ファイルを作成しましょう。

- Dockerfile
- docker-compose.yml
- Gemfile
- Gemfile.lock
- entrypoint.sh

一つひとつファイルの作るのが面倒であれば
以下のコマンドをターミナルで叩くと一発で作れます。

```
touch {Dockerfile,docker-compose.yml,Gemfile,Gemfile.lock,entrypoint.sh}
```

作成できたら、Gemfile.lock 以外の 4 ファイルを編集していきます。

#### Dockerfile 　を編集

Docker では、 **Dockerfile という名前のファイルで定義した通り**に
コンテナイメージの作成が行われます。

そのため、Rails を動かすために必要なパッケージのインストール等は
この Dockerfile の中で指定することになります。

また、Dockerfile 内でベースとなるコンテナイメージを指定することも可能です。

空の Linux から Ruby をインストールしていくのは大変なので、
通常は任意のバージョンの Ruby が最初からインストールされている
[Ruby 公式のイメージ](https://hub.docker.com/_/ruby)を使用するのがいいでしょう。

今回は **Ruby 2.7.5** を指定してみましょう。

Dockefile を以下のように編集してください。

**Dockerfile**

```Dockerfile
FROM ruby:2.7.5

# yarnパッケージ管理ツールをインストール
RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn

RUN apt-get update -qq && apt-get install -y nodejs yarn
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

RUN yarn install --check-files
RUN bundle exec rails webpacker:compile

# コンテナ起動時に実行させるスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Rails サーバ起動
CMD ["rails", "server", "-b", "0.0.0.0"]
```

#### docker-compose.yml 　を編集

今回のように Rails を動かすコンテナサービス以外にも
MySQL (DB) を動かすコンテナサービスを起動し、サービス間での連携が必要な場合には
**Docker Compose** というツールを利用します。

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

Docker Compose では、Docker ビルドやコンテナ起動のオプションも含め
複数のコンテナのための定義を **docker-compose.yml** というファイルに記述することで、
**Docker イメージのビルドやコンテナの起動を一括**で行うことができるようになります

では、docker-compose.yml の中身を以下のように編集します。

`db` という欄で MySQL (DB) のコンテナサービス（以下、コンテナ）の起動に関する設定をし、
`web` という欄で Rails (アプリ) サービス起動に関する設定をしています。

**docker-compose.yml**

```docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"
    volumes:
      - ./tmp/db:/var/lib/mysql

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

### Gemfile の編集

**Gemfile**

```Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6.1.4'
```

### entrypoint.sh の編集

**entrypoint.sh**

```entrypoint.sh
#!/bin/bash
set -e

rm -f /myapp/tmp/pids/server.pid

exec "$@"
```

これでスタート時点で必要なファイルは準備できました！

### 2. コンテナイメージのビルド

次は、前項で作成した Docker 関連ファイルを使って
早速コンテナイメージをビルドします。

ここで、

```
$ docker-compose build
```

ここで数分〜十数分かかることがあるので、気長に待ちましょう。

### 3. Rails プロジェクトを作成

次は docker-compose コマンドを使って `rails new` を実行し、
Rails プロジェクトを作成しましょう。

`docker-compose run` に続けてサービス名を指定し、
さらにコンテナ内で実行したいコマンド（=rails コマンド) を続けていきます。

Rails が動くサービスには `web` という名前を docker-compose.yml で付けたので
コマンドでのコンテナ名としては `web` を当てはめます。

以下のコマンドを実行してください。

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

`rails new` した時と同じように、ディレクトリ内に関連ファイルが生成されます。

### 4. データベースの準備

では次に、データベースの準備をしていきましょう。

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

下記のように、まるっと書き換えてください。

**config/database.yml**

```config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: localhost

development:
  <<: *default
  database: myapp_development
  host: db
  username: root
  password: password

test:
  <<: *default
  database: myapp_test
  host: db
  username: root
  password: password
```

ポイントは、`host` の欄が `db` であることです。

`db` は docker-compose.yml で指定した MySQL のコンテナ名ですね。

同じ docker-compose.yml で指定したコンテナ間であれば、
コンテナ名をホストとして名前解決してアクセスすることができます。

さて、これで Rails がデータベースと連携できるようになったので
`rails db:create` コマンドを docker-compose 経由で実行して
データベースを作成しておきましょう。

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

### 5. 必要なパッケージをインストール

Rails 6 系からは Webpacker が必要となっているため
web コンテナ内に Webpacker をインストールしておきます。

これも `rails` コマンドから実行できます。

```
$ docker-compose run web rails webpacker:install
...
Webpacker successfully installed 🎉 🍰
```

これで Rails サーバを起動させるための準備が整いました！

次はいよいよ、docker-compose で Rails サーバを起動させましょう。

### 6. コンテナを起動

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

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

`docker-compose up` は、コンテナ docker-compose.yml に基づいて起動するコマンドです。

コンテナ起動時にコンテナ内で実行させたいコマンド (`= rails s`) は
Dockerfile で設定しているので、
コンテナを起動させると Rails サーバが立ち上がります。

また、オプションの `-d` を付けるとバックグラウンドで起動させることができます。

### 7. ブラウザで動作確認

これで無事に Rails の開発用サーバが起動したことになります。

ブラウザのアドレスバーに **http://localhost:3000/** と入力し、起動を確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/880b2c8e-0701-898c-3e28-d44ec25905a9.png)

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

ここまでお疲れ様でした。

### 8. コンテナを削除

さて、動作確認ができたらコンテナは停止させておきましょう。

docker-compose コマンドを使うと、一括でコンテナを削除させることができます。
開発用サーバを止めるため、コンテナを一括で削除するには以下のコマンドを実行します。

```
$ docker-compose down
```

## まとめ

今回は　今回は docker-compose を用いて
Rails 6 系のアプリを Docker ベースで構築する方法をチュートリアル形式で解説しました。

実務などの本番運用を想定する場合には
Nginx 等で別途 Web サーバのコンテナを起動させたり、
コンテナイメージを軽量化させる工夫などが必要になりますが
開発環境のために作って壊す程度であれば、今回ご紹介した方法で十分だと思います。

初学者の方は開発環境の構築で詰まることが多いですが、
Docker であれば環境 (PC) との依存による問題を回避しやすいので
ぜひ Docker を使った開発環境の構築を頑張ってみてください。