docker-composeで作る開発環境の構築例

自分の理解をまとめたメモです

# 環境
MacOS X

```
%uname -r
10.6.0
%docker -v; docker-compose --version; docker-machine --version
Docker version 17.06.0-ce, build 02c1d87
docker-compose version 1.14.0, build c7bdf9e
docker-machine version 0.12.0, build 45c69ad
```

# docker-composeとは

- [docker-compose](https://docs.docker.com/compose/)とは複数のコンテナ群とネットワークをまとめて定義できる．
- docker-composeを使うと依存関係も含めた構成管理が簡単．
- 1コマンドで開発環境が展開される

## 開発環境の例

`Jupyter` で `PostGIS` のデータを解析する構成．
外部向けにJupyterが `8888` で口を開けている．

```:データフロー
                   +---------------------------------------------+
                   |Docker                                       |
+--------+         |       +----------+          +-----------+   |
|        |   :8888 |  :8888|          |     :5432|           |   |
|  PC    +----------------->  Jupyter +---------->  PostGIS  |   |
|        |         |       |          |          |           |   |
+--------+         |       +----------+          +-----------+   |
                   |        jupyter-host          postgis-host   |
                   +---------------------------------------------+
```

## Docker-composeの構成ファイル

- [version3](https://docs.docker.com/compose/compose-file/) で書いた例

- `docker-compose up -d` でバックグラウンドで起動
- 構成情報はディレクトリ内の `docker-compose.yaml` を入力にする

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

services:
  jupyter_host:  # Docker内のホスト名
    container_name: jupyter # 起動するコンテナ名．指定するとスケール不可．
    image:  jupyter/datascience-notebook:latest
    ports:
      - "8888:8888" # 更改するポート <host port>:<container port>の順に記述
    depends_on:
      - postgis_host # コンテナが依存する別のコンテナ
    command: start-notebook.sh --NotebookApp.token='' # コンテナ起動時の引数
    networks:
      - front # コンテナが属するネットワークの名前．この場合は．<foldername>_front になる

  postgis_host:
    container_name: postgis
    image: mdillon/postgis:latest
    ports:
      - "5432:5432"
    networks:
      - front

networks:
    - front:
```

## 起動

起動したコンテナ情報が `container_name` の通りになっている．

```zsh:
% docker ps
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS              PORTS                    NAMES
aeaac41d8ae4        jupyter/datascience-notebook:latest   "tini -- start-not..."   2 minutes ago       Up 2 minutes        0.0.0.0:8888->8888/tcp   jupyter
8260dc0a5118        mdillon/postgis:latest                "docker-entrypoint..."   2 minutes ago       Up 2 minutes        0.0.0.0:5432->5432/tcp   postgis
```

## ネットワーク

ネットワーク `docker_front` がネットワーク種別 `bridge` で作られる．
`bridge` はMACアドレスで転送するネットワークのことを指す．

```
% docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
51ec4719d125        bridge              bridge              local
b5100cb01c8b        docker_front        bridge              local
b24b5c9dff85        host                host                local
534cd4e39f0c        none                null                local
```

`docker_front` を見ると， `container_name` で定義したホスト名がそれぞれ入っている．
2台のコンテナが属するサブネットとIPアドレス，コンテナIDと対応するホスト名を情報として持っている．

```
%docker network inspect docker_front
[
    {
        "Name": "docker_front",
        "Id": "b5100cb01c8bfb550848fcbc0672a0a841cda422acb2b3fb6746e3965146d5ae",
        "Created": "2017-07-19T14:40:12.814716329Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
...
        "ConfigOnly": false,
        "Containers": {
            "8260dc0a51181b3f0fe1b8f8f465414b44eb0fa9dbd57042d33cc69d2aa4547a": {
                "Name": "postgis",
                "EndpointID": "8846b328d88a37e915273158b9d3eeb4e2c70d84ce0e0267462b514b5edad169",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "aeaac41d8ae4311ecaa98d8ec7e458210a12183c8890bb57a347b2ce6d126c55": {
                "Name": "jupyter",
                "EndpointID": "4e6053617bed06fa4e5108993d3f1aa7c9b32e1f93f39d320579f27617e3716e",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "front",
            "com.docker.compose.project": "docker"
        }
    }
]
```

## ホスト名の解決

ホスト名は `/etc/hosts` で解決していない．

```
% docker exec postgis cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.18.0.2	8260dc0a5118
```

`127.0.0.11` のアドレスを持つDockerのDNSサーバで名前解決をしている．

```
% docker exec postgis cat /etc/resolv.conf
docker exec postgis cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
```

複数のサブネット間の通信を模擬した環境を作る場合，ルートにDNSを持たせて解決するアーキテクチャだと想定する．