DockerでRails7.1.2×PostgreSQLの環境構築

# はじめに
今回は初めてDockerを使って環境構築してみたので、そのまとめを残していきたいと思います。

https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails

こちらのリポジトリを参考に
- Ruby: 3.3.0
- Rails: 7.1.2
- wsl2
- Docker Desktopインストール済み
- composeでsecretsを使う

で環境構築しました。

# 環境構築のステップ
まずはファイルを6つ用意します。
- Dockerfile.dev
- compose.yaml
- Gemfile
- Gemfile.lock
- entrypoint.sh
- db_password

それぞれ中身を見ていきましょう。
まずは`Dockerfile.dev`から、名前はなんでもいいのですが、Rails7.1以降の仕様から.devをつけています。
```Dockerfile:Dockerfile.dev
# syntax=docker/dockerfile:1
FROM ruby:3.3.0
RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /myapp

COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN bundle install

container starts.
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"]
```

特に解説することはありません。サンプルをほぼそのまま使っています。
次に、compose.yamlです。
ファイル名は`docker-compose.yml`とか`docker-compose.yaml`とかでもいいのですが、こちらの`compose.yaml`が推奨とのことなので、こちらを採用しました。

```yaml:compose.yaml
version: '3'

services:
  db:
    image: postgres
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: /run/secrets/db_password
    secrets:
      - db_password

  web:
    build: 
      context: .
      dockerfile: Dockerfile.dev
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      POSTGRES_PASSWORD: /run/secrets/db_password
    secrets:
      - db_password

volumes:
  db-data:

secrets:
  db_password:
    file: db_password
```
公式ドキュメントでパスワードなどはsecrersを使うのが良いと書いてあったので、使ってみました。
変更点は`secrets`と`volumes`、それからbuildするDockerfileを`Dockerfile.dev`にしました。

次は`Gemfile`です。
```Gemfile:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>7.1.2'
```
バージョンを最新のものにしました。
「なんとなく1番新しいのがいいやろ」と思ってこのバージョンにしましたが、これのせいでとても苦労しました。

次の`Gemfile.lock`は空です。
次に`entrypoint.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 "$@"
```
こちらも丸パクリです。
最後に`db_password`です。
```:db_password
password
```
中身はなんでもいいです。


それでは用意ができたら早速やっていきましょう！
まずは`rails new`をしていきましょう。
```bash
docker compose run --no-deps web rails new . --force --database=postgresql --skip-bundle
```
再ビルドするので`--skip-bundle`しときましょう。
次にビルドするのですが、ここでかなり苦戦しました。
普通に`Dockerfile`で進めているとここでエラーを吐きまくります。
自分は6時間ぐらいここでエラーと格闘しました笑

原因はRails7.1からの仕様でした。
>2.1 新規RailsアプリケーションでDockerfileが生成されるようになった
>新規Railsアプリケーションでは、デフォルトでDockerがサポートされるようになりました（#46762）。 新しいアプリケーションを生成すると、そのアプリケーションにDocker関連ファイルも含まれます。
>これらのファイルは、RailsアプリケーションをDockerでproduction環境にデプロイするための基本的なセットアップとして提供されます。重要なのは、これらのファイルは開発用ではないことです。

>開発用ではないことです。

>開発用ではないことです。

開発用ではないんですよ！！
そりゃあエラー吐きまくるわ

ちなみに`rails new`の時に`--skip-docker`でDockerfileと.dockerignoreが作られなくなるので、こちらでもOKです。
私もせっかくなので、Dockerfileをつくってもらいました。
一応ここで作られたDockerfileは`Dockerfile.prod`にリネームしておきました。

新しい`Gemfile`が作られたのでイメージを再ビルドする必要があります。
```bash
docker compose build
```

次に`config/database.yml`に変更を加えます。
```diff_yaml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
+ host: db
+ username: postgres
+ password: <%= ENV.fetch("POSTGRES_PASSWORD") %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
上記の3つを追加します。

これでPostgreSQLが起動できます。

```bash
docker compose up
```

最後にdbを作成しましょう。
別のターミナルで

```bash
docker compose run web rake db:create
```

`http://localhost:3000`にアクセス


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575564/5790fdfd-ab0e-9891-0c23-b359e8314834.png)


お疲れさまでした。


# トラブルシューティング
私の環境だけかもしれませんが、よく
```bash
 => ERROR [web] resolve image config for docker.io/docker/dockerfile:1                                             0.7s
------
 > [web] resolve image config for docker.io/docker/dockerfile:1:
------
failed to solve: error getting credentials - err: exit status 1, out: ``
```
このようなエラーがでていました。
このエラーが出たときは別のタブで`wsl --shutdown`でwsl2をシャットダウンしてから再起動すると解決しました。同じようなエラーがでる方はよかったら試してみてください。

# まとめ
Docker Composeを用いてRails7.1.2の環境構築をしてみましたが、かなり迷走しました。しかし、Dockerについての知識は深まったので良かったです。迷走したおかげで色々便利そうなリポジトリやVScodeの拡張機能とかがしれて逆に良かったです笑
Rails以外の環境構築がしたいかたはこちらのリポジトリを参考にしてください。

https://github.com/docker/awesome-compose?tab=readme-ov-file



# 参考文献
[Docker公式ドキュメント](https://docs.docker.com/)
- 結局一番参考になるのは公式ドキュメントでした。

[Ruby on Rails 7.1 リリースノート](https://railsguides.jp/v7.1/7_1_release_notes.html)
- 答えは全てここに載っていました笑