Docker ComposeでRails+PostgreSQLの環境構築

docker-composeの勉強に，Railsの環境構築をやってみたのでハマったところも含めてメモ．
参考: [Quickstart: Compose and Rails](https://docs.docker.com/compose/rails/)

# 実行環境

- MacBook Pro (13-inch, 2019)
 - macOS Catalina version 10.15
- Docker version 19.03.5
- docker-compose version 1.24.1
- ruby 2.5.7
- Rails 5.2.4.1
- postgres (PostgreSQL) 12.2

# 構築手順

## Dockerfileの作成

参考ページそのままに，`Dockerfile`を作成．

```Dockerfile:Dockerfile
FROM ruby:2.5

RUN apt-get update -qq && apt-get install -y nodejs 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"]
```

## Gemfileの作成

同じく`Gemfile`を作成．

```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
```

## Gemfile.lockの作成

空の`Gemfile.lock`を作成．

```bash
$ touch Gemfile.lock
```

## entrypoint scriptの作成

`server.pid`が存在するとサーバの再起動が失敗するというRails特有の問題があり，それを修正するためのentrypoint scriptを作成．

```bash:entrypoint.sh
#!/bin/bash
set -e
                                
rm -f /myapp/tmp/pids/server.pid

exec "$@"
```

## docker-compose.ymlの作成

DBサーバとAPPサーバを立てるための`docker-compose.yml`を作成．拡張子は`yml`と`yaml`のどちらでも大丈夫．
なお，参考ページに沿った手順で進めていますが，以下の`docker-compose.yaml`はDBのパスワードの設定が不足しているため注意(後述)．

```yml:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    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"
    depends_on:
      - db
```

## Railsアプリの作成

以下のコマンドを実行し，Railsアプリのスケルトンを作成．

```bash
$ docker-compose run web rails new . --force --no-deps --database=postgresql
```

## DBの指定

Railsはデフォルトでlocalhost上で起動しているデータベースを探すので，dbコンテナを使うよう`config/database.yml`を以下の内容に置き換えます．
なお，先程の`docker-compose.yml`と同じく，DBのパスワードの設定が不足しています(後述)．

```yml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test
```

## コンテナの起動(失敗，修正)

準備ができたので，以下のコマンドでコンテナを立ち上げます．

```bash
$ docker-compose up
```

すると，以下のエラーが表示されてdbコンテナが落ちます(本来ならDBの接続待ちのメッセージが表示される)．

> db_1   | Error: Database is uninitialized and superuser password is not specified.
db_1   |        You must specify POSTGRES_PASSWORD to a non-empty value for the
db_1   |        superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
db_1   |
db_1   |        You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
db_1   |        connections without a password. This is *not* recommended.

postgresでパスワード無しでのログインが拒否されているため，`config/database.yml`にパスワードを追記．
さらに`docker-compose.yml`にもパスワードを追記．

```yml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: postgres # ここを追記
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test
```

```yml:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment: # ここから以下2行を追記
      POSTGRES_PASSWORD: postgres
  web:
    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"
    depends_on:
      - db
```

一旦落ちたdbコンテナも含めて削除し，再度`docker-compose up`を実行．

```bash
$ docker-compose stop
$ docker rm $(docker ps -aq)
$ docker-compose up
```

すると，今度はdbコンテナのログで`database system is ready to accept connections
`というメッセージが確認できます．

## データベースの作成

最後に，以下のコマンドでデータベースを作成します．

```bash
$ docker-compose run web rake db:create
Starting ror_db_1 ... done
Created database 'myapp_development'
Created database 'myapp_test'
```

## 完成

これで全ての設定が完了したので，`localhost:3000`にアクセスするとRailsの初期ページが表示されます．

<img width="1552" alt="スクリーンショット 2020-03-10 22.14.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592431/3aa03ce5-2230-5c0b-c3d0-e47b5fdd9554.png">