DockerでRuby on Railsの環境構築をする（M1Mac+Rails+MySQL+webpacker+sidekiq）

## はじめに

弊社ではローカルマシンにRails環境を構築して開発環境として使っていたのですが、機種ごとにCPUであったりOSの差異により、環境構築がすんなりいかないということが増えてきました。そこで、上記を解決するためにローカル環境をDockerで立ち上げるように変更しました。
なお今回本番およびステージング環境のDocker化は行っていないため、Macのローカルでのみ動かす前提となります。

## 環境

PC: mac（Apple M1）
OS: macOS Ventura 13.2.1
Ruby: 2.7.3
bundler:2.3.7
Rails: 6.1.4
node: 14.4.0

※nodeのバージョンが古いので、新規アプリケーションを作成する際は新しいバージョンに置き換えることをおすすめします。

## Dockerのメリット

Dockerを使用することで、以下のようなメリットがあります。

### 環境の再現性

Dockerを使用することで、Intel CPUとシリコン、M1とM2など環境の差異を気にせず、アプリケーションを実行する環境を簡単に再現することができます。

### 環境構築の簡素化

従来はPCの入れ替えや新規参画の際の環境構築で1日を費やしており、これに対しての課題感がありました。
一方、Dockerを使用すればDockerイメージをビルドするだけで、必要なライブラリやツールがすべて含まれたイメージを作成することができ、開発環境を簡単かつ迅速にセットアップすることができます。

## Docker Desktop
### インストール
まず、Docker DesktopをMacにインストールします。

1. [Dockerの公式ウェブサイト](https://www.docker.com/products/docker-desktop)にアクセスします。
2. 「Download Docker Desktop for Mac」をクリックします。
3. ダウンロードが完了したら、Docker.dmgファイルを開きます。
4. Docker.appをApplicationsフォルダにドラッグアンドドロップします。
5. Docker.appを起動します。
6. 「Open」ボタンをクリックして、Dockerがシステムに変更を加えることを許可します。
7. Dockerのログインページが表示されます。Dockerアカウントを持っている場合はログインし、そうでない場合はアカウントを作成してください。

以上で、Docker Desktopをインストールすることができます。

### gRPC FUSEからVirtioFSにファイル共有を変更する

Docker Desktopでは、ファイル共有機能がデフォルトでgRPC FUSEとなっていますが、最近のバージョンではVirtioFSをサポートしています。以下の手順に従って、VirtioFSにファイル共有を変更してみてください。
VirtioFSは、gRPC FUSEよりも高速で安定性も向上しているため、Dockerコンテナのファイル共有においてより高いパフォーマンスを発揮します。

1. 「設定アイコン」 => 「General」を開く
1. file sharingをgRPC FUSEからVirtioFSに変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139602/f0dcb163-12da-aff0-c0d9-6879f38d8188.png)
1. Apply & restart」をクリックして設定を反映する

## 定義ファイル作成

### Dockerfile

まずアプリケーションのルートディレクトリにDockerfileを作成し、以下のように編集します。
本番環境で利用する場合はDockerfile内でbundle installおよびyarn installを行いますが、今回はローカル環境での利用を想定しているため、イメージの軽量化のためDockerfile内では行わないこととしています。

```docker:Dockerfile
# Node.jsインストール用ビルドステージ
FROM node:14.4-slim AS nodejs

# メインビルドステージ（このステージの内容が最終的なイメージになる）
FROM ruby:2.7.3

# nodejsをインストールしたイメージからnodejsをコピーする
COPY --from=nodejs /usr/local/bin/node /usr/local/bin/
COPY --from=nodejs /opt/yarn* /opt/yarn/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn && \
  ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg

# アプリケーション起動用のユーザーを追加
RUN mkdir /app

# bundlerのインストール
RUN gem install bundler:2.3.7 && \
  bundle config set path /usr/local/bundle

WORKDIR /app

CMD ["bash"]

```

### docker-compose

Dockerfileと同じディレクトリに、以下のようにdocker-compose.ymlを作成してください

```yml:docker-compose.yml
version: '3'
volumes:
  node_modules:
  bundle:
  mysql:
services:
  mysql:
    container_name: mysql
    image: mysql:8.0
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_DATABASE: app_development ＃ 実際に使うDBの名前に読み替えてください
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      TZ: Asia/Tokyo
    volumes:
      - mysql:/var/lib/mysql
    ports:
      - 3306:3306
  redis:
    container_name: redis
    image: redis:5.0.6-alpine
  rails:
    &rails
    container_name: rails
    build:
      context: ./
      dockerfile: Dockerfile
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -b '0.0.0.0'"
    stdin_open: true
    tty: true
    volumes:
      - .:/app:delegated
      - node_modules:/app/node_modules:delegated
      - bundle:/usr/local/bundle:delegated
    depends_on:
      - mysql
      - redis
    environment:
      DATABASE_HOST: mysql
      REDIS_HOST: redis
      WEBPACKER_DEV_SERVER_HOST: webpacker
    ports:
      - 3000:3000
  webpacker:
    <<: *rails
    container_name: webpacker
    command: bundle exec bin/webpack-dev-server
    environment:
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
    ports:
      - 3035:3035
  sidekiq:
    <<: *rails
    container_name: sidekiq
    command: bundle exec sidekiq -C config/sidekiq.yml
    ports:
      - 6379:6379
```

### コマンド実行
以下は全てcodecampのルートディレクトリ（docker-composeが配置されているディレクトリ）で実行してください

```bash:bundle install & yarn install & schema 反映 & seed_fu
docker-compose run --rm rails bash -c 'bundle install -j4 && \
  yarn install && \
  bundle exec ridgepole -c config/database.yml --apply -f db/Schemafile && \
  bundle exec rake db:seed_fu'
```

弊社ではDBのmigrationを`ridgepole`を用いて行っていますがデフォルトのmigrateを使っている場合は以下としてください

```bash:bundle install & yarn install & schema 反映 & seed_fu
docker-compose run --rm rails bash -c 'bundle install -j4 && \
  yarn install && \
  bundle exec rails db:migrate && \
  bundle exec rake db:seed_fu'
```

以下のコマンドを使用して、Docker Composeを起動します。

```
docker-compose up -d --build
```

コンテナが正常に立ち上がり、http://localhost:3000 にアクセスできればOKです。

コンテナが正常に起動しているかはDocker Desktopで確認ができます
↓起動に失敗している例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139602/f0b0cb04-059f-3763-84e2-87585162f0b8.png)

↓正常に起動している例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139602/fcdb1f30-e7b5-ca57-16cd-1a38be7b5b8d.png)

## まとめ

この記事では、Macのローカル環境にあるDockerでRailsを動かす方法を説明しました。Dockerを使用することで、環境の再現性、環境構築の簡素化、隔離された環境などのメリットがあります。ぜひ、この記事を参考にして、Dockerを使ったRailsアプリケーション開発に挑戦してみてください。