【Docker Network 第２章】Docker Networkingについて解説

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/7cf74b2f-2176-d9bb-55d2-5cb5690f0d68.png)

#概要
Dockerは、スタンドアロンモード、Docker Composeの使用、単一のホスト、またはコンテナーをデプロイして複数のホスト間でDockerエンジンを接続するなど、さまざまなユースケースで使用できます。 ユーザーは、デフォルトネットワーク、ホストネットワーク、またはオーバーレイなどの他のタイプのより高度なネットワークでDockerコンテナーを使用できます。 これは、ユースケースや採用されているテクノロジーによって異なります。

この記事では、さまざまなタイプのコンテナネットワークについて理解すると同時にコンテナネットワーキングについても学習します。 さまざまな種類のネットワークについて説明し、最後に、プラグインを使用してDockerネットワークを拡張する方法を理解します。 この記事はシリーズの第2部です。 第１章については、[この記事](https://qiita.com/MetricFire/items/617ecce36f4aca64ddb9)をご覧ください。 また、[Kubernetes Networking](https://www.metricfire.com/blog/kubernetes-networking-101/?GAID=2038175526.1567400116)と[cAdvisorを使用したDockerコンテナの監視](https://qiita.com/TomoEndo/items/4aa2d9889c49148a3d7f)に関するリソースもありますので、興味がある方は、そちらもチェックしてみてください。

[【Docker Network 第1章】](https://qiita.com/MetricFire/items/617ecce36f4aca64ddb9)
[【Docker Network 第3章】](https://qiita.com/MetricFire/items/b731c84975bd9894748d)

#スタンドアロンのDockerネットワーク
###デフォルトのブリッジネットワーク
Dockerを新たにインストールすると、デフォルトのブリッジネットワークが稼働していることがわかります。

docker network lsと入力すると、次のように表示されます。

```
NETWORK ID          NAME                DRIVER              SCOPE
5beee851de42        bridge              bridge              local
```

ifconfigコマンドを使用すると、このネットワークインターフェイスが「docker0」と呼ばれることにも気付くはずです。

```
docker0: flags=4099&lt;UP,BROADCAST,MULTICAST&gt;  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:90:68:1f:7f  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
```

すべてのDockerインストールにこのネットワークがあります。 Nginxなどのコンテナを実行すると、デフォルトでブリッジネットワークに接続されます。

```
docker run -dit --name nginx nginx:latest
```

「inspect」コマンドを使用して、ネットワーク内で実行されているコンテナを確認できます。

```
docker network inspect bridge


---
        "Containers": {
            "dfdbc18945190c832c3e0aaa7013915d77022851e69965c134045bb3a37168c4": {
                "Name": "nginx",
                "EndpointID": "33a598ffd6d4df792c58a6b6fdc34cd162c9dd3a3f1e58add29f30ad7f1dfdac",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
```

Dockerは、ソフトウェアベースのブリッジネットワークを使用します。これにより、同じブリッジネットワークに接続されているコンテナーは、同じブリッジネットワークで実行されていない他のコンテナーから分離しながら通信できます。

同じブリッジネットワークで実行されているコンテナがどのように相互に接続できるかを見てみましょう。 テスト目的で2つのコンテナを作成しましょう。

```
docker run -dit --name busybox1 busybox
docker run -dit --name busyboxZ busybox
```

コンテナのIPアドレスは次のとおりです。

```
docker inspect busybox1 |  jq -r  ' [0].NetworkSettings.IPAddress'
docker inspect busybox2 |  jq -r  '.[0].NetworkSettings.IPAddress'


---
172.17.0.3
172.17.0.4
```

これらのIPアドレスの1つを使用して、別のコンテナーからコンテナーにpingを実行してみましょう。 たとえば、IP 172.17.0.3を使用して、「busybox2」から「busybox1」という名前のコンテナにpingを実行します。

```
docker exec -it busybox2 ping 172.17.0.3


---
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.245 ms
```

したがって、同じブリッジ上のコンテナは、IPを使用して相互に認識できます。 IPの代わりにコンテナの名前を使用したい場合はどうなるでしょうか。

```
docker exec -it busybox2 ping busybox1
---
ping: bad address 'busybox1'
```

同じブリッジネットワーク上で実行されているコンテナは、IPアドレスを使用して相互に認識できることが理解できます。 一方、デフォルトのブリッジネットワークは自動サービス検出をサポートしていません。

#ユーザー定義のブリッジネットワーク
Docker CLIを使用すると、他のネットワークを作成できます。 以下を使用して、2番目のブリッジネットワークを作成できます。

```
docker network create my_bridge --driver bridge
```

ここで、「busybox1」と「busybox2」を同じネットワークに接続します。

```
docker network connect my_bridge busybox1
docker network connect my_bridge busybox2
```

名前を使用して「busybox1」にpingを再試行します。

```
docker exec -it busybox2 ping busybox1
---
PING busybox1 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.113 ms
```

自動サービス検出をサポートしているのは、ユーザー定義のブリッジネットワークのみであると結論付けることができます。 コンテナーでサービス検出を使用する必要がある場合は、デフォルトのブリッジを使用せずに、新しいブリッジを作成してください。

‍###ホストネットワーク
ホストネットワークで実行されているコンテナは、ホストのネットワーク構成と一致します。

Nginxイメージの例をとると、ポート80が公開されていることがわかります。

```
EXPOSE 80
```

コンテナを実行する場合、通常はポート80を別のポート（たとえば8080）で公開する必要があります。

```
docker run -dit -p 8080:80 nginx:latest
```

これで、コンテナはポート8080でアクセスできます。

```
curl -I 0.0.0.0:8080


---
HTTP/1.1 200 OK
Server: nginx/1.17.5
Date: Wed, 20 Nov 2019 22:30:31 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT
Connection: keep-alive
ETag: "5daf1268-264"
```

ホストネットワークで同じコンテナを実行すると、ホストのポート80がすべての場合に使用されるため、公開されたポートは無視されます。 実行する場合：

```
docker run -dit --name nginx_host --network host -p 8080:80 nginx:latest
```

Dockerは警告を表示します：

```
WARNING: Published ports are discarded when using host network mode
```

このコンテナを削除して、ポートを公開せずに再実行してみましょう。

```
docker rm -f nginx_host;
docker run -dit --name nginx_host --network host  nginx:latest
```

これで、ホストマシンのポート80で「curl」を実行して、Webサーバーが応答することを確認できます。

```
curl -I 0.0.0.0:80



---
HTTP/1.1 200 OK
Server: nginx/1.17.5
Date: Wed, 20 Nov 2019 22:32:27 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT
Connection: keep-alive
ETag: "5daf1268-264"
Accept-Ranges: bytes
```

ネットワークアドレス変換（NAT）がないため、ホストネットワークでコンテナーを実行するとパフォーマンスを最適化できます。 ホストネットワークでコンテナを実行すると、そのネットワークはホストから分離されず、独自のIPを取得しません。 これらは、このタイプのネットワークの限界です。

###Macvlanネットワーク
たとえば、基盤となる物理ネットワークに直接接続されることが予想されるトラフィックを監視するアプリケーションを開発している場合は、macvlanネットワークドライバーを使用できます。 このドライバーは、各コンテナーの仮想ネットワークインターフェイスにMACアドレスを割り当てます。

例：

```
docker network create -d macvlan --subnet=150.50.50.50/24--gateway=150.50.50.1  -o parent=eth0 pub_net
```

macvlanネットワークを作成するときは、parentを指定する必要があります。これは、トラフィックが物理的にルーティングされるときに使用されるホストインターフェイスです。

###None

場合によっては、コンテナを着信/発信トラフィックから分離する必要があります。ネットワークインターフェイスがないこのタイプのネットワークを使用できます。

コンテナが持つ唯一のインターフェースは、ローカルループバックインターフェース（127.0.0.1）です。

#分散ネットワーク
###オーバーレイネットワーク
コンテナプラットフォームには異なるホストがあり、それぞれでいくつかのコンテナが実行されている場合があります。 これらのコンテナは相互に通信する必要がある場合があります。 これは、オーバーレイネットワークが役立つ場合です。

オーバーレイネットワークは、異なるホストの複数のDockerデーモン間で作成された分散ネットワークです。 このネットワークに接続されているすべてのコンテナは通信できます。

###Ingress
たとえば、Docker Swarmは、オーバーレイネットワークを使用してSwarmサービス間のトラフィックを処理します。

これをテストするために、3台のDockerマシン（manager + two machines）を作成しましょう。

```
docker-machine create manager
docker-machine create machine1
docker-machine create machine2
```

これらのマシンごとに異なるシェルを構成した後（eval $（docker-machine env <machine_name>を使用）、次のコマンドを使用して、managerでSwarmを初期化します。

```
docker swarm init --advertise-addr &lt;IP_address&gt;
```

両方のワーカーでjoinコマンドを実行することを忘れないでください。

```
docker swarm join --token xxxx &lt;IP_address&gt;:2377
```

docker network lsを使用して各ホスト上のネットワークを一覧表示すると、オーバーレイIngressネットワークの存在に気付くでしょう。

```
o5dnttidp8yq   ingress      overlay      swarm
```

managerで、3つのレプリカを使用して新しいサービスを作成します。

```
docker service create  --name  nginx --replicas 3 --publish published=8080,target=80 nginx
```

サービスがデプロイされているスウォームノードを確認するには、docker service psnginxを使用します。

```
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE        
fmvfo2nschcq        nginx.1             nginx:latest        machine1            Running             Running 3 minutes ago
pz1kob42tqoe        nginx.2             nginx:latest        manager             Running             Running 3 minutes ago
xhhnq68sm65g        nginx.3             nginx:latest        machine2            Running             Running 3 minutes ago
```

この場合、各ノードでコンテナを実行しています。

docker inspect ingressを使用してIngressネットワークを検査すると、同じネットワークに接続されているピア（スワムノード）のリストを確認できます。

```
 "Peers": [
            {
                "Name": "3a3c4007c923",
                "IP": "192.168.99.102"
            },
            {
                "Name": "9827ad03b358",
                "IP": "192.168.99.100"
            },
            {
                "Name": "60ae1df1c8b2",
                "IP": "192.168.99.101"
            }
```

Ingressネットワークは、デフォルトで作成される特定のタイプのオーバーレイネットワークです。

ユーザー定義のオーバーレイネットワークに接続せずにサービスを作成すると、デフォルトでこのIngressネットワークに接続します。 Nginxを使用して、ユーザー定義のオーバーレイネットワークなしで実行されているが、デフォルトでIngressネットワークに接続されているサービスの例を次に示します。

```
docker service inspect nginx|jq -r  .[0].Endpoint.Ports[0]


---
{
  "Protocol": "tcp",
  "TargetPort": 80,
  "PublishedPort": 8080,
  "PublishMode": "ingress"
}
```

#Dockerネットワークプラグイン
新しいタイプのネットワークを必要とする他のタイプのユースケースがあります。 また、別のテクノロジーを使用して、オーバーレイネットワークとVXLANトンネルを管理することもできます。

Dockerネットワークは拡張可能であり、プラグインを使用してデフォルトで提供される機能を拡張できます。

ネットワークプラグインを使用または開発できます。 DockerHubには検証済みのネットワークプラグインもいくつかあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/0bffdb71-7952-b382-3d95-be8cfd314567.png)

各プラグインには、異なるユースケースとインストール手順があります。 たとえば、Weave Netは、ホストのクラスター全体でコンテナーを接続し、自動検出を可能にする仮想Dockerネットワークです。

これをインストールするには、DockerHubの公式の指示に従うことができます。

```
docker plugin install --grant-all-permissions store/weaveworks/net-plugin:2.5.2
```

Weave Netネットワークを作成し、以下を使用して接続可能にすることができます。

```
docker network create --driver=store/weaveworks/net-plugin:2.5.2 --attachable    my_custom_network
```

次に、同じネットワークを使用してコンテナを作成します。

```
docker run -dit --rm --network=my_custom_network -p 8080:80 nginx
```

このシリーズの３章まであります。パートIを見逃した場合は、[こちら](https://qiita.com/MetricFire/items/617ecce36f4aca64ddb9)をチェックしてください。 Dockerコンテナーの監視に興味がある場合は、[cAdvisorを使用したDockerの監視](https://qiita.com/TomoEndo/items/4aa2d9889c49148a3d7f)に関する記事でその方法を学習してください。 また、[Prometheusを使用したKubernetesのモニタリング](https://qiita.com/MetricFire/items/7eec4addca4a40a4d2d2)に関するブログ投稿もご覧ください。

#シリーズ
[【Docker Network 第1章】](https://qiita.com/MetricFire/items/617ecce36f4aca64ddb9)
[【Docker Network 第3章】](https://qiita.com/MetricFire/items/b731c84975bd9894748d)