docker-compose から docker network を少しだけ理解したい

## docker-compose での疑問
docker公式っぽいやつの docker-compose の例 : https://docs.docker.com/compose/gettingstarted/

ここでの`app.py`の`redis`の`host`が以下のように指定されています。

```py

cache = redis.Redis(host='redis', port=6379)
```

なぜ `host='redis'`で別のコンテナの`redis`につなぐことが出来るんだい? 

上記の公式サイトには以下のように解説されています。


> In this example, redis is the hostname of the redis container on the application’s network. We use the default port for Redis, 6379.

はぇ〜

## application’s network ってなに

ここでいう `application’s network` とは `docker container` におけるネットワークのことっぽい？

`docker-compose up` 等で起動されたコンテナ群は、すべて同一のネットワークに所属することになるようです。

参考にさせていただいた記事 : https://qiita.com/roba4coding/items/efd3a38db08eb476d412


## つまりどういうことだってばよ

`docker inspect` コマンドを使うことでふわっと概要がわかります。

`inspect` するためにまず コンテナのIDを調べます。

```sh

$ docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                    NAMES
aa690f2ae5d4        example_docker_compose_web   "python app-server/s…"   2 minutes ago       Up 2 minutes        0.0.0.0:5000->5000/tcp   example_docker_compose_web_1
4f39c7c9cc47        redis:alpine                 "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        6379/tcp                 example_docker_compose_redis_1
```

`inspect` します。

```sh

$ docker inspect 4f39c7c9cc47
...
            "Networks": {
                "example_docker_compose_default": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "4f39c7c9cc47",
                        "redis"
                    ],
                    ...
                }
            }
...
```

コンテナのID : `4f39c7c9cc47`(example_docker_compose_redis_1) が `redis` というエイリアスで登録されているのですね。

このエイリアスを使うことが出来るのが、同一 `docker network` に所属するものだけだということですね。

上記でいうと コンテナ `aa690f2ae5d4`(example_docker_compose_web_1) が エイリアスを使うことが出来るということですね。

どこで `redis` というエイリアスの名前が決まったかということですが、`docker-compose.yml`に書いてある `services`の直下の定義の名のことみたいですね。

```yml

version: '3'
services:
  # ↓これ
  web:
    build: .
    ports:
     - "5000:5000"
  # ↓これ
  redis:
    image: "redis:alpine"
```

## docker network ってなに

`docker network ls` で現在存在する `docker network` の一覧を見ることができます。

```sh

$ docker network ls
NETWORK ID          NAME                               DRIVER              SCOPE
ac27f0096628        bridge                             bridge              local
e72136cdac25        example_docker_compose_default     bridge              local
d2b0552308a8        host                               host                local
```

ここで 最初の `docker-compose` の `example` で作られたであろう `example_docker_compose_default` の`docker network`の詳細を見てみましょう。

コマンドは `docker network inspect` です。

```sh

$ docker network inspect example_docker_compose_default
[
    {
        "Name": "example_docker_compose_default",
        "Id": "e72136cdac25de9dbc9875467aacd59e916ba8b7122cbede91f81387a2a18715",
...
        "Containers": {
            "4f39c7c9cc478dc30aca3bd21c6dc1eda2bb189c0b5264a325f98b38ad8cd7c6": {
                "Name": "example_docker_compose_redis_1",
                ...
            },
            "aa690f2ae5d483c0c2cf213d9929a3d49025859464abe095f861c05bbb66ee32": {
                "Name": "example_docker_compose_web_1",
                ...
            }
        },
...
]
```

`Containers` に 先ほど `docker-compose` で作られたコンテナ達がありますね。コンテナIDも一致しているようです。


参考にさせていただいた記事 : https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9


## docker-compose を使わずにやってみよう

今回は別の例として `mysql` が起動しているコンテナ に対して `python` が起動したコンテナからアクセスしたいと思います。

### docker networkを知らなかった時

まず`mysql`のコンテナをたてます。

```sh

$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql mysql:5.6
4f7475ea1ac4db5d4aad630cbe585faf2dca39db61d7e405e14e9554414bd486
```

`python` が起動しているコンテナから `mysql`のコンテナにアクセスするためには、そのコンテナのアドレスを知る必要があります。

```sh

$ docker exec test-mysql cat /etc/hosts
127.0.0.1	localhost
.. 
172.17.0.2	4f7475ea1ac4
```

こうすることでようやく接続することができました。(もっといいやり方あったら教えてください..)

```py

>>> import mysql.connector
>>> conn = mysql.connector.connect(host="172.17.0.2",user="root",password="root",port=3306,database="mysql")
>>> conn.is_connected()
True
```


### docker networkを使った場合

まず、コンテナが所属するための `docker network` を作ります。

`docker network`に関して参考にさせていただいたブログ : https://www.sambaiz.net/article/7/

```sh

$ docker network create -d bridge test-network
25d355cf117def0e6ce801341e1b535320cd688435a436ce063dc49bbb3c9c0e
$ docker network ls
NETWORK ID          NAME                               DRIVER              SCOPE
ac27f0096628        bridge                             bridge              local
e72136cdac25        example_docker_compose_default     bridge              local
d2b0552308a8        host                               host                local
07263a6d0de1        test-network                       bridge              local
```

コンテナが作成される時に、作ったネットワークに所属してもらうようにするには、`--net` オプションを使うようです。

```sh

$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network --net-alias mysql  mysql:5.6
0f901dbda634c3d05cce10d2bf91fb0ef82d39fbd1b1046f284db522bc8387f8
```

こうすることで、`docker-compose` で起動したコンテナと同様にエイリアスが登録されます。

```sh

$ docker inspect 0f901dbda634
...
            "Networks": {
                "test-network": {
                    ...
                    "Aliases": [
                        "mysql",
                        "0f901dbda634"
                    ]
            ...
            }
...
```

そして python が起動するコンテナも同一`docker network`上にたててあげれば、

```sh

$ docker run -it --net=test-network test-python
>>> import mysql.connector
>>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql')
>>> conn.is_connected()
True

```

無事、コンテナを名前解決できるようになり、`host='mysql'` で接続できているのがわかると思います。

#### `--link` の場合

```sh
$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network  mysql:5.6
2d96784fb9ae77cec276558d3439e3b455782bb4bac4291b76b65a27d5c27480
$ docker run -it --net=test-network --link test-mysql:mysql test-python
Python 3.7.3 (default, Mar 27 2019, 23:48:15)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mysql.connector
>>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql')
>>> conn.is_connected()
True
```

同様に繋ぐことが出来ました。

`link` の場合 `Aliases`ではなく`Links`に名前解決するための情報が書かれていました。

```
...
            "Networks": {
                "test-network": {
                    ...
                    "Links": [
                        "test-mysql:mysql"
                    ],
                    "Aliases": [
                        "d0d2ed057334"
                    ],
                ...
                }
            }
...
```

`--net-alias` と `--link` の使い分けに関してはまだ知識が浅いのでいつか調べたいと思います。

## まとめ

**docker-compose** を使おう!