Dockerを使ったRailsとNext.jsの開発環境の構築

### 自己紹介
初めまして、オーリーです。未経験からエンジニアへ転職活動中の者です。
先日、Next,js, Typescript、Rails(api)、Fargate, Terraform、Git Hub Actionsを使用したポートフォリオを作成しました。
その際に作成したDokerfile、docker-composeをアップします。
何分私も初学者ですので、もっと良い書き方があると思います。あくまでご参考までにー。

-----
### 概要
rails, next.jsの開発環境のDockerfileとdocker-compose.yml

-----
### ディレクトリ構成
app
├── backend
│   └── api
│       ├── Dockerfile.dev
│       └── entrypoint.sh
│
├── frontend
│   └── front
│       └── Dockerfile.dev
│  
└── docker-compose.dev.yml

- ディレクトリ構成:
.`app`ディレクトリの下には`backend/api`と`frontend/front`ディレクトリがあり、それぞれ配下にRails(api)とNext.jsを作成。
.`backend/api`にはRails用の`Dockerfile.dev`と`entrypoint.sh`を作成。
.`frontend/front`にはNext.js用の`Dockerfile.dev`を作成。

- 各ファイルの解説
. `backend/api/Dockerfile.dev`:
Railsアプリ(API)をビルドするDockerfile。
.`backend/api/entrypoint.sh`:
RailsアプリがDockerコンテナ内で実行される際に最初に実行されるスクリプトを記載。
. `frontend/front/Dockerfile.dev`:
Next.jsアプリをビルドするDockerfile。
.`docker-compose.dev.yml`:
Dockerコンテナの設定を管理。作成するサービスは`db`（MySQL）、`api`（Rails）、`front`（Next.js）の3つ。



-----
### Railsのdocker file

```dockerfile:backend/api/Dockerfile.dev
# ベースイメージとしてrubyのバージョン3.1.2を使用
FROM ruby:3.1.2

# nodejs、npm、vimをインストールし、必要ない一時ファイルを削除、yarnをグローバルにインストール
RUN apt-get update -qq \
  && apt-get install -y nodejs npm vim\
  && rm -rf /var/lib/apt/lists/* \
  && npm install --global yarn

# コンテナ内で作業するディレクトリ（フォルダ）を指定
WORKDIR /api-app

# ローカルのGemfileとGemfile.lockをコンテナ内の指定ディレクトリにコピー
COPY Gemfile /api-app/Gemfile
# ローカルのGemfile.lockをコンテナにコピーして、依存関係の一貫性を保証
COPY Gemfile.lock /api-app/Gemfile.lock

# Gemfileに記載された依存関係をインストール
RUN bundle install

# コンテナ起動時に実行するスクリプトをコンテナ内の/usr/bin/にコピー
COPY entrypoint.sh /usr/bin/
# コンテナ内のentrypoint.shスクリプトに実行権限を付与
RUN chmod +x /usr/bin/entrypoint.sh

# コンテナ起動時にentrypoint.shスクリプトを実行
ENTRYPOINT ["entrypoint.sh"]

# コンテナが起動するときに実行するデフォルトコマンドを設定（Railsサーバーを起動）
CMD ["rails", "server", "-b", "0.0.0.0"]
```
### 補足
- `apt-get update -qq`:
システムのパッケージリストを更新する。`-qq`は、ログ出力を最小限に抑えるオプション。
- `apt-get install -y nodejs npm vim`
`nodejs`（JavaScriptをサーバーサイドで実行するための環境）、`npm`（JavaScriptのパッケージ管理ツール）、`vim`（テキストエディタ）をインストールする。`-y`は、インストールの確認を求められた際に自動で「はい」と答えるオプション。
- `rm -rf /var/lib/apt/lists/*`:
インストールの際に使用した一時ファイルを削除し、イメージのサイズを小さくする。
- `npm install --global yarn`
`yarn`（別のJavaScriptのパッケージ管理ツール）をグローバルにインストールする。
- `WORKDIR /api-app`:
- コンテナ内での作業ディレクトリを`/api-app`に設定する。このディレクトリは後続の命令で使用される基準ディレクトリとなります。
-----
### entrypoint.sh
```sh:backend/api/entrypoint.sh
#!/bin/bash
# スクリプトを実行するシェルをbashとして指定

# エラーが発生した場合にスクリプトをすぐに停止させる
set -e

# Railsが生成するserver.pidファイルがあれば削除する
rm -f /api-app/tmp/pids/server.pid

# RailsのDockerfileのCMDで渡されたコマンドを実行
exec "$@"
```
### 補足
- #!/bin/bash`:
シェバン（shebang）。1行目に記載。bashを利用したシェルスクリプトであることを示しています。この行は、スクリプトを実行するために使用するシェルまたはインタプリタを指定します。ここでは`bash`シェルを指定しています。linuxカーネルはファイルの先頭に#!があれば、その後ろに書かれたコマンド（この場合は/bin/bash）を実行します。


-----
### Next.js
```dockerfile:frontend/front/Dockerfile.dev
# Node.jsのバージョン16を使用するAlpine Linuxベースのイメージを選択
FROM node:16-alpine

# コンテナ内の作業ディレクトリを/usr/src/frontに設定
WORKDIR /usr/src/front

# Next.jsのテレメトリ機能を無効化する環境変数を設定
ENV NEXT_TELEMETRY_DISABLED 1
```
### 補足
- ENV NEXT_TELEMETRY_DISABLED 1:
Next.js は、一般的な使用法に関する匿名のテレメトリデータを収集しています。テレメトリ機能を無効化すると、使用状況データの送信は行いません。

-----
### docker-compose.dev.yml
```yml:docker-compose.dev.yml
# docker-composeのバージョン指定
version: "3.8"

# コンテナの定義開始
services:
  db:
    # 使用するイメージを指定（MySQLのバージョン8.0）
    image: mysql:8.0
    # コンテナ名の設定
    container_name: mysql-ctr-dev
    # MySQLの認証方式を変更するためのコマンド
    command: --default-authentication-plugin=mysql_native_password
    # MySQLのデータを永続化するためのボリューム設定
    volumes:
      - db-data-dev:/var/lib/mysql
    # MySQLの環境変数設定（パスワード、ユーザー名など）
    environment:
      MYSQL_ROOT_PASSWORD: root_password_dev
      MYSQL_USER: user_dev
      MYSQL_PASSWORD: password_dev
      TZ: Asia/Tokyo
    # ホストのポート3306とコンテナのポート3306を紐づけ
    ports:
      - "3306:3306"

  api:
    # Dockerfile.devを使用してイメージをビルド
    build:
      context: ./backend/api/
      dockerfile: Dockerfile.dev
    # ビルドしたイメージの名前を指定
    image: rails-img-dev
    # コンテナ名の設定
    container_name: rails-ctr-dev
    # コード同期などのためのボリューム設定
    volumes:
      - ./backend/api:/api-app
      - public-data-dev:/api-app/public
      - tmp-data-dev:/api-app/tmp
      - log-data-dev:/api-app/log
    # Railsサーバーの起動コマンド
    command: bash -c "rm -f tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
    # ホストのポート3010とコンテナのポート3000を紐づけ
    ports:
      - "3010:3000"
    # dbサービスへの依存関係を定義
    depends_on:
      - db
    # コンテナの標準入力を開く
    stdin_open: true
    # コンテナにTTYを割り当て
    tty: true

  front:
    # Dockerfile.devを使用してイメージをビルド
    build:
      context: ./frontend/front
      dockerfile: Dockerfile.dev
    # ビルドしたイメージの名前を指定
    image: nextjs-img-dev
    # コンテナ名の設定
    container_name: nextjs-ctr-dev
    # フロントエンドのコード同期のためのボリューム設定
    volumes:
      - ./frontend/front:/usr/src/front
    # フロントエンドの起動コマンド
    command: "npm run dev"
    # ホストのポート3001とコンテナのポート3000を紐づけ
    ports:
      - "3001:3000"
    # apiサービスへの依存関係を定義
    depends_on:
      - api

# 名前付きボリュームの定義
volumes:
  public-data-dev:
  tmp-data-dev:
  log-data-dev:
  db-data-dev:
```

### 補足
dbサービス
- `container_name: mysql-ctr-dev`:
コンテナの名前をmysql-ctr-devに設定します。コンテナを特定しやすくします。
- `volumes`:
データの永続化に使用します。MySQLのデータを保存し、コンテナが削除されてもデータが残るようにします。

apiサービス
- `build`:
Dockerfileを使ってイメージをビルドします。`context`でDockerfileの場所を指定し、`dockerfile`で使用するDockerfileの名前を指定します。
- `volumes`:
コードの変更をリアルタイムで反映させるために、ホストマシンのディレクトリとコンテナ内のディレクトリを同期します。
- `ports`:
コンテナのポートをホストマシンのポートにマッピングし、外部からアクセスできるようにします。