Docker のネットワークについて

この記事は、[福岡若手Sier_bc Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fukuoka-sier_young_bc) の 13 日目の投稿です。

# はじめに
Docker を勉強していて、どうも難しく感じてしまうのがコンテナのネットワークについて。
自分の備忘録もかねて徒然なるままに綴ります。

# 確認用の環境構築
確認用の環境は、Virtual Box で仮想マシンを作成し、その中に Docker の環境を作ります。
[以前の自分の投稿で](https://qiita.com/guromityan/items/6bc813c7b7587e6a8876)、
> ただ、個人的に Virtual Box で仮想マシン作って〜、Nginx インストールして〜
ってのはめんどくさいので Docker でやってしまいます。（ごめんね）

と書いていましたが今回はわざわざ Virtual Box 上に Docker の環境を作ります。
ただ、ここはさすが Docker さん。
簡単に環境を構築できるコマンドが用意されています。
それが、 [docker-machine](http://docs.docker.jp/machine/overview.html#docker-machine) コマンド。
( 「Docker 版の Vagrant 的なやつ」 と言うとイメージがしやすい?? )

やり方は簡単で、Virtual Box と [docker-machine コマンドをインストール](http://docs.docker.jp/machine/install-machine.html) して以下のコマンドを実行。

```
docker-machine create nw-vm
```
これで、Virtual Box 上に Docker の環境が入った`nw-vm`という名前のインスタンスが立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/1dff7b89-9a85-5c77-4d5d-bd5438c5e933.png)
インスタンスの中に入るには、

```
$ docker-machine ssh nw-vm

   ( '>')
  /) TC (\   Core is distributed with ABSOLUTELY NO WARRANTY.
 (/-_--_-\)           www.tinycorelinux.net

docker@nw-vm:~$
```
で中に入れます。

# デフォルトのネットワーク
インスタンスの中に入ったら、デフォルトの Docker ネットワークを確認します。

```
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4a85b1978bc9        bridge              bridge              local
f06510f48928        host                host                local
6aa5429b7a4f        none                null                local
```
Docker をインストールすると必ずこれらのネットワークが作成されます。

## bridge network
コンテナを起動する際に特にネットワークを指定しないと `bridge` が選択されます。
その詳細を確認します。
( ちなみに、docker で何かの詳細を確認する時はだいたい、`docker ~ inspect ~` です。)

```
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "4a85b1978bc9dfb5f5304686227fd6e4f34d7f0ef4cb567f7fb091211a9feb13",
        "Created": "2019-12-12T14:17:10.468964848Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
```
注目すべきは以下です。

```
"Config": [
    {
        "Subnet": "172.17.0.0/16",
        "Gateway": "172.17.0.1"
    }
]
```
コンテナは、`172.17.0.0/16` のネットワークに所属します。
そして、ゲートウェイの `172.17.0.1` は `docker0` インターフェースに接続されています。
インスタンスのネットワークインターフェースを確認します。

```
$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:7C:77:4F:5F
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
```
`inet addr:172.17.0.1` で、確かに `docker0` インターフェースが `172.17.0.1` の IP アドレスが割り当てられていることが確認できました。

### コンテナを起動してみる

```
$ docker run -itd --rm --name=nginx nginx
```
で起動し、詳細を確認

```
$ docker inspect nginx
~~~ 省略 ~~~
"Networks": {
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "4a85b1978bc9dfb5f5304686227fd6e4f34d7f0ef4cb567f7fb091211a9feb13",
        "EndpointID": "a3414897f695a122751cc0e33de651b988a91c3b69b493ad4ad66efab29b41d2",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:02",
        "DriverOpts": null
    }
}
~~~ 省略 ~~~
```
めちゃめちゃ表示される中から下の方の `Networks` でコンテナのネットワーク状態を確認できます。
このコンテナには、`172.17.0.2` の IP アドレスが割り当てられています。

###  ネットワークの作成

```
$ docker network create my-bridge 
```
でユーザ定義のブリッジネットワークを作成することができます。
コンテナをネットワークに接続するためには、

```
// 起動中のコンテナの場合
docker network connect <ネットワーク名> <コンテナ名>

// 最初からネットワークに接続して起動する場合
docker run --network <ネットワーク名> ~~~
```
作成した、`my-bridge` とデフォルトの `bridge` の違いは、コンテナ名で名前解決ができるかどうかです。
ユーザ定義のネットワークであれば、コンテナ名で名前解決ができるため、
同じネットワークに所属するコンテナ同士であれば、コンテナ名で通信することができます。

## host network
コンテナがこのネットワークに所属した状態で起動すると、コンテナはホストマシンのネットワークインターフェースと共有された状態になります。
例えば、Nginx のサーバを起動した場合、外部からコンテナの 80 番ポートにアクセスするためには `-p` オプションでポートフォワードを設定する必要があります。
しかし、host ネットワークであれば Nginx を起動したらホストマシンの 80 番ポートがそのままコンテナの 80 番ポートに流れて行きます。

`docker-machine` コマンドで起動したインスタンスの IP アドレスは、

```
$ docker-machine ip nw-vm
192.168.99.115
```
で確認することができます。
この状態で、host ネットワークに所属した Nginx コンテナを起動します。

```
$ docker run -itd --name=nginx2 --rm --network=host nginx
```
これで、ブラウザから先ほど確認した http://192.168.99.115 にアクセスすると Nginx デフォルトページが表示されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/bb9cf437-bc92-b28c-e017-1b249591eeba.png)


## none network 
コンテナがこのネットワークに所属した状態で起動すると、このコンテナは **ループバックインターフェースしか持たない** 状態になります。

# さいごに

立ち上げたインスタンスの停止は以下のコマンドでできます。

```
$ docker-machine stop nw-vm
```
次はマルチホスト上でのコンテナ間通信について書こうと思います。

### ちなみに
docker-machine コマンドは有能なやつで、AWS の EC2 上に Docker ホストを構築できちゃったりもします。
詳しくは自分で調べてください。()