Docker ComposeでRails環境を構築

初学者の方向けに発信されているきよとのプログラミング大学のチャンネルで、Docker Composeを使ったRails環境構築の動画を見つけ、これが非常に分かりやすかったので、備忘録として記事にまとめたいと思います。

DockerでRails環境をつくりたいという方はこの動画を見ればOKだと思います。
https://youtu.be/ltDdZAJli8c

## Docker Composeとは
複数のアプリケーションをまとめて操作できるツール。例えばRailsでアプリケーションを開発する際、最低限Webサーバーとデータベースサーバーが必要になるが、通常それぞれのサーバーを構築し、接続するなどの操作が必要となる。docker-composeではコマンド一発でそれらを立ち上げて接続することができるため、非常に楽に開発環境を構築することができる。

## 全体の流れ
- Docker関連のファイルを用意
- 初期設定
- 起動
- よく使うコマンド

## Docker関連のファイルを用意
### ① Dockerfile
ここにrailsのイメージを作成する記述を行う。

```dockerfile:Dockerfile

# ベースイメージを指定
FROM ruby:2.7

# nodejsとyarnをインストールするため、JavaScript関連のライブラリをインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  # nodejsとyarnをインストール
  && apt-get update -qq \
  && apt-get install -y nodejs yarn
# 作業ディレクトリを指定
WORKDIR /app
COPY ./src /app
# Ruby関連のライブラリ(gem)のインストール
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install
```
※ APIモードで開発をする場合、nodejsとyarnは不要

### ② Gemfile
次にGemfileを用意します。

```ruby:Gemfile
source 'https://rubygems.org'

gem 'rails', '~> 6.1.0'
```
上記のように、<code>rails</code>のライブラリが入った状態で<code>rails new</code>を実行すると、railsのファイルの雛形を一斉に作ることができる。その際、Gemfileが新しく作成され、それと置き換わる形となる。

### ③ docker-compose.yml
最後にdocker-compose.ymlを用意します。

```yml:docker-compose.yml
ersion: '3'
services:
  db:
    image: mysql:8.0
    # mysql8.0から認証形式が変更になっていて、それを5系の認証形式に戻す設定。これをしないとエラーになる
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - ./src/db/mysql-data:/var/lib/mysql
    # 環境変数の設定
    # MySQLはパスワードを設定しないとエラーになる
    environment:
      MYSQL_ROOT_PASSWORD: password
  web:
    build: .
    # 標準入出力を有効にする設定
    # これをしないとデバックができない
    tty: true
    stdin_open: true
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./src:/app
      # gemを入れた際に、buildし直さなくても良くする設定
      - bundle:/usr/local/bundle
    ports:
      - "3000:3000"
    # railsからMySQLへ接続する際、接続情報としてdbサービスのIPアドレスを指定する必要がある。その接続先のIPアドレスをdbで接続できるようにする設定
    depends_on:
      - db
volumes:
  bundle:
    driver: local
```

開発をしていると、<code>A server is already running. Check /app/tmp/pids/server.pid.</code>のエラーでハマることがある。これは、サーバーが実行中か否かをserver.pidの有無で判断しており、何らかの理由でサーバーが実行していないがserver.pidファイルが残った状態となったときに起こる。これを防ぐため、起動時にはserver.pidの削除を行う。

```yml
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
```

## 初期設定
ファイルが用意できたらrails newコマンドを実行する。

```terminal
$ docker-compose run web rails new . --force --database=mysql
```
Gemfileが変更されたため、イメージの再ビルド

```terminal
$ docker-compose build
```
config/database.ymlを参照し、データベースへの接続先情報を修正する。

```yml:database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  # docker-compose.ymlで設定したパスワードを入力
  password: password
  # docker-compose.ymlのdepends_onで設定した値を入力
  host: db
  # 以下略
```

## 起動

```
$ docker-compose run --rm web rails db:create
$ docker-compose up -d
```
ブラウザでlocalhost:3000へアクセスし、下画面が表示されれば成功！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583698/c781d050-9247-3302-2e93-6c62327b182e.png)

## よく使うコマンド
- イメージのビルド

```
$ docker-compose build
```
- コンテナの作成と起動

```
$ docker-compose up -d
```
- コンテナを停止、削除

```
$ docker-compose down
```
- コンテナの一覧を表示

```
$ docker-compose ps
```
- ログを表示

```
docker-compose logs
```
- コンテナを作成してコマンドを実行

```
$ docker-compose run <サービス> <コマンド>
```
- 起動中のコンテナにコマンド実行

```
$ docker-compose exec <サービス> <コマンド>
```