今回は開発環境構築をします。
前回構成を書いた通り、Rails + React + MySQL のDocker環境を作成します。
リポジトリの全体像は、以下のような感じ。
各ソースのディレクトリをコンテナにマウントします。
backend/
├ rails #バックエンドのソース
└ Dockerfile
frontend/
├ react #フロントエンドのソース
└ Dockerfile
docker-compose.yml
前提
macOS Monterey バージョン12.4
Docker Desktopはインストール済み
Docker構築
Docker自体をよく知らないという方は先人の知見を参考にしてください!
※そんなにわからなくていいや〜という方向けの超々ざっくり説明
→コンテナっていう塊の中でrubyとかnodeとかがそれぞれ動いていて、docker-compose.ymlが複数のコンテナの置き方とか繋ぎ方とかの指示書、Dockerfileは各コンテナの中に入れておくものとか起動した時に何をするかとかの指示書。これらの指示書を共有するとみんな同じ内容の環境で開発できるね!プロジェクトごとに使いたいバージョンとか変わってもコンテナを変えればいいだけだね!便利!っていう技術。
Docker公式のRailsのサンプルはちょっと古いけどこれ。(2023-03現在ruby2.5)
参考にした記事は以下。
Rails6.1 + MySQL + ReactでのDocker環境を構築する
Rails 7 + MySQLの環境構築をDocker composeで作る
※以下、「achievelist」は今回作るアプリ名です。好きな名前をつけてください。念の為。
バックエンド用のコンテナを作成する(Rails7.0)
/achievelist/tmp/pids/server.pid
が存在するとサーバー立ち上げに失敗するからentrypoint.sh
を使って起動時に削除しないといけないらしいです。試しに削除せずにコンテナ起動してみたら、確かに以下のようなメッセージが表示されて起動に失敗しました。
backend_1 | A server is already running. Check /achievelist/tmp/pids/server.pid.
対策は、Dockerfileと同階層に以下のようなentrypoint.sh
を設置して、Dockerfile内で/usr/bin/
にコピーし、ENTRYPOINTとして設定することです。
#!/bin/bash
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /achievelist/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
他は普通に必要な工程を書いてDockerfileを作成します。
FROM ruby:3.2.1
WORKDIR /achievelist
COPY ./rails/achievelist/Gemfile /achievelist/Gemfile
COPY ./rails/achievelist/Gemfile.lock /achievelist/Gemfile.lock
RUN bundle install
COPY ./rails/achievelist /achievelist
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
まずはこれを動かすだけのdocker-compose.yml
を書いて、、
version: '3.8'
services:
backend:
build:
context: ./backend/
dockerfile: Dockerfile
stdin_open: true
tty: true
volumes:
- ./backend/rails/achievelist:/achievelist
command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
ports:
- "3000:3000"
environment:
TZ: Asia/Tokyo
実行!
$ docker-compose up
Recreating achievelist_backend_1 ... done
Attaching to achievelist_backend_1
backend_1 | => Booting Puma
backend_1 | => Rails 7.0.4.2 application starting in development
backend_1 | => Run `bin/rails server --help` for more startup options
backend_1 | Puma starting in single mode...
backend_1 | * Puma version: 5.6.5 (ruby 3.2.1-p31) ("Birdie's Version")
backend_1 | * Min threads: 5
backend_1 | * Max threads: 5
backend_1 | * Environment: development
backend_1 | * PID: 1
backend_1 | * Listening on http://0.0.0.0:3000
backend_1 | Use Ctrl-C to stop
http://localhost:3000/
にアクセスすると、無事Railsのロゴを見ることができました。
DB用のコンテナを作成する(MySQL8.0)
こちらは公式のイメージをそのままdocker-compose.ymlに指定するだけ。DBデータは永続化しています。
※ユーザー名やパスワードは、環境設定ファイルとかに書いた方がいいです。
version: '3.8'
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
environment:
- MYSQL_DATABASE=testdb
- MYSQL_USER=root
- MYSQL_PASSWORD=pass
- MYSQL_ROOT_PASSWORD=pass
- TZ=Asia/Tokyo
backend:
build:
context: ./backend/
dockerfile: Dockerfile
stdin_open: true
tty: true
volumes:
- ./backend/rails/achievelist:/achievelist
command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
ports:
- "3000:3000"
environment:
TZ: Asia/Tokyo
depends_on:
- db
volumes:
db_data:
あと、depends_onっていう項目を今回知りました。
コンテナの依存関係を指定すると起動のタイミングをいい感じにしてくれるそうです。(参考記事)
フロントエンド用のコンテナを作成する(React18.0)
ここにReactのコンテナを載せていきます。
正直Reactは構築の手間もかからないしホスト機で直接動かせばよくない?みたいな気持ちもあるけどnodeのバージョンとかもあるしちゃんとコンテナ立てようっと。
デフォルトのポート番号が3000なのでそのままだとバックエンドと被っています。フロントのポート番号を3001とかにずらしてもいいんだけど、慣習的にサーバーサイドのポート番号は80みたいなところがあるので、ここは3000を譲ってもらうことにします。
本当はプロキシ通してSSL化して443ポートにすべきだけど面倒だからなし!
フロントのDockerfileは以下。nodeは最新で、19.7.0にしておきます。
FROM node:19.7.0-alpine
WORKDIR /usr/src/app
で、これも載せたdocker-compose.ymlが以下になります。
version: '3.8'
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
environment:
- MYSQL_DATABASE=testdb
- MYSQL_USER=root
- MYSQL_PASSWORD=pass
- MYSQL_ROOT_PASSWORD=pass
- TZ=Asia/Tokyo
backend:
build:
context: ./backend/
dockerfile: Dockerfile
stdin_open: true
tty: true
volumes:
- ./backend/rails/achievelist:/achievelist
command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
ports:
- "80:3000"
environment:
TZ: Asia/Tokyo
depends_on:
- db
frontend:
build:
context: ./frontend/
dockerfile: Dockerfile
stdin_open: true
tty: true
volumes:
- ./frontend/react/achievelist:/usr/src/app
command: sh -c "npm start"
ports:
- "3000:3000"
volumes:
db_data:
これで、一通りできたので、docker-compose up
すると、
http://localhost:3000/
にアクセスするとReactの画面、
http://localhost:80/
にアクセスするとRailsの画面が表示する状態になりました。
あとは、開発していくうちに困ったことがあれば改修していくことにします。
GitHubに載せる
私はあらかじめリモートリポジトリを作成してcloneしたところに上記環境を載せる派ですが、もう作ってしまったものをgit管理したい人は、git init してからリモートリポジトリを設定してpushしましょう。
次回予告
次は、この環境の上でいよいよWebアプリ開発に入ります。まずはAPIを作ろう!ということで次回はバックエンド編です。そもそもRuby on Railsの学習がしたくて始めたので、ここがメイン。がんばるぞい!
(2023-03-07) docker-composeのdbのenvironmentの値にクオーテーションをつけていることにより想定したユーザー・パスワードの登録ができていなかったのでクオーテーションを外しました。