Docker ComposeでRails + PostgreSQLの開発環境を構築する

## はじめに

本記事は、RailsプロジェクトにPostgreSQLを追加し、Docker Composeで開発環境を構築する手順について解説します。
Dockerを使うことでローカル環境に依存しない開発環境を用意することができ、チームでの共有にも役立ちます。
（手順はDocker公式サイトの[クィックスタート: Compose と Rails](https://docs.docker.jp/compose/rails.html)を参考にしました）

#### この記事でできること

- Docker Composeを使ってRails + PostgreSQL開発環境を構築
- `http://localhost:3000`でRailsアプリにアクセスできる
- ソースコードの変更をブラウザに即時反映させる

## バージョン情報と動作環境

バージョン情報
- Ruby: 3.2.2
- Rails: 7.0.6
- PostgreSQL: 12

動作環境
- MacBook Air
- チップ：Apple M3
- メモリ 16GB

## 準備

Dockerを使用するには、Docker Desktopを起動しておく必要があります。
初めて使用する方は、以下のリンクからインストールしてください。


https://www.docker.com/ja-jp/get-started/


## 手順

### 1. Railsプロジェクトのディレクトリへ移動する

ターミナルを開き、`cd`コマンドでRailsプロジェクトのディレクトリへ移動します。
```console:ターミナル
$ cd rails-docker
```
`ls`コマンドでディレクトリの中身を表示すると、以下のようになっています。
※ `Gemfile` と `Gemfile.lock` はRailsの使用ライブラリを定義したファイルです。プロジェクトに含まれていることを確認してください。
```console:ターミナル
$ ls
Gemfile		    Rakefile	config		lib		  storage	 vendor
Gemfile.lock	app		    config.ru	log		  test
README.md	    bin		    db		    public	  tmp
```


### 2. Dockerfileの作成

エディタを開き、`Dockerfile`を作成します。
以下のように記述します。

```Dockerfile:Dockerfile
FROM ruby:3.2.2
RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs
WORKDIR /myapp
COPY Gemfile Gemfile.lock /myapp
RUN bundle install
```



### 3. docker-compose.ymlの作成

続けて、`docker-compose.yml`ファイルを作成します。
以下のように記述します。

```yml:docker-compose.yml
services:
  db:
    image: postgres:12
    # PostgreSQLの初期ユーザー名とパスワードを設定する（これが無いとエラーになる）
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
  web:
    build: .
    # docker-compose up実行時にDBを起動しブラウザにアクセスできるようにする
    command: >
      bash -c "
        bundle exec rails db:prepare &&
        bundle exec rails s -p 3000 -b '0.0.0.0'
      "
    # webからdbへ接続するためにdbと同じ値を環境変数に設定する（database.ymlに対応）
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    # ホストのカレントディレクトリをコンテナの/myappディレクトリにマウントする
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    # dbの起動後にwebを起動する
    depends_on:
      - db
```
### 4. database.ymlの修正

データベース（PostgreSQL）との接続設定を行います。
`config`ディレクトリ内の`database.yml`を以下のように書き換えます。
```yml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5
  
  development:
  <<: *default
  database: myapp_development
  
  test:
  <<: *default
  database: myapp_test
  
  # 以下はコメントアウトする
  # production:
  #   <<: *default
  #   database: myapp_production
  #   username: myapp
  #   password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %>
```

### 5. アプリの起動とブラウザ表示

ファイルの設定が完了したので、以下のコマンドでアプリを起動します。
```console:ターミナル
$ docker-compose up
```
`docker-compose up`の実行により、次の処理が自動で行われます。
- Dockerイメージをビルドする（初回のみ）
- db（PostgreSQL）のコンテナを作成・起動する
- web（Rails）のコンテナを作成・起動する
- Railsのコマンド（`rails db:prepare`, `rails s`）を実行し、アプリが起動する（ブラウザで`http://localhost:3000`にアクセスできるようになる）

<br>

起動が成功すると、ターミナルがログ出力中の状態になります。
![96373445-9236-4FD1-A0FF-3EE4D77C6B7C.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075222/47edb155-ccd4-4e98-9fb3-4c45ebae7e67.jpeg)


ブラウザで`http://localhost:3000`にアクセスすると、アプリを表示することができました。

![C23BE0F5-0DFA-40A6-85EE-E5C9A8B6E05B.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075222/60657bde-0d3d-4e66-91f1-80f1c65208dd.jpeg)

ホストとコンテナ間でファイルシステムを同期（マウント）しているため、ソースコードの変更がリアルタイムでブラウザに反映されることを確認できます。

ソースコード
![4C5CEB8A-611F-4A5E-92F0-7CAC213570D5_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075222/35d528aa-b069-4888-bcf2-881c323d2091.jpeg)

ブラウザ（再読み込みをする）
![DFDA55C8-723B-404D-AB2C-4074B7C869F2_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075222/d51baf55-9c46-4eb7-9eb0-8b60d8eccb0e.jpeg)

### 5. アプリの停止と削除

`Ctrl+C`でアプリを停止することができます。
以下のコマンドを実行すると、コンテナや関連するネットワークが削除され、環境がクリーンな状態に戻ります。


```console:ターミナル
$ docker-compose down
```
再度アプリを起動するには`docker-compose up`を実行します。

<br>


## 参考

https://docs.docker.jp/compose/rails.html

https://zenn.dev/hs7/articles/2cc4d67650ba69

https://sleepless-se.net/2018/06/02/dockercomposecommand%E3%82%92%E8%A4%87%E6%95%B0%E8%A1%8C%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/