Docker Composeでwebアプリ(Rails)をDocker化する方法

## 条件
* Docker未使用の環境で動作するRailsのwebアプリを用意する。
* RailsアプリはRubyのバージョン3.2.2、dbとしてpostgresのバージョン12を使用する。
* `docker-compose up`でRailsプロセスとdbが起動し、http://localhost:3000 でこのWebアプリでアクセスできるようにする。
* ホストのファイルシステムとコンテナのファイルシステムを同期させる。

## Docker化に向けた大まかな方針
* `docker-compose up`ですべての環境を構築できるようにするのが最終的なゴールになります。しかし、Dockerfileやdocker-compose.ymlに必要なコマンドを最初から網羅して記載することは難しいです。
* そこで、まずはWebアプリを起動するために最低限のDockerfileやdocker-compose.ymlを用意するのみにとどめ、立てたコンテナの中で必要なコマンドを模索する作業を行います。
* コンテナの中で環境構築に必要なコマンドを特定することができたら、Dockerfileやdocker-compose.ymlにコマンドを追記し環境構築の自動化を行います。

## Docker化の手順
### 1.コンテナを立てるための最低限のファイルの準備
* Railsアプリのためアプリケーション用とdb用のコンテナを使用します。複数コンテナを使うため、Dockerfileとdocker-compose.ymlを用意します。
* WebアプリのソースがGitHub等リモートのリポジトリで公開されている場合クローンしてきます。
* その後、土台となるDockerfileとdocker-compose.ymlを作成します。
* また、railsのdatabase.yml等に記述が不足している場合は必要な内容を追記します。

```Dockerfile:Dockerfile
# Rubyのバージョンは元のWebアプリのGemfileを参考にします。
FROM ruby:3.2.2
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /rails-docker
COPY Gemfile Gemfile.lock /rails-docker/
RUN bundle install
```

```yml:docker-compose.yml
version: '3.9'

volumes:
  db-data:

services:
  web:
    build: .
    # アプリケーション側のコンテナでは何かしらコマンドの入力が必要であると推測されます。
    # しかし、この段階では必要なコマンドが特定できないためcommandを入力しません。
    ports:
      - '3000:3000'
    volumes:
      - '.:/rails-docker'
    environment:
      - 'DATABASE_PASSWORD=postgres'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres:12
    volumes:
      - 'db-data:/var/lib/postgresql/data'
    environment:
      - 'POSTGRES_USER=postgres'
      - 'POSTGRES_PASSWORD=postgres'
```

### 2.コンテナを起動し、環境構築に必要なコマンドを特定する。
* `docker-compose up -d`をしたのち、`docker-compose exec web bash`をします。こうすることでwebという名称のアプリケーション側のコンテナの中のbashを起動できます。
* このステップでは、コンテナの中でrailsのアプリケーション起動を行い、http://localhost:3000 でWebアプリにアクセスできるようにします。**ここで入力したコマンドがそのまま環境構築に必要なコマンドになるため**、重要な作業になります。
* ここからはDockerの話というよりはRailsのアプリケーション起動に必要なコマンドの話となります。
  1. まず、`$ rails db:create`を入力してDBの作成を行います。
  2. その後、`$ rails db:migrate`を入力してmigrationファイルの内容をDBに反映します。
  3. 最後に、`rails s -b 0.0.0.0`を入力して、Railsサーバーを起動します。
* これらを入力した後、ブラウザ上でhttp://localhost:3000 を入力することでWebアプリにアクセス可能になります。

### 3.Webアプリの起動に必要なコマンドをdocker-compose.ymlに追記する
* Webアプリの起動が確認できたら、`docker-compose up`の1コマンドのみでサーバー起動までの環境構築を完了できるようにします。
* docker-compose.ymlのcommandに以下を追記します。今回のケースだと追記後のyamlファイルは以下になります。

```yml:docker-compose.yml
version: '3.9'

volumes:
  db-data:

services:
  web:
    build: .
    # コンテナの中で特定した環境構築用のコマンドをyamlファイルに追記します。
    command: >
      bash -c "rails db:create &&
              rails db:migrate &&
              rails s -b 0.0.0.0"
    ports:
      - '3000:3000'
    volumes:
      - '.:/rails-docker'
    environment:
      - 'DATABASE_PASSWORD=postgres'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres:12
    volumes:
      - 'db-data:/var/lib/postgresql/data'
    environment:
      - 'POSTGRES_USER=postgres'
      - 'POSTGRES_PASSWORD=postgres'
```

### 4.docker-compose upで動作確認
* 最後に`docker-compose up`を入力してRailsプロセスとdb起動まで完了するか確認いたします。エラーなくコンテナが起動し、http://localhost:3000 でWebアプリへアクセスできたらDocker化完了です！

:::note warn
※コンテナの中でコマンドを入力していた際には発生しなかったエラーが生じることもあります。その場合には、エラーを解消するためのコマンドをyamlファイルに追記しましょう。
:::

## さいごに
* 今回は構成がシンプルなRailsアプリのDocker化を行ったので、土台となるDockerfileとdocker-compose.ymlの準備も容易でした。
* しかし、複雑なアプリになると土台のDockerfileとdocker-compose.ymlを用意すること自体困難なことも想定されます。その場合は、Dockerfileから構築していく作業から行う必要があります。