Ruby 3.x, Rails 7.x, PostgreSQL の Docker 環境構築 2023


## まえがき

以前、[Ruby 3.x, Rails 6.x, MySQL 8.x の Docker 環境構築。](https://qiita.com/goya-hideaki/items/2597b39b966cb37ec9e1) の記事を書いたときは Rails 6.x だったのですが、季節が流れ 7.x がめでたく出てしまったので新たに書き起こします。

実践で考えれば、本当に必要なのは 6.x を安全にアップデートする手順なのかもしれませんが、それはさておきます。

上述の記事が2021年02月26日投稿なので、その頃と比べると Docker の情勢や Windows/Mac の環境もかなり変わってしまったのですが、そういう細かい話題はすぐに廃れるのでそこも元気にスルーしていきましょう。

## 目標

Ubuntu 22.04.2 LTS on WSL2 で Docker を使用した Rails 環境立ち上げまでを行います。

[クィックスタート: Compose と Rails](https://docs.docker.jp/compose/rails.html) を参考にするため、今回の DB は PostgreSQL となります。

## 前提

Windows 10 に Docker がインストールされた Ubuntu 22.04.2 LTS on WSL2 が設定されている状況から始めます。

- Windows 10
    - Ubuntu 22.04.2 LTS on WSL2
    - Docker 20.10.22

また、Docker のサービスは起動しておいてください。

```shell
$ sudo service docker start
```

## 手順

### 1. 各種 Docker 設定ファイル準備
1. Dockerfile
1. compose.yaml
1. Gemfile
1. Gemfile.lock
1. entrypoint.sh

`myapp` フォルダを作成し、その中に上記５ファイルを作成します。構成と内容は以下の通りです。

```フォルダ構成
.myapp
├── Dockerfile
├── compose.yaml
├── entrypoint.sh
├── Gemfile
└── Gemfile.lock
```

#### 1.1. Dockerfile

```./Dockerfile
FROM ruby:3.2.1

RUN apt update -qq && apt install -y postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY 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"]

```

#### 1.2. compose.yaml

最近知ったのですが、`docker-compose.yml` のファイル名が非推奨になり、`compose.yaml` を推奨するように変わったようです。
そんな、拡張子まで変わって！

cf. [Compose Specification（仕様）](https://docs.docker.jp/compose/compose-file/index.html#compose-spec-compose-file)

```./compose.yaml
services:
  backend:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    networks:
      - back-tier
  frontend:
    build: .
    command: bash -c "bundle e rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3000:3000"
    depends_on:
      - backend
    volumes:
      - .:/myapp
    networks:
      - front-tier
      - back-tier

networks:
  front-tier: {}
  back-tier: {}

```

#### 1.3. entrypoint.sh

例の `server.pid` を削除するためだけのシェルです。

```./entrypoint.sh
#!/bin/bash
set -e

rm -f /myapp/tmp/pids/server.pid

exec "$@"

```

#### 1.4. Gemfile

Rails のバージョンは現時点での最新版 `7.0.4.2` にしておきます。
cf. https://rubyonrails.org/

```./Gemfile
source 'https://rubygems.org'
gem 'rails', '7.0.4.2'
```

#### 1.5. Gemfile.lock

Gemfile.lock は空ですので、`$ touch Gemfile.lock` で作成しましょう。

```./Gemfile.lock
```

### 2. プロジェクトのビルド

ここから作成したファイルを元に Rails のプロジェクトを作成していきます。
コマンドが `docker-compose` ではなく `docker compose` であることに注意してください。

#### 2.1. プロジェクトファイルの生成

まずは `rails new` で各種ファイルを生成し、`chown` で権限の変更を行ってから `build` します。

``` shell
$ docker compose run frontend rails new . --force --database=postgresql
$ sudo chown -R $USER:$USER .
$ docker compose build
```

#### 2.1. DB の設定

`config/database.yml` に `host`, `username`, `password` を追加します。

```./config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: backend
  username: postgres
  password: password
  pooling  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

# 以下略
```

``` shell
$ docker compose run frontend rails db:create
```

#### 2.2. Rails の起動と確認

`docker compose up` でサーバを起動してから Windows のブラウザで `http://localhost:3000/` または `http://127.0.0.1:3000/` にアクセスすると初期ページが表示されるはずです。

``` shell
$ docker compose up
```

WSL2 のコンソールログには `Listening on http://0.0.0.0:3000` と出ているかもしれませんが、`http://0.0.0.0:3000/` ではつながりません。

![なんか新しくなった Rails のトップページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1144449/9300be59-8cd7-dcbf-8ddb-ef1fbcc07b18.png)

## 以上！

Rails 7.x の立ち上げができました。
ね、簡単でしょう？　ここまでは。
WSL2 の場合、Rails のコマンドで生成されるファイル群の権限が軒並み `root` になるため、Windows/WSL での Rails 開発はここからが地獄になってしまいます。
ちなみに今回 Mac で対応しなかったのは手元の私物 MacBook が Catalina で止まってしまっており、現行の Docker Desktop から対象外とされてしまったためです。切ない。

### 余談

``` shell
$ docker compose run frontend rails g scaffold user name:string email:string
$ sudo chown -R $USER:$USER .
$ docker compose run frontend rails db:migrate
```

上記で User モデルを作成でき、`http://127.0.0.1:3000/users` から操作も行えるようになるはずです。
途中、権限周りなどでエラーになった場合は `docker compose stop` と `docker compose up` を行ったり `sudo chown -R $USER:$USER .` することで救われるかもしれません。

ブラウザからデータを登録後、`rails dbconsole` や `rails c` でデータを確認できます。
postgres のパスワードは `config/database.yml` に設定したもの（ここでは `password`）になります。

``` shell
$ docker compose run frontend rails dbconsole
[+] Running 1/0
 ⠿ Container myapp-backend-1  Running                                                                                                 0.0s
Password for user postgres:
psql (13.9 (Debian 13.9-0+deb11u1), server 15.1 (Debian 15.1-1.pgdg110+1))
WARNING: psql major version 13, server major version 15.
         Some psql features might not work.
Type "help" for help.

myapp_development=# select * from users;
 id | name |      email      |         created_at         |         updated_at
----+------+-----------------+----------------------------+----------------------------
  1 | test | aaa@example.com | 2023-xx-xx xx:xx:xx.798722 | 2023-xx-xx xx:xx:xx.798722
(1 row)

myapp_development=# quit
```

``` shell
$ docker compose run frontend rails c
[+] Running 1/0
 ⠿ Container myapp-backend-1  Running                                                                                                 0.0s
Loading development environment (Rails 7.0.4.2)
irb(main):001:0> u = User.first
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
=>
#<User:0x00007f693abf0ab8
...
irb(main):002:0> pp u.attributes
{"id"=>1,
 "name"=>"test",
 "email"=>"aaa@example.com",
 "created_at"=>Xxx, xx Xxx 2023 xx:xx:xx.798722000 UTC +00:00,
 "updated_at"=>Xxx, xx Xxx 2023 xx:xx:xx.798722000 UTC +00:00}
=>
{"id"=>1,
 "name"=>"test",
 "email"=>"aaa@example.com",
 "created_at"=>Xxx, xx Xxx 2023 xx:xx:xx.798722000 UTC +00:00,
 "updated_at"=>Xxx, xx Xxx 2023 xx:xx:xx.798722000 UTC +00:00}
irb(main):003:0> quit
```

今回は以上となります。

## 参考資料

以下の記事、情報を参考にさせていただきました。
ありがとうございます。

- [クィックスタート: Compose と Rails](https://docs.docker.jp/compose/rails.html)
- [Compose Specification（仕様）](https://docs.docker.jp/compose/compose-file/index.html#compose-spec-compose-file)