Memo：Docker Compose

## 目次

- [環境変数](#環境変数)

    - [環境変数の展開](#環境変数の展開)
    - [コンテナ内環境変数の指定](#コンテナ内環境変数の指定)

- [プロフィール](#プロフィール)
    - [プロフィールをサービスに割り当てる](#プロフィールをサービスに割り当てる)
    - [プロフィール有効化](#プロフィール有効化)
    - [複数プロフィールの有効化](#複数プロフィールの有効化)
    - [プロフィールの自動有効化](#プロフィールの自動有効化)
- [設定の共有](#設定の共有)
    - [複数のComposeファイル](#複数のComposeファイル)
- [ネットワーク](#ネットワーク)
    - [コンテナからコンテナのアクセス](#コンテナからコンテナのアクセス)
    - [`links`キーワード](#linksキーワード)
    - [任意のネットワークを指定](#任意のネットワークを指定)
    - [アプリケーション全体のデフォルトネットワークを指定](#アプリケーション全体のデフォルトネットワークを指定b)
    - [既存ネットワークを使用](#既存ネットワークを使用)
    - [起動順、停止順の制御](#起動順、停止順の制御)

## 環境変数

### 環境変数の展開

bashと同じ形式で展開できる

```yml:docker-compose.yml
web:
  image: "webapp:${TAG}"
```

デフォルトでは`docker compose`実行時のカレントディレクトリ直下の`.env`ファイルが参照される

```sh:bash
$ echo TAG=1.0 > ./.env
```

```yml:docker-compose.yml
web:
  image: "webapp:${TAG}" # -> webapp:1.0
```

`--env-file`コマンドラインオプションで環境変数ファイルを指定できる
パスはカレントディレクトリからの相対パスになる

```sh:bash
$ docker compose --env-file ./config/.env.dev up 
```

### コンテナ内環境変数の指定

`environment`キーで指定

```yml:docker-compose.yml
web:
  environment:
      - DEBUG=1
```

シェル上の環境変数を参照する

```sh:bash
$ export DEBUG=1
```

```yml:docker-compose.yml
web:
  environment:
      - DEBUG # -> 1
```

環境変数ファイルを指定する：`env_file`キー
Dockerfileの`ARG`、`ENV` よりも優先される
ymlファイル内で環境変数が直接設定された場合はそちらが優先

```sh:bash
$ echo DEBU=1 > .env.dev
```

```yml:docker-compose.yml
web:
  env_file:
      - ./.env.dev
```
Composeが使う環境変数は`COMPOSE_`または`DOCKER_`から始まる
環境変数一覧：<https://docs.docker.com/compose/environment-variables/>

## プロフィール

### プロフィールをサービスに割り当てる

`profiles`キーで指定できる
正規表現も可能
以下の場合、プロフィールがfrontendに設定されていない場合は`backend`と`db`のみ起動する

:::note
メインとなるサービスは常時起動できるようにプロフィールを設定しないのが吉
:::

```yml:docker-compose.yml
version: "3.9"
services:
  frontend:
    image: frontend
    profiles: ["frontend"]

  phpmyadmin:
    image: phpmyadmin
    depends_on:
      - db
    profiles:
      - debug

  backend:
    image: backend

  db:
    image: mysql
```

### プロフィール有効化

コマンドラインオプションで設定する方法

```sh:bash
$ docker-compose --profile debug up
```

コマンド前に環境変数を設定する方法：`COMPOSE_PROFILES`環境変数

```sh:bash
$ COMPOSE_PROFILES=debug docker-compose up
```

### 複数プロフィールの有効化

```sh:bash
$ docker-compose --profile debug --profile frontend up
$ COMPOSE_PROFILES=debug,frontend docker-compose up
```

### プロフィールの自動有効化

`profiles`キーに設定されたプロフィールは`docker compose run`実行時に有効化される

```yml:docker-compose.yml
version: "3.9"
services:
  backend:
    image: backend

  db:
    image: mysql

  db-migrations:
    image: backend
    command: myapp migrate
    depends_on:
      - db
    profiles:
      - tools
```

```sh
# backend と db のみ起動
$ docker-compose up -d

# こちらは db-migrations を実行（必要となる db も起動）するにあたり、
# プロフィール `tools` を自動的に有効化
$ docker-compose run db-migrations
```

依存関係にあるサービスは自動有効化されないので、個別にプロフィールを有効化するか、依存対象と同一のプロフィールにする

## 設定の共有

### 複数のComposeファイル

基盤となる`docker-compose.yml`ファイルのほかに、`docker-compose.override.yml`に追加の設定を記述すれば、`docker compose up`実行時に自動で読み込まれる

```yml:docker-compose.yml
web:
  image: example/my_web_app:latest
  depends_on:
    - db
    - cache

db:
  image: postgres:latest

cache:
  image: redis:latest
``.

```yml:docker-compose.override.yml
web:
  build: .
  volumes:
    - '.:/code'
  ports:
    - 8883:80
  environment:
    DEBUG: 'true'

db:
  command: '-d'
  ports:
    - 5432:5432

cache:
  ports:
    - 6379:6379
```

明示的にファイルを指定する場合は`-f`オプション

```sh:bash
$ docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```

## ネットワーク

### コンテナからコンテナのアクセス

v2.1以上だとデフォルトで`attachable`であり、サービス名でコンテナにアクセスできない

`attachable`キーワードに`false`を設定すれば非有効化できる

### `links`キーワード

デフォルトの「サービス名=ホスト名」以外に別名を設定できる

以下の場合には`db`あるいは`database`でも接続できる

linksリファレンス：<https://docs.docker.jp/compose/compose-file/compose-file-v2.html#compose-file-links>

```yml:docker-compose.yml
version: "3.9"
services:

  web:
    build: .
    links:
      - "db:database"
  db:
    image: postgres
```

### 任意のネットワークを指定

`networks`キーを使う

以下の場合、`proyxy`サービスは`db`サービスから分離されるが、`app`サービスと`db`サービスはネットワークを共有している

networksキーリファレンス：<https://docs.docker.jp/compose/compose-file/compose-file-v2.html#network-configuration-reference>

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

services:
  proxy:
    build: ./proxy
    networks:
      - frontend
  app:
    build: ./app
    networks:
      - frontend
      - backend
  db:
    image: postgres
    networks:
      - backend

networks:
  frontend:
    # Use a custom driver
    driver: custom-driver-1
  backend:
    # Use a custom driver which takes special options
    driver: custom-driver-2
    driver_opts:
      foo: "1"
      bar: "2"
```

`name`キーワードで任意の名前も設定できる

```yml:docker-compose.yml
version: "3.9"
services:
  # ...
networks:
  frontend:
    name: custom_frontend
    driver: custom-driver-1
```

### アプリケーション全体のデフォルトネットワークを設定

`default`エントリに定義できる

```yml:docker-compose.yml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres

networks:
  default:
    # 任意のドライバを使う
    driver: custom-driver-1
```

### 既存ネットワークを使用

`external`オプションを使用

以下ではmy-pre-existing-networkという名前のネットワークを探す

```yml:docker-compose.yml
services:
  # ...
networks:
  default:
    name: my-pre-existing-network
    external: true
```

## 起動順、停止順の制御

`depends_on`キーで行う

あくまで起動順を制御するだけで準備が整うまでは待たないので、別途ラッパースクリプトなどを用意する

```yml:docker-compose.yml
version: "2"
services:
  web:
    build: .
    ports:
      - "80:8000"
    depends_on:
      - "db"
    command: ["./wait-for-postgres.sh", "db:5432", "--", "python", "app.py"]
  db:
    image: postgres
```

```shell:wait-for-postgres.sh
#!/bin/sh
# wait-for-postgres.sh

set -e

host="$1"
shift

until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"
exec "$@"
```