💨

Dockerを使ってRails7, React18の開発環境を構築します

2023/03/05に公開
2

記事を書くきっかけ

Dockerを使ってRails, React環境を構築することがしばしばあったのですが、そのたびに色々と調べ直し、時間がかかってしまっていたので記事にまとめました。

ゴール

RailsとReactのそれぞれでデフォルトページを表示させる。

Rails7+MySQL

まずはじめに、Rails7+MySQLの環境構築を目指します。

各種設定ファイルを作成します。
私の場合は以下のような構成にしました。

zenn-rails-react
├backend
│├Gemfile
│├Gemfile.lock
│├entrypoint.sh
│└Dockerfile
└docker-compose.yml

まずは、Gemfileを記述します。
こちらのサイトでRailsのバージョンを確認して、今回は7.0.4を指定しました。

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

続いて、Dockerfileのビルドができるように空のGemfile.lock作成します。

続いて、Railsにはサーバー内にserver.pidというファイルが先に存在していたときに、サーバーが再起動できなくなる問題があるようなので、それを回避するためのスクリプトを作成します。

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

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

exec "$@"

続いて、Dockerfileを作成します。
今回rubyに使用するイメージはlatest、gemのバージョンはこちらのサイトで確認して、最新のものを使用しました。

Dockerfileの内容をざっくりと説明すると、イメージを指定した後にコンテナ内にapiというディレクトリを作成し、作業ディレクトリを指定しています。
次に、ローカルのGemfileとGemfile.lockをコンテナ内にコピーし、その後に、Gemをインストールします。
最後に、コンテナ起動時に実行するスクリプトを記述しています。こちらでは、コンテナ起動時にRailsサーバが起動するようにしてあります。

Dockerfile
FROM ruby:latest

ARG RUBYGEMS_VERSION=3.4.6

RUN mkdir /api

WORKDIR /api

COPY Gemfile /api/Gemfile

COPY Gemfile.lock /api/Gemfile.lock

RUN gem update --system ${RUBYGEMS_VERSION} && \
    bundle install

COPY . /api

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

CMD ["rails", "server", "-b", "0.0.0.0"]

最後に、docker-compose.ymlを作成します。
docker-compose.ymlの内容をざっくりと説明すると、apiというサービス名を指定して、こちらはbackend配下のDockerfileを基にイメージをビルドしています。
volumesではローカルのbackendディレクトリをコンテナ内のapiディレクトリにマウントしています。
このあと、Reactで3000ポートを使用したいのでapiコンテナのポートは3001を指定しました。
depends_onでは、サービスの依存関係を指定しています。今回のように記述した場合、起動時には、db→apiの順に起動します。また、停止時には、api→dbの順に停止します。
また、dbサービスには最新のMySQLイメージを指定しています。
文字化け防止のために、utf8を指定しました。
volumesを記述するとコンテナを作り直したとしてもPCにデータを保存する領域が作成されるので今回はdb-volumesをボリュームしました。

docker-compose.yml
version: '3'
services:
  api:
    build: ./backend/
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./backend:/api
    ports:
      - 3001:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:latest
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: "Asia/Tokyo"
    ports:
      - "3306:3306"
  
volumes:
  db-volume:

ここまでの準備ができたら、apiモードでRailsプロジェクトを作成します。
docker compose runでは引数に指定したサービスのコンテナ内でコマンドを実行します。

docker compose run api rails new . --force --database=mysql --api

Railsプロジェクトが作成できたら、イメージをビルドします。

docker compose build

ここまでできたら、データーベースの設定をします。
デフォルトではpasswordが空白、hostがlocalhostとなっているのでdocker上で設定した値に修正します。

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

コンテナを起動して、DBを作成します。
docker compose upに-dオプションを付与することで、バックグラウンドでコンテナを実行することができます。

docker compose up -d
docker compose exec api rails db:create

下記コマンドでコンテナの情報を確認してみます。
apiとdbのふたつのコンテナが起動していることが確認できました。

docker compose ps
NAME                    COMMAND                  SERVICE             STATUS              PORTS
zenn-rails-react-api-1   "entrypoint.sh /bin/…"   api                 running             0.0.0.0:3001->3000/tcp
zenn-rails-react-db-1    "docker-entrypoint.s…"   db                  running             0.0.0.0:3306->3306/tcp, 33060/tcp

それでは、http://localhost:3001にアクセスしてみましょう。
以下のようなページが表示されたら成功です。

忘れないうちにCORSの設定をしておきます。
Gemfileに記載されている下記の部分のコメントアウトを解除します。

Gemfile
gem "rack-cors"

Gemfileを更新したので次のコマンドを実行します。

docker compose exec api bundle install

クライアント側から呼び出せるように下記のファイルを変更します。

backend/config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "localhost:3000"

    resource "*",
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

ここまででRailsとMySQLの開発環境が用意できました!

React

ここからはReactの開発環境を構築します。
先ほど作成したディレクトリ構成にfrontendディレクトリを追加します。
プロジェクトディレクトリ下にfrontendディレクトリを作成し、その下にはDockerfileを作成しました。

zenn-rails-react
├backend
│├Gemfile
│├Gemfile.lock
│├entrypoint.sh
│└Dockerfile
├frontend
│└Dockerfile
└docker-compose.yml

frontendディレクトリ下のDockerfileを記述します。
こちらのサイトで確認したところ、Nodeは14.0.0以上、npmは5.6以上のバージョンが必要であることが分かったので、イメージはlts-slimを指定しました。
作業ディレクトリを指定した後、コンテナが勝手に終了しないように設定しました。

Dockerfile
FROM node:lts-slim

WORKDIR /front

ENV CI=true

続いて、docker-compose.ymlにfrontサービスを追加します。
追加した内容をざっくりと説明すると、まず、frontのコンテナはfrontend下のDockerfileを基にイメージをビルドしています。
次に、ローカルのfrontend下のappディレクトリをコンテナ内のfrontにマウントしています。
また、ホットリロードを行うための設定をしました。
最終的なdocker-compose.ymlは以下のようになりました。

docker-compose.yml
version: '3'
services:
  api:
    build: ./backend/
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./backend:/api
    ports:
      - 3001:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:latest
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: "Asia/Tokyo"
    ports:
      - "3306:3306"
  front:
    build: ./frontend/
    volumes:
      - ./frontend/app:/front
    ports:
      - 3000:3000
    tty: true
    stdin_open: true
    environment:
      - CHOKIDAR_USEPOLLING=true
  
volumes:
  db-volume:

それでは、コンテナをビルドして起動します。

docker compose up -d --build

ひとまず、コンテナの情報を確認します。
先ほどに加えて、frontのコンテナも起動していることが確認できました。

docker compose ps
NAME                      COMMAND                  SERVICE             STATUS              PORTS
zenn-rails-react-api-1     "entrypoint.sh /bin/…"   api                 running             0.0.0.0:3001->3000/tcp
zenn-rails-react-db-1      "docker-entrypoint.s…"   db                  running             0.0.0.0:3306->3306/tcp, 33060/tcp
zenn-rails-react-front-1   "docker-entrypoint.s…"   front               running             0.0.0.0:3000->3000/tcp

下記コマンドでfrontコンテナに入ります。

docker compose exec front bash

frontコンテナに入ったあと、下記コマンドを実行し、reactプロジェクトを作成します。

npx create-react-app . --template typescript

少し時間がかかりますが、reactプロジェクトが作成できました。
続いて、frontコンテナ内で下記のコマンドを実行します。

npm start

それでは、http://localhost:3000にアクセスしてみましょう。
以下のようなページが表示されたら成功です!

これで、Rails7とReact18の開発環境を構築することができました。

今回の成果物を私のgithub上に公開しています。

https://github.com/925rycki/zenn-app

お疲れさまでした!

まとめ

Dockerを使ってReact7, React18の開発環境をできました。Dockerを使って開発環境を構築する方法は調べると数多くの情報が出てきますが、改めて自分で動作を確認しながら作業を進めていくことで理解を深めることができたと思います。今回の設定は必要最小限のものなので、実際にサービスを運用するためにはまだまだ追記や変更があると思います。しかし、そのような設定も今回の経験の上に成り立つものだと思うので、今後は経験を積んでさらにDockerを活用していきたいと思います。

参考

【Docker】Rails 7+MySQLのDocker環境を構築する
DockerでReact+TypeScript環境を作ってみた~formatterを添えて~

Discussion

PaoPao

リッキー様、
すばらしい投稿誠にありがとうございました。
おかげ様で、RailsとReactの環境を作ることができました。ほんとうにありがとうございます。
すみません、もしよろしければ、Todoアプリなど、作成した環境から、どうやってアプリを作成
していけばよいのか、ご教示いただくことはできませんか?

りっきーりっきー

コメントありがとうございます。いただいたご要望、今後の記事作成の参考にさせていただきます!