docker compose override入門

docker compose overrideについて、概要と使用例を載せていく

リポジトリ：https://github.com/tkeshun/docker_compose_override

## docker compose overrideとは

複数のcomposeファイルをマージして、１つのcomposeファイルを作る方法。
- 参考
  - https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/
  - https://docs.docker.com/reference/compose-file/merge/

環境固有のものや、dev・stagging・production(docker-composeをプロダクション環境で使うことはありえないが)など設定をわけることができる。

デフォルトでは`compose.yml`、`compose.override.yml`の２つに分けられる
マージは`-f`オプションで行うことができる
マージ結果がみたいときは、`docker compose -f ファイル名 -f ファイル名 config`でみれる。
マージしたcomposeファイルで起動したい場合は`docker compose -f ファイル名 -f ファイル名 up`でOK。
ちなみに３ファイル以上でもマージできる。あとに指定したファイルで上書きされていく。
以下に例を示す。

### ２つのファイルをマージする

- compose.yml(マージされるファイル)

```yaml
$ cat compose.yml 
services:
  app:
    image: my-app:latest
    ports:
      - "3000:3000"
```

- compose.override.yml(マージするファイル)

```yaml
$ cat compose.override.yml 
services:
  app:
    environment:
      - NODE_ENV=development
    volumes:
      - ./src:/app/src
```

- マージ後(compose.ymlにcompose.override.ymlをマージする)

```yaml
$ docker compose -f compose.yml -f compose.override.yml config
name: docker_compose_override
services:
  app:
    environment:
      NODE_ENV: development
    image: my-app:latest
    networks:
      default: null
    ports:
      - mode: ingress
        target: 3000
        published: "3000"
        protocol: tcp
    volumes:
      - type: bind
        source: /home/shun/workspace/docker_compose_override/src
        target: /app/src
        bind:
          create_host_path: true
networks:
  default:
    name: docker_compose_override_default
```

※補足：書かれてないのに増えている項目は、マージによって生成されるものではなくデフォルト設定である。
通常は暗黙的に設定される項目が、configでyamlを出力するとみることができる。
そのため、以下のようにcompose.ymlだけ指定してconfigを出力してみると暗黙に設定される項目をみることができる。

```yaml
$ docker compose -f compose.yml config
name: docker_compose_override
services:
  app:
    image: my-app:latest
    networks:
      default: null
    ports:
      - mode: ingress
        target: 3000
        published: "3000"
        protocol: tcp
networks:
  default:
    name: docker_compose_override_default
```

`networks`以下が暗黙的にされる項目。

### マージルール

マージルールの一部を紹介

#### 同じキーを指定すると上書きされる

```yaml
$ cat value.yml 
services:
  app:
    image: my-app:1.0
```

```yaml
$ cat value.override.yml 
services:
  app:
    image: my-app:2.0
```

```yaml
$ docker compose -f value.yml -f value.override.yml config
name: example2
services:
  app:
    image: my-app:2.0
    networks:
      default: null
networks:
  default:
    name: example2_default
```

#### 同じキーの中で違うキーを指定するとマージされる

```yaml
$ cat onaji-key.yaml 
services:
  app:
    image: my-app:1.0
    environment:
      NODE_ENV: production
```

```yaml
$ cat onaji-key.override.yml 
services:
  app:
    environment:
      DEBUG: true
```

```yaml
$ docker compose -f onaji-key.yaml -f onaji-key.override.yml config
name: example3
services:
  app:
    environment:
      DEBUG: "true"
      NODE_ENV: production
    image: my-app:1.0
    networks:
      default: null
networks:
  default:
    name: example3_default
```

#### リストはマージされる

```yaml
$ cat list.yml 
services:
  app:
    image: my-app:1.0
    environment:
    - production
```

```yaml
$ cat list.override.yml 
services:
  app:
    environment:
    - dev
```

```yaml
$ docker compose -f list.yml -f list.override.yml config 
name: example4
services:
  app:
    environment:
      dev: null
      production: null
    image: my-app:1.0
    networks:
      default: null
networks:
  default:
    name: example4_default
```

#### あとのファイルでnullを指定すると値の削除ができる
 
```yaml
$ cat compose.yml 
services:
  app:
    image: my-app:1.0
    environment:
      - APP_ENV=production
      - DEBUG=true
```

```yaml
$ cat compose.override.yml 
services:
  app:
    environment:
      DEBUG: null
```

```yaml
$ docker compose -f compose.yml -f compose.override.yml config
name: poc-docer-override
services:
  app:
    environment:
      APP_ENV: production
    image: my-app:1.0
    networks:
      default: null
networks:
  default:
    name: poc-docer-override_default
```

## まとめ

composeファイルのオーバーライド、マージについてまとめた。
実用例でいうと、複数のDBを使う場合やバージョンによって初期化SQLなどが違う場合はイメージを固めておいて、compose.<version>.db.ymlなどにしてimageキーの値を上書きすると便利なのではないかと思う。
記事を見た人は是非活用してほしい。