【挫折回避】Docker Composeを使ってWebアプリを5分でdocker化してみる(Rails×postgreSQL)

※この記事は「[Happiness Chain Advent Calendar 2023](https://adventar.org/calendars/9414)」11日目の記事です。<br>

## はじめに
この記事では、「Dockerとは」のような詳しい説明は省略し、とりあえず「WebアプリをDocker化する」という点のみにフォーカスし、その流れを簡潔に紹介しています。<br>

:::note warn
※私自身Dockerの学習を始めたばかりの者です。そのため、このあと記載している内容の中には、おかしな点、間違っている点があるかもしれません。もしそのような点に気付かれた方がいましたら、コメントで指摘していただけますと幸いです。<br>また、今後学習を経て本記事の内容を変更する可能性もあります。あらかじめご了承ください。
:::

## 対象の読者
- Dockerについて勉強を始めたばかりの人（イメージとコンテナぐらいは何となく理解している程度）
- 現場でDockerを使っているけど何が起こっているのか分からない人
- とりあえずWebアプリをDocker化して、Webアプリを作る学習に集中したい人（Dockerの学習は後回しにしたい人）

## 記事をお読みいただく前の注意点
この記事では、Dockerの仕組みや操作について詳しい説明はしていません。記事の中でイメージやコンテナなどのキーワードを使用していますが、そういったキーワードが何を意味するかも説明していません。そのため、この記事を読む前にDockerの基礎の基礎は学習していただいた方が良いかもしれません。<br>また、この後の記事前半で、docker化にあたって必要なファイルやコマンドについて少し解説し、その後の記事後半で、実際のdocker化の流れを紹介しています。docker化の部分はご自身で実際にやってみていただくと、早ければ5分程度で完了すると思いますが、実行される環境によっては上手く起動せず、エラーが発生する可能性もあります（現に私も色々試した上で上手くいった方法をご紹介しているに過ぎません）。あらゆる環境の動作を保証する内容ではない点はご了承ください。

## なぜこの記事を書いたのか？
Dockerって学習し始めると奥が深いし、環境構築をしたことがない人や、とりあえずWebアプリを作る学習を優先させたい人、環境構築の学習は後回しで良いという人にとって、Dockerの導入はかなりハードルの高いことだと思います。かくいう私も、現在進行形でDockerについて勉強している初学者で、まだまだ知らないこと、よく分からないことだらけです。<br>
ですが、Dockerの基礎教材を1周回してみた感想ですが、docker化するだけであれば必要な操作は少ないし、まずはとりあえずdocker化するという体験をしてみて、あとはその過程でエラーが発生したり、自分の環境に合わせてカスタマイズしたくなった場合に、都度調べて知識を補充し、トライ＆エラーの中でDockerと少しずつ仲良くなっていくのが良いのではないかなと感じました。<br>そうでないと、Dockerの学習初期の頃は、Dockerの仕組みや各種コマンドの説明だけで頭の中がパンパンになり、本題のdocker化というフェーズになかなか辿り着けず、挙げ句の果てにはDockerの学習を途中で挫折してしまうことになると思います。<br>
そうならないように、この記事では、Dockerについて詳しく説明することはせず、Webアプリをdocker化するにあたって必要最低限「あぁそうなんだ」ぐらいに知っておくべきことを説明した上で、実際にRailsとpostgreSQLを使用したアプリケーション環境を構築する流れを紹介したいと思います。<br>ここで紹介する流れ通りに進めて頂くことで簡単にDockerの開発環境が構築できるため、「現時点でDockerのことは詳しくないけど、とりあえずDockerを導入したい」という人にとって、参考になる内容なのではないかと思います。



## 記事のタイトルに入っている「Docker Compose」とは
Docker Composeとは、複数のDockerコンテナをまとめて管理するためのツールです。Docker Composeを使うことで、アプリケーションのコンテナとデータベースのコンテナをまとめて起動することができます。Webアプリの開発やデプロイを効率化することができるため、複数のコンテナを使った開発ではDocker Composeを利用するケースが多いかと思います。<br>なお、Docker Composeは通常、Dockerと一緒に提供されるツールで、Dockerをインストールすると同時にインストールされます。そのため、再度インストールする必要はありませんが、もしターミナルで下記コマンドを実行してみてDocker Composeのバージョンが表示されない場合は、Docker Composeをインストールしてください。

```shell
docker-compose -v
```

## docker化で必要なもの
Webアプリをdocker化するにあたり、必須のファイルとコマンドをご紹介します。

### 必要なファイル
docker化にあたり、必須となるファイルは以下の2つだけです。<br>

- Dockerfile
- docker-compose.yml

Dockerfileは、コンテナにインストールするソフトウェアや環境変数などを指定するファイルです。コンテナは、このDockerfileをもとにビルドされます。<br>docker-compose.ymlは、Docker Composeでコンテナを管理するためのファイルです。コンテナの定義や起動方法などを記述します。<br>なお、厳密にいえば、Webアプリを生成するにあたり他にも必要になるファイルはあります。ですが、それらは各フレームワークで必要になるだけで、Dockerとして必要なファイルは上の2ファイルだけです。

### 必要なコマンド
docker化にあたり、必須となるコマンドは以下の2つだけです。<br>

- docker-compose build
- docker-compose up

docker-compose buildは、docker-compose.ymlに定義されたサービスをビルドします。各サービスのDockerfileを使用してイメージを作成します。<br>docker-compose upは、ビルドされたイメージをもとにコンテナを起動します。これにより、定義されたサービスがコンテナ内で動作し、アプリケーションが利用可能になります。<br>なお、今回はバックグラウンドでコンテナを起動する-dオプションを付けたdocker-compose up -dコマンドを使用します。
<br>
以上が、Docker Composeを使ったWebアプリケーションのDocker化に必要なファイルやコマンドです。あとは、構築する条件に合わせて必要になるファイルやコマンドがあるぐらいなもので、Docker自体で必要になるものというのは実際のところかなり少ないです。<br>
この後、いよいよ実際にこれらのファイルとコマンドを使ってRails×postgreSQLの環境を構築してみます。


## 実践Rails×postgreSQL環境構築
### 0. ディレクトリ構成
今回構築するアプリケーションのディレクトリ構成は以下の通りです。まずは、myappディレクトリを作成し、そのプロジェクトディレクトリ直下にDockerfile・docker-compose.yml・Gemfile・Gemfile.lockの4つのファイルを配置します。<br>
GemfileとGemfile.lockは、RubyプロジェクトにおいてGemと呼ばれるライブラリやツールの依存関係を管理するためのファイルです。

```plaintext
myapp/
|-- Dockerfile
|-- docker-compose.yml
|-- Gemfile
|-- Gemfile.lock
```

### 1. 必要なファイルを作成する
各ファイルを作成し、必要な情報を記述していきます。

- Dockerfile

```Dockerfile:Dockerfile
FROM ruby:3.2.2
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /myapp
COPY Gemfile Gemfile.lock /myapp/
RUN bundle install
```

- docker-compose.yml

```yaml:docker-compose.yml
version: '3'

volumes:
  db-data:

services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - '.:/myapp'
    environment:
      - 'DATABASE_PASSWORD=postgres'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"

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

- Gemfile

```gemfile:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.0.6'
```

- Gemfile.lock
このファイルは空のままでOKです。

### 2. Railアプリの雛形を生成する
ターミナルでプロジェクトディレクトリに移動し、下記コマンドを実行します。<br>コマンドを実行すると、プロジェクトディレクトリ内にRailsアプリケーションのファイルが生成されます。

```shell
docker-compose run web rails new . --force --database=postgresql
```

### 3. ビルドする
下記コマンドでビルドします。

```shell
docker-compose build
```

### 4. config/database.ymlを修正する
Railsアプリケーションのconfig/database.ymlを開き、以下の該当箇所を探してコードを追加します。

```yaml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db #追加
  user: postgres #追加
  port: 5432 #追加
  password: <%= ENV.fetch("DATABASE_PASSWORD") %> #追加
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```

### 5. コンテナを起動する
下記コマンドで、アプリ用とデータベース用のコンテナをバックグラウンドで起動します。

```shell
docker-compose up -d
```

### 6. データベースを生成する
下記コマンドでデータベースを生成します。

```shell
docker-compose run web rails db:create
```

### 7. ブラウザでページを確認する
ブラウザで`http://localhost:3000`にアクセスして、Railsのデフォルトページが表示されたら成功です。


## おわりに
どうでしょう、多少なりともDockerのハードルを低く感じて頂けたでしょうか？実際のところ、多くの人にとってDockerを理解すること、Dockerを使いこなせるようになることは、決してハードルの低いことではないと感じます。少なくとも、私にとってはハードルの高いことです。今回ご紹介したRailsとpostgreSQL12の環境も、Dockerで構築出来るまでに何度もエラーが発生し、1日がかりの作業となりました。<br>
ですが、トライ＆エラーを繰り返しながら触れていってみると、だんだんとDockerが自分の方に近づいて来てくれているような気もします（気がするだけ？）。まずは触れてみる、触れるために最初のハードルを下げてみる。この記事の内容が、少しでもみなさんのDocker導入のハードルを下げることのお役に立てたら嬉しく思います。