Dockerを使ってRails7, React18の開発環境を構築します
記事を書くきっかけ
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を指定しました。
source 'https://rubygems.org'
gem 'rails', '~>7.0.4'
続いて、Dockerfileのビルドができるように空のGemfile.lock作成します。
続いて、Railsにはサーバー内にserver.pidというファイルが先に存在していたときに、サーバーが再起動できなくなる問題があるようなので、それを回避するためのスクリプトを作成します。
#!/bin/bash
set -e
rm -f /api/tmp/pids/server.pid
exec "$@"
続いて、Dockerfileを作成します。
今回rubyに使用するイメージはlatest、gemのバージョンはこちらのサイトで確認して、最新のものを使用しました。
Dockerfileの内容をざっくりと説明すると、イメージを指定した後にコンテナ内にapiというディレクトリを作成し、作業ディレクトリを指定しています。
次に、ローカルのGemfileとGemfile.lockをコンテナ内にコピーし、その後に、Gemをインストールします。
最後に、コンテナ起動時に実行するスクリプトを記述しています。こちらでは、コンテナ起動時にRailsサーバが起動するようにしてあります。
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をボリュームしました。
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上で設定した値に修正します。
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に記載されている下記の部分のコメントアウトを解除します。
gem "rack-cors"
Gemfileを更新したので次のコマンドを実行します。
docker compose exec api bundle install
クライアント側から呼び出せるように下記のファイルを変更します。
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を指定しました。
作業ディレクトリを指定した後、コンテナが勝手に終了しないように設定しました。
FROM node:lts-slim
WORKDIR /front
ENV CI=true
続いて、docker-compose.ymlにfrontサービスを追加します。
追加した内容をざっくりと説明すると、まず、frontのコンテナはfrontend下のDockerfileを基にイメージをビルドしています。
次に、ローカルのfrontend下のappディレクトリをコンテナ内のfrontにマウントしています。
また、ホットリロードを行うための設定をしました。
最終的な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上に公開しています。
お疲れさまでした!
まとめ
Dockerを使ってReact7, React18の開発環境をできました。Dockerを使って開発環境を構築する方法は調べると数多くの情報が出てきますが、改めて自分で動作を確認しながら作業を進めていくことで理解を深めることができたと思います。今回の設定は必要最小限のものなので、実際にサービスを運用するためにはまだまだ追記や変更があると思います。しかし、そのような設定も今回の経験の上に成り立つものだと思うので、今後は経験を積んでさらにDockerを活用していきたいと思います。
参考
【Docker】Rails 7+MySQLのDocker環境を構築する
DockerでReact+TypeScript環境を作ってみた~formatterを添えて~
Discussion