【Docker Compose】compose.yaml で環境変数を利用する

# はじめに
この記事では、compose.yaml で環境変数を利用する方法について記載します。

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

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

# 環境変数に置き換える
以下の `compose.yaml` のポート番号とデータベース接続情報を `.env` ファイルを作成して、そちらに定義します。

```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:

```

`.env` ファイルを作成し、`app` / `db` / `mail` サービスのホストマシンのポート番号とデータベース接続情報を定義します、

```.env
APP_HOST_MACHINE_PORT=8000

DB_ROOT_PASSWORD=password
DB_USER=app
DB_PASSWORD=password
DB_DATABASE=sample
DB_HOST_MACHINE_PORT=3306

MAIL_HOST_MACHINE_PORT=8025

```

定義した環境変数を `compose.yaml` で `${VAR_NAME}` という形式で利用します。

```compose.yaml
services:
  app:
    ports:
      - "${APP_HOST_MACHINE_PORT}:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
    build: ./docker/app
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_DATABASE=${DB_DATABASE}
      - TZ=Asia/Tokyo
    ports:
      - "${DB_HOST_MACHINE_PORT}: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:
      - "${MAIL_HOST_MACHINE_PORT}:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
    image: axllent/mailpit:v1.18
volumes:
  db-compose-volume:
  mail-compose-volume:

```

`docker compose config` で指定した環境変数が設定されていることを確認できます。

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

```powershell
name: docker-mail-app
services:
  app:
    build:
      context: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\app
      dockerfile: Dockerfile
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8000
        published: "8000"
        protocol: tcp
    volumes:
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\src
        target: /my-work
  db:
    environment:
      MYSQL_DATABASE: sample
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: app
      TZ: Asia/Tokyo
    image: mysql:8.4.0
    networks:
      default: null
    ports:
      - mode: ingress
        target: 3306
        published: "3306"
        protocol: tcp
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\db\init
        target: /docker-entrypoint-initdb.d
  mail:
    environment:
      MP_DATABASE: /data/mailpit.db
      TZ: Asia/Tokyo
    image: axllent/mailpit:v1.18
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8025
        published: "8025"
        protocol: tcp
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
networks:
  default:
    name: docker-mail-app_default
volumes:
  db-compose-volume:
    name: docker-mail-app_db-compose-volume
  mail-compose-volume:
    name: docker-mail-app_mail-compose-volume
```

# 環境変数のデフォルト値と必須設定
ポートはデフォルト値を設定し、データーベース接続情報は必須設定にします。

- `${VAR_NAME:-default}` : `VAR_NAME` が未定義 or 空の場合、`default` とする
- `${VAR_NAME:?error}` : `VAR_NAME` が未定義 or 空の場合、`error` を含むメッセージを表示して終了

```compose.yaml
services:
  app:
    ports:
      - "${APP_HOST_MACHINE_PORT:-8000}:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
    build: ./docker/app
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:?review .env}
      - MYSQL_USER=${DB_USER:?review .env}
      - MYSQL_PASSWORD=${DB_PASSWORD:?review .env}
      - MYSQL_DATABASE=${DB_DATABASE:?review .env}
      - TZ=Asia/Tokyo
    ports:
      - "${DB_HOST_MACHINE_PORT:-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:
      - "${MAIL_HOST_MACHINE_PORT:-8025}:8025"
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
    image: axllent/mailpit:v1.18
volumes:
  db-compose-volume:
  mail-compose-volume:

```

試しに `.env` のポートの環境変数を全て削除して、`docker compose config` を実行します。

```powershell
docker compose config
```

デフォルト値として設定された値が表示されます。

```powershell
name: docker-mail-app
services:
  app:
    build:
      context: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\app
      dockerfile: Dockerfile
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8000
        published: "8000"
        protocol: tcp
    volumes:
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\src
        target: /my-work
  db:
    environment:
      MYSQL_DATABASE: sample
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: app
      TZ: Asia/Tokyo
    image: mysql:8.4.0
    networks:
      default: null
    ports:
      - mode: ingress
        target: 3306
        published: "3306"
        protocol: tcp
    volumes:
      - type: volume
        source: db-compose-volume
        target: /var/lib/mysql
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\db\init
        target: /docker-entrypoint-initdb.d
  mail:
    environment:
      MP_DATABASE: /data/mailpit.db
      TZ: Asia/Tokyo
    image: axllent/mailpit:v1.18
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8025
        published: "8025"
        protocol: tcp
    volumes:
      - type: volume
        source: mail-compose-volume
        target: /data
networks:
  default:
    name: docker-mail-app_default
volumes:
  db-compose-volume:
    name: docker-mail-app_db-compose-volume
  mail-compose-volume:
    name: docker-mail-app_mail-compose-volume
```

今度は `DB_ROOT_PASSWORD=password` を削除して確認してみます。

```powershell
docker compose config
```

`error` を含むメッセージが表示されます。

```powershell
error while interpolating services.db.environment.[]: required variable DB_ROOT_PASSWORD is missing a value: review .env
```

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