Rails6.1 + MySQL + ReactでのDocker環境を構築する

[株式会社TECH LUCK](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)という会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご連絡いただけますと幸いです。

# 前提

SPAアプリケーションを作成するために、Rails6.1, MySQL, Reactでの開発を行いました。
その際に、`docker-compose`で環境構築を行なったので、その備忘録になります

**バージョン**
Ruby:v3.1.0
Ruby on Rails:v6.1.5
React:v18
docker-compose:v3.7

# 基本のアプリケーション作成
まずはプロジェクトのディレクトリ（RailsとReactを入れるための箱）を作るところから始めます。
この記事では`todoapp`というアプリケーションを作成するという形にします。
また、Railsは`backend`、Reactは`frontend`というアプリケーション名で作成することにします。

```bash
mkdir todoapp
cd todoapp
mkdir backend
mkdir frontend
touch docker-compose.yml
touch backend/Gemfile
touch backend/Gemfile.lock
touch backend/entrypoint.sh
touch backend/Dockerfile
touch frontend/Dockerfile
```

# Rails側（backend）の設定

Railsアプリケーションを作成するため、以下のファイル群に記述を追加します。

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


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

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```

```dockerfile:todoapp/backend/Dockerfile
FROM ruby:3.1.0
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# 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

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
```

```ruby:backend/Gemfile
source 'https://rubygems.org'
gem 'rails', '6.1.5'
```

```yml:todoapp/docker-compose.yml
version: '3.7'

services:
  db:
    image: mysql:8.0
    platform: linux/x86_64
    command: --default-authentication-plugin=mysql_native_password
    ports:
      - "4306:3306"
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    security_opt:
      - seccomp:unconfined
  backend:
    build:
      context: ./backend/
      dockerfile: Dockerfile
    stdin_open: true
    tty: true
    volumes:
      - ./backend:/myapp
      - bundle:/usr/local/bundle
    command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    depends_on:
      - db
    ports:
      - "3001:3000"
    environment:
      TZ: Asia/Tokyo
volumes:
  db:
    driver: local
  bundle:
    driver: local
```

ここまで設定できたら、以下のコマンドでRailsのDockerコンテナの中でRailsアプリケーションを作成します。

```bash:todoapp
docker-compose run --no-deps backend rails new . --force -d mysql --api --skip-test
```

Railsアプリケーションが作成できたら、`docker-compose`でDBに接続するために、`database.yml`の`defult`の箇所に`host: db`を追加します。
ここを追加しないと、Railsがdocker-composeで立ち上がっているMySQLへ接続することができません。

```yml:todoapp/backend/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
  host: db #ここを追加
```

# React側（frontend）の設定
Reactアプリケーションの直下、つまり`todoapp/frontend`ディレクトリの直下に`Dockerfile`を以下の記述で作成します。

```docker:todoapp/frontend/Dockerfile
FROM node:14.17.1-alpine
WORKDIR /usr/src/app
```

# docker-compose.ymlの設定

以下の記述で、`docker-comopse.yml`をプロジェクトの直下`todoapp`ディレクトリの直下に作成します。

```yml:todoapp/docker-compose.yml
version: '3.7'

services:
  db:
    image: mysql:8.0
    platform: linux/x86_64
    command: --default-authentication-plugin=mysql_native_password
    ports:
      - "4306:3306"
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    security_opt:
      - seccomp:unconfined
  backend:
    build:
      context: ./backend/
      dockerfile: Dockerfile
    stdin_open: true
    tty: true
    volumes:
      - ./backend:/myapp
      - bundle:/usr/local/bundle
    command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    depends_on:
      - db
    ports:
      - "3001:3000"
    environment:
      TZ: Asia/Tokyo
  frontend:
    build:
      context: ./frontend/
      dockerfile: Dockerfile
    volumes:
      - ./frontend:/usr/src/app
    command: sh -c "cd app && npm start"
    ports:
      - "3000:3000"
volumes:
  db:
    driver: local
  bundle:
    driver: local
```

```bash:todoapp
docker-compose run --rm frontend sh -c "npx create-react-app app"
```


# 実際に動かしてみる
以下のコマンドでdocker-comopseしてアプリケーションを起動させましょう。

```bash:todoapp
docker-compose up
```

初回の起動はRailsのDBが作成されていないため、エラーが発生することになると思います。以下のコマンドでDBを作成しましょう。

```bash:todoapp
docker-compose exec backend rails db:create
```

ローカルのブラウザからは**Railsはポート番号3001**、**Reactはポート番号3000**でアクセスになるので注意してください。
`docker-compose.yml`の設定でこちらは変更することができるので、お好みに合わせて適宜変更してください。
React側をポート番号3000にしないと、websocket関連でコンソールにエラーが吐かれるようになってしまったので、現状ではReact側をポート番号3000に指定しています。


# Git管理
RailsとReactでアプリケーション作成のタイミングで、それぞれGitの管理がされてしまいます。
そうなると、`todoapp`配下でgit管理をしようと思っても、うまくできないことになってしまいます。
その際には、`todoapp/backend/.git`と`todoapp/frontend/.git`のそれぞれのファイルを削除した後に`todoapp`の直下で`git init`を行うようにします。


```bash:todoapp
rm -rf backend/.git
rm -rf frontend/.git
git init
```

.gitignoreファイルに関してはプロジェクト内に複数存在していてもいい形になりますので特にいじらなくても問題ないかと思います。

こちらに詳しく書いてあります。

https://qiita.com/anqooqie/items/110957797b3d5280c44f


以上になります。

# 参考にした記事

https://zenn.dev/ryouzi/articles/de6000058a65fc

https://qiita.com/pon0204/items/ff00dff171e24d1c220e

https://qiita.com/taki_21/items/613f6a00bc432d1c221d