Rails7（esbuild + Tailwind + MySQL）をDocker Composeで環境構築してデバッグも行えるようにする

[株式会社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)からご連絡いただけますと幸いです。

# 前提

Rails7の環境構築でesbuild,Tailwind, MySQLでの構成の際に、Docker Composeで環境構築する際にハマったところなどをまとめておきました。
また、自分が書いた他の記事では、Dockerを使っている際に`pry-rails`、`pry-byebug`を使っている際にデバッグがおかしくなるため、`docker-compose.yml`を書き換えて`docker attach`でのデバッグが正常に行えるようにしました。

開発環境は以下の通りです。
- M1 Mac
- Ruby v3.2（RailsのDockerコンテナの中でのバージョン）
- Rails v7.0.5（RailsのDockerコンテナの中でのバージョン）
- Node v18.16.1（RailsのDockerコンテナの中でのバージョン）
- MySQL v8.0.32（MySQLコンテナの中でのバージョン）

# Docker Composeを実行する前に作成・変更が必要なファイル

## entrypoint.sh
以下の記述で作成します。

```sh: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
以下の記述で作成します。

```Dockerfile:Dockerfile
FROM ruby:3.2.0

RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs
RUN apt-get install -y default-mysql-client
RUN npm install -y --global yarn

WORKDIR /myapp
COPY . /myapp

RUN bundle install
RUN yarn install

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"]
```

## database.yaml
以下のように変更します。

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

development:
  <<: *default
  host: db #ここを追加
  database: instalike_development

test:
  <<: *default
  host: db #ここを追加
  database: instalike_test
```

## docker-compose.yml
以下の記述で作成します。

```yaml:docker-compose.yml
version: '3.8'
services:
  db:
    image: mysql:8.0.32
    command: --default-authentication-plugin=mysql_native_password
    container_name: db
    ports:
      - 4306:3306
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      TZ: Asia/Tokyo
    security_opt:
      - seccomp:unconfined
  app:
    tty: true
    stdin_open: true
    container_name: app
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
    command: bash -c "rm -rf tmp/pids/server.pid && rails server -b 0.0.0.0 -p 3000"
    environment:
      TZ: Asia/Tokyo
    depends_on:
      - db
    ports:
      - 3000:3000
  front-build:
    tty: true
    stdin_open: true
    container_name: front-build
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
    command: bash -c "yarn build --watch && yarn build:css --watch"
    environment:
      TZ: Asia/Tokyo
    depends_on:
      - db
volumes:
  db:
    driver: local
  bundle:
    driver: local
  node_modules:
    driver: local
  public-data:
  tmp-data:
```

### appのcommandについて
Railsサーバーを起動しています。

### front-buildのcommandについて
CSS・JSのビルドと変更の監視をしています。


### node_modulesについて
`yarn install`した際に`node_modules`を`volumes`に保存するようにします。
これをしないと、`docker compose up`の途中の`./bin/dev`の実行の際に以下のようなエラーが出てきます。

```bash:エラー文
app  | 12:42:23 js.1   | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=/assets --watch
app  | 12:42:23 css.1  | $ tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify --watch
app  | 12:42:23 js.1   | /bin/sh: 1: esbuild: not found
app  | 12:42:23 js.1   | error Command failed with exit code 127.
app  | 12:42:23 js.1   | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
app  | 12:42:23 css.1  | /bin/sh: 1: tailwindcss: not found
app  | 12:42:23 css.1  | error Command failed with exit code 127.
app  | 12:42:23 css.1  | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
app  | 12:42:24 js.1   | exited with code 127
app  | 12:42:24 system | sending SIGTERM to all processes
app  | 12:42:24 css.1  | exited with code 127
```

これは`node_modules`が保存されていないために、`yarn build --watch`の実行がエラーになってしまうためです。
そのため、`volumes`を使って`node_modules`を永続化させるようにします。

# Docker Composeの実行
必要なファイルが揃ったら、以下のコマンドを実行してDocker Composeでアプリケーションを起動させます。

```bash:ターミナル
docker compose build --no-cache
docker compose up -d

# 以下は別のタブで実行する。
docker compose run app rails db:create rails db:migrate
```

# Rails側のデバッグ
`gem "pry-byebug"`、もしくは、`gem "pry-rails"`をインストールして、処理を止めたい箇所に`binding.pry`を記述します。

```bash:ターミナル
doceker comopse up -d
docker attach app
```

を実行すれば処理が止まるようになります。