DockerでRails7 + Postgresqlを環境構築する

# はじめに
Dockerで環境構築するのは初学者にとってはめちゃくちゃ大変だと思います。（自分もかなり苦労しました)
なので今回は自分のメモも兼ねて初心者ながら、その方法について記載していきたいと思います。

# 実装
## ファイルを作成
まずは、プロジェクトを配置するフォルダを準備します。ここが Rails のルートフォルダになります。
今回は`sample-app`ディレクトリを作成し、その下にDockerの環境構築をしていこうと思います。
以下を順にターミナルで叩いてください。(コードエディタで直接作成しても大丈夫です)
```
mkdir sample-app
cd sample-app
touch Dockerfile Gemfile Gemfile.lock docker-compose.yml entrypoint.sh
```

## それぞれのファイルに記述
それでは、先ほど作成したファイルにコードを記述していきましょう。

### Dockerfile
```
FROM ruby:3.1.2

ENV TZ Asia/Tokyo
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# コンテナの作業ディレクトリを指定
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

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"]
```
Rubyのバージョンはローカル環境と合わせておいた方がエラーなく進めやすいと思います。以下が参考になるかと思います。
・https://k-koh.hatenablog.com/entry/2020/01/22/134227
・https://techtechmedia.com/fix-rbenv-version/
・https://zenn.dev/tmasuyama1114/articles/rbenv-switch-ruby-versions

### docker-compose.yml
```
version: '3'
services:
  db:                             #dbコンテナの設定について記述
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_volume:/var/lib/postgresql/data　　　　　　#/dataまでpathを指定しないとdbの永続化できない。永続化しないとdocker downするたびにdbを作成しないといけない。毎回するのは手間なのでここで永続化しておく。
    ports:
      - '3306:3306'
      
#rails側のコンテナの設定について記述。apiじゃなくて、webと記述している場合もあります。docker-compose exec(run)の後にはここで指定した名前を記述して、コマンドを叩いています。
  api:　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　
    build: .
    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
    stdin_open: true #dockerコンテナを起動したままにできる。コンテナ内に入ってコマンドを打ち込める
    tty: true          #コンテナを起動させたまま、bashで入れたりできる
    depends_on:
      - db
volumes:　　　　　　　　　　　　　　　　　　　　　　　　#永続化するvolumeの名前を指定してあげる
  postgres_volume:
```

### 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 "$@"
```

### Gemfile
```
source "https://rubygems.org"
gem "rails", "~> 7.0.4"
```
ここもローカルのrailsのバージョンと合わした方が後々エラーになりづらいです。

### Gemfile.lock
ここは何も記述しなくて大丈夫です。

## rails newする
これでrails　newする準備はできたので、ターミナルで叩いていきましょう。
sample-appディレクトリのままで、下記を実行します
```
docker-compose run api rails new . --force --database=postgresql
```
・`api`の部分は、docker-compose.ymlで記述した、`api:`の部分でこれがrails側のコンテナ名になります。
なので今後、`docker-compose run`や`docker-compose exec`などを叩く時は、その後に指定した名前を記述してください。
・`--api`をつけると、apiモードで作成できる
・--css=bootstrapなどとつけるとcssフレームワークも一緒に導入できる。他にもtailswind、bulma、postcss、sassも選べる。
・--database=postgresqlでdbを導入できる。他にもmysqlなどがある。

### config/database.ymlが作成されるので、以下を記述
rails newすると、sample-app以下にたくさんファイルが作成されると思います。
その中にconfig/database.ymlがあるので、以下を記述してください。
```
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password #これは、docker-compose.ymlで指定したパスワード
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %>
```

## ビルドしつつ、サーバーを起動
以下をターミナルで叩きます。
```
docker-compose up -d --build
```
下記でも大丈夫です。
```
docker-compose build
docker-compose up -d
```

## localhost:3000 にブラウザでアクセス
アクセスすると以下が表示されると思います。
![スクリーンショット 2023-03-06 9.51.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/b97c74f9-442b-048f-266a-56657e65ee5d.png)

これは、dbを作成してくださいということなので、`docker-compose exec api rails db:create`してください。
すると、いつものRailsの画面が表示されると思うので完成です。

# ポイント
もしかしたらエラーに躓いてsample-appディレクトリごと削除して、最初からやり直そうと思うことがあると思います。
そのまま実行すると色々とエラーが出ると思うので、やりなおそうとするのであれば以下を試してください。

## Dockerイメージの削除
イメージとは超絶ざっくりいうとdockerfileからbuildしたものです。
説明すると長くなっちゃうのでここは調べてみてください。

さて、削除方法ですが、`docker images`を叩くと以下が表示されます。
```
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
<none>                    <none>              77af4d6b9913        19 hours ago        1.089 GB
committ                   latest              b6fa739cedf5        19 hours ago        1.089 GB
<none>                    <none>              78a85c484f71        19 hours ago        1.089 GB
docker                    latest              30557a29d5ab        20 hours ago        1.089 GB
<none>                    <none>              5ed6274db6ce        24 hours ago        1.089 GB
postgres                  9                   746b819f315e        4 days ago          213.4 MB
postgres                  9.3                 746b819f315e        4 days ago          213.4 MB
postgres                  9.3.5               746b819f315e        4 days ago          213.4 MB
postgres                  latest              746b819f315e        4 days ago          213.4 MB
```
例えば、一番上の<none> を削除したい場合は、`docker rmi 77af4d6b9913`と叩くと削除されます。
今回の場合、sample-app_apiとかがおそらくあると思うので、それを削除してもらえればいいと思います。(なければすいません)
・https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae
この記事が参考になります。

## volumeの削除
ここも一応載せておきます。
volumeも削除しないとエラーに繋がると思いますし、不必要なものは消しておかないとPCが重くなります。イメージも同様。
・https://qiita.com/Ikumi/items/b319a12d7e2c9f7b904d
こちらが参考になります。

# 終わりに
少しわかりにくい部分もあると思うのですが、少しでも参考になれば嬉しいです。
私が参考にした記事は以下に載せおきます。

# 参考記事
[docker-compose + Rails 7 + Postgres の環境構築](https://zenn.dev/lirais/articles/fe240a0c248783#)
[Docker Compose で Rails 7/ruby 3.1.2 + PostgreSQL環境を作る](https://zenn.dev/hs7/articles/2cc4d67650ba69)
[Dockerイメージとコンテナの削除方法](https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae)
[Docker volumeの削除](https://qiita.com/Ikumi/items/b319a12d7e2c9f7b904d)
[docker-composeでpostgresのDBが永続化できていなかったのを直した](https://qiita.com/at_sushi/items/04a84193fb6c7076e86f)