Docker Compose を使って App / DB / Mail コンテナの開発環境を構築する

# はじめに
この記事では、Docker Compose を使った App / DB / Mail コンテナの開発環境の構築手順について記載します。

https://docs.docker.com/compose/

以下の記事では、 Docker Compose を使わずに構築する手順を記載しています。
また、構築する開発環境の要件や各種リソース情報もこちらの記事に記載があります。

https://qiita.com/Yasushi-Mo/items/6a4d1af9c7cdb3c68ce1

# 開発環境
開発環境は以下の通りです。

- Windows 11
- Docker Engine 26.1.1
- Docker Compose 2
- PHP 8.3
- MySQL 8.4.0
- Mailpit 1.18

# compose.yaml を作成する

## ファイルを作成する
まずはプロジェクト直下に `compose.yaml` を作成します。

```powershell
├─compose.yaml
├─docker
│  ├─app
│  ├─db
│  └─mail
└─src
```

## サービスを定義する
Docker Compose では、コンテナ1つずつをサービスとして扱います。
まず `services` というプロパティを定義します。その下に3つのコンテナ分のサービスを定義します。

```compose.yaml
services:
  app:
  db:
  mail:
```

この先、次はボリュームを定義しますが、それ以降は今回定義した3つのサービスの先に `docker container run` のオプションを定義していきます。

:::note
ネットワークの定義は不要です。デフォルトで Docker Compose はコンテナ起動時にブリッジネットワークを作成し、全てのコンテナを作成したネットワークに接続します。コンテナはサービス名で相互に通信できます。
:::

:::note
`docker container run` で利用していた以下のオプションの追加は不要です。

- `--name` : サービス名で代替できるため
- `--rm` : `docker compose down` でコンテナを停止すると、自動で削除されるため
- `--detach` : `compose.yaml` で利用できないため（`docker compose up` のオプションで利用する）
- `--network` : 前述の通りデフォルトでネットワークに接続されるため

:::

## ボリュームの定義
オプションを追加する前にボリュームを定義しておきます。

```compose.yaml
services:
  app:
  db:
  mail:
volumes:
  db-compose-volume:
  mail-compose-volume:
```

## 環境変数
`db` と `mail` に環境変数を定義します。

```compose.yaml
services:
  app:
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
volumes:
  db-compose-volume:
  mail-compose-volume:
  
```

## ポートの公開

```powershell
services:
  app:
    ports:
      - "8000:8000"
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
    ports:
      - "3306:3306"
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
    ports:
      - "8025:8025"
volumes:
  db-compose-volume:
  mail-compose-volume:
  
```

## ボリュームのマウント
`db` と `mail` にボリュームのマウントを定義します。

```powershell
services:
  app:
    ports:
     - "8000:8000"
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
    ports:
      - "3306:3306"
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
    ports:
      - "8025:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
volumes:
  db-compose-volume:
  mail-compose-volume:

```

## バインドマウント
`app` と `db` にバインドマウントを定義します。

```compose.yaml
services:
  app:
    ports:
      - "8000:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
    ports:
      - "3306:3306"
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init
        target: /docker-entrypoint-initdb.d
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
    ports:
      - "8025:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
volumes:
  db-compose-volume:
  mail-compose-volume:

```

:::note
相対パスは `.` で書き始めます。
:::

## 利用イメージ
`db` と `mail` に利用イメージを定義します。

```compose.yaml
services:
  app:
    ports:
      - "8000:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
    ports:
      - "3306:3306"
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init
        target: /docker-entrypoint-initdb.d
    image: mysql:8.4.0
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
    ports:
      - "8025:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
    image: axllent/mailpit:v1.18
volumes:
  db-compose-volume:
  mail-compose-volume:

```

## イメージビルド
`app` はベースイメージをそのまま使わず Dockerfile からイメージをビルドします。
そのため、`build` プロパティの値に Dockerfile のパスを渡し、イメージビルドを定義します。

```compose.yaml
services:
  app:
    ports:
      - "8000:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
    build: ./docker/app
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=app
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=sample
      - TZ=Asia/Tokyo
    ports:
      - "3306:3306"
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init
        target: /docker-entrypoint-initdb.d
    image: mysql:8.4.0
  mail:
    environment:
      - TZ=Asia/Tokyo
      - MP_DATABASE=/data/mailpit.db
    ports:
      - "8025:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
    image: axllent/mailpit:v1.18
volumes:
  db-compose-volume:
  mail-compose-volume:

```

これで `compose.yaml` は完成です。

# Docker Compose の操作
`compose.yaml` が完成したので、Docker Compose のコマンドを利用して、コンテナの動作を確認します。

## コンテナの作成と起動 `docker compose up`

https://docs.docker.com/reference/cli/docker/compose/up/

```powershell
docker compose up --detach --build
```

- `--detach` : バックグラウンドで実行
- `--build` : コンテナを起動する前にイメージをビルド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/57cbdaaa-06ec-711a-0e5e-5fc64bdeb420.png)


ブラウザで動作確認をします。

App コンテナ（ http://localhost:8000/ ）にアクセスすると、以下の画面が表示されます。
ユーザー一覧と各ユーザーにメールを送信したことが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/ea6c37f3-028e-db2b-e3a5-0cf8defe9daa.png)

Mail コンテナ（ http://localhost:8025/ ）にアクセスすると、以下の画面が表示されます。
2通のメールが確認できます。また、メールのタイトル、本文ともに実装通りの文言になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/226b2e13-2584-165b-6936-bc3e162ba900.png)

## コンテナ一覧の確認

https://docs.docker.com/reference/cli/docker/compose/ps/

```powershell
docker container ps
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/1e90d7f3-8587-0b24-98bb-3e5a7d8299d3.png)

:::note
起動したコンテナは `docker container ls` でも確認できます。

```powershell
docker container ls
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/2e9e186f-2ee9-45fc-d36f-b78a41a423cd.png)

:::

## 起動中のコンテナでコマンドを実行 `docker compose exec`

https://docs.docker.com/reference/cli/docker/compose/exec/

```powershell
docker compose exec app bash
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/bd460424-a320-65ae-1f83-2742ea6d442e.png)

:::note
`docker compose exec` はデフォルトで `--interactive` と `--tty` オプションが有効になっているため、対話操作時、これらのオプションの指定は不要です。
:::

## コンテナの停止と削除 `docker compose down`

https://docs.docker.com/reference/cli/docker/compose/down/

```powershell
docker compose down
```

コンテナとネットワークが削除されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/0fad8222-189a-89ac-d38e-a07551b90ac9.png)

:::note
オプションを追加すると、イメージとボリュームも削除されます。

```powershell
docker compose down --rmi all --volumes
```

- `--rmi all` : イメージの削除
- `--volumes` : ボリュームの削除

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/c62f51f0-f7a3-4f48-df35-d81691371c6c.png)

:::

# 参考
- [docker compose exec](https://docs.docker.com/reference/cli/docker/compose/exec/)
- [docker compose down](https://docs.docker.com/reference/cli/docker/compose/down/)
- [docker compose ps](https://docs.docker.com/reference/cli/docker/compose/ps/)
- [Docker Compose Quickstart](https://docs.docker.com/compose/gettingstarted/)
- [docker compose up](https://docs.docker.com/reference/cli/docker/compose/up/)
- [	鈴木亮「開発系エンジニアのためのDocker絵とき入門」秀和システム、2024](https://www.shuwasystem.co.jp/book/9784798071503.html)

# 関連URL

https://github.com/yasushi-mo/docker-mail-app/tree/main

https://qiita.com/Yasushi-Mo/items/6a4d1af9c7cdb3c68ce1