Dockerにおけるネットワーク

## はじめに
こちらはDockerネットワーク関連についての記事になります。情報が陳腐化している箇所もありますのでご了承ください:bow:。

以下は、私がDocker関連についてまとめている記事になります。もし興味がありましたらご覧になってください。
* [Dockerにおけるコンテナ](https://qiita.com/Hirohana/items/c881118021fd156ccefe "Dockerにおけるコンテナ") 
* [Dockerにおけるイメージとは](https://qiita.com/Hirohana/items/a7b11c72e525c48d34bf "Dockerにおけるイメージとは") 
* [Dockerにおけるネットワーク](https://qiita.com/Hirohana/items/3fff1a1d11a0f1505dad "Dockerにおけるネットワーク") 
* [Dockerにおけるデータ管理](https://qiita.com/Hirohana/items/59a22d549fcfb096f0b9 "Dockerにおけるデータ管理")


## Dockerにおけるネットワーク
Dockerにおけるネットワークは、Dockerコンテナ間やコンテナとホストマシン、または外部のネットワークとの通信を管理するための仮想ネットワークです。Dockerは、コンテナのネットワークを容易に設定・管理するための機能を提供しています。

Dockerには以下のようなネットワークが定義されています。

1. **デフォルトのブリッジネットワーク**
1. **ユーザー定義ブリッジネットワーク**
1. **ホストネットワーク**
1. **ノンネットワーク**

Dockerのネットワークは、`docker network ls`コマンドで確認することができます。
```terminal: terminal
$ docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
682cc16dc1af   bridge    bridge    local　// 1. デフォルトのブリッジネットワーク
fff149d9ddb5   host      host      local  // 3. ホストネットワーク
d62c6cb8c5c5   none      null      local  // 4. ノンネットワーク
```

上記を見ると、`デフォルトのブリッジネットワーク`、`ホストネットワーク`、`ノンネットワーク`が確認できます。
`ユーザー定義ブリッジネットワーク`については、文字通りユーザーが定義、作成するネットワークになりますので初期の段階では表示されません。

では最初に`デフォルトのブリッジネットワーク`について解説します。

## デフォルトのブリッジネットワーク
Dockerデーモンが起動すると自動的に作成されるデフォルトのブリッジネットワークです。コンテナは作成したらデフォルトでbridgeドライバで作成されたこのブリッジネットワークに属することになります。

<details><summary>デフォルトブリッジのネットワークの詳細</summary>
デフォルトブリッジネットワークは、Dockerコンテナがホストマシンと通信するための仮想ネットワークを提供します。具体的には、Dockerが実行されているホストマシンの物理ネットワークインターフェース（通常はdocker0と呼ばれる）とブリッジ接続されます。このブリッジは、ホストマシンとコンテナ間の通信を中継し、コンテナにIPアドレスを割り当てる役割を果たします。

またコンテナは自動的にこのネットワークに接続され、IPアドレスが割り当てられます。コンテナ同士も互いに通信することができます。

更にデフォルトブリッジネットワークはDockerが初めてインストールされるときに自動的に作成されます。このネットワークを使用すると、コンテナはホストマシンや他のコンテナと容易に通信することができます。ただし、デフォルトブリッジネットワークは、他のユーザー定義ブリッジネットワークとは分離されていません。つまり、デフォルトブリッジネットワークに接続されたコンテナは、同じネットワーク内の他のコンテナと相互に通信することができます。
</details>

ネットワークの詳細は、`docker network inspect <network-name>`で確認できます。`<network-name>`には確認したいネットワークの名前またはIDを指定します。このコマンドにより、ネットワークのドライバ、割り当てられたサブネット、接続されているコンテナなどの情報を取得することができます。

デフォルトのブリッジネットワークについて詳細を見てみます。

```terminal: terminal
$ docker network inspect bridge

// 省略
 "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
// 省略
```
詳細を全て記載すると膨大なコード量になるので、抜粋します。

Dockerのネットワーク管理機能の"IPAM"(IP Address Management)において"Config"の欄を確認すると、ネットワークの"Subnet"とデフォルトの"Gateway"のIPが表示されています。

"Subnet"は、`ネットワーク内の IP アドレスの範囲を表しています。コンテナが作成された場合、そのコンテナが割り当てられるIPは`172.17.0.0 から 172.17.255.255`までの間ということになります。

"Gateway"は、ネットワーク内のデフォルトゲートウェイの IP アドレスを示しています。デフォルトゲートウェイは、ネットワーク内の他のネットワークやインターネットへのパケット転送の役割を果たします。この場合、172.17.0.1 が ブリッジネットワークのデフォルトゲートウェイとなります。

では次に、実際にコンテナを作成してデフォルトのブリッジネットワークに接続されるか確認してみます。

```terminal: terminal
$ docker run -itd --name alpine1 alpine /bin/sh

$ docker network inspect bridge

// 省略

 "Containers": {
            "5108afd7ece432651b89de58bbe669675261c4760ca4a34bfb097b9aff5e07fa": {
                "Name": "alpine1",
                "EndpointID": "98426d953b50a4f12a41782e3acd82387f48a32bb2e02ed8858f856ceddc97a2",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },

// 省略
```

`alpine1`というコンテナを作成し、`docker inspect`コマンドでデフォルトのブリッジネットワークに繋がっているか見たことろ、上記のように`"IPv4Address": "172.17.0.2/16",`でIPが割り当てられています。

しかしデフォルトのブリッジネットワークでIPアドレスによる通信は行えますが、コンテナ名で通信を行おうとしてもDockerデーモンでDNSの機能が提供されないため、名前解決ができずコンテナ間の通信が行えません。

```terminal: terminal
$ docker run -itd --name alpine2 alpine /bin/sh

$  docker attach alpine2

/ # ping -w 3 alpine1
ping: bad address 'alpine1'
```

上記はalpine2というコンテナを作成し、alpine2のコンテナに接続しalpine1に対してコンテナ名でping通信を行ったところ、`bad address 'alpine1`というレスポンスが返ってきておりコンテナ名で通信ができないことを表しています。

しかしこれは冒頭で取り上げた、`ユーザー定義ブリッジネットワーク`を使えば解決できます。

次に`ユーザー定義のブリッジネットワーク`について説明します。

## ユーザー定義ブリッジネットワーク

ユーザー定義ブリッジネットワーク（User-defined Bridge Network）は、ユーザーが独自に作成することができるブリッジネットワークの一種です。デフォルトブリッジネットワークとは異なり、ユーザーが自由に設定できるカスタムネットワークです。

ユーザー定義ブリッジネットワークを作成すると、Dockerは仮想のブリッジインターフェースを作成し、そのネットワーク内のコンテナを接続します。ユーザー定義ブリッジネットワークでは、コンテナは指定されたネットワーク内で互いに通信することができます。

ではユーザー定義のブリッジネットワーク(my_nw)を作成し、上記で作成した`alpine1`と`alpine2`のコンテナを接続してみます。

ネットワークの作成コマンドは`docker network create <ネットワーク名>`です。
また、ネットワークとコンテナを接続するコマンドは`docker network connect <ネットワーク名> <コンテナ名>`になります。
```terminal: terminal
$ docker network create my_nw

$ docker network connect my_nw alpine1
$ docker network connect my_nw alpine2

$ docker network inspect my_nw

// 省略

 "Containers": {
            "5108afd7ece432651b89de58bbe669675261c4760ca4a34bfb097b9aff5e07fa": {
                "Name": "alpine1",
                "EndpointID": "3ffdf393af1ad7f850193d7953ea27a88dd62e7779e8297269681ea5db37194b",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "eae4741e2a8e14b2d0bfa161ec3ab733e8d52261496ffa5006a09f4691d89744": {
                "Name": "alpine2",
                "EndpointID": "70e26d75d4c5e84d32bcc63bfd69bb5d73d9dad923bcf1cf3d0ef13bfbc7162e",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },

// 省略
```

これで`my_nw`のネットワークに`alpine1`と`alpine2`のコンテナが接続されたことが確認できたので、IPアドレスではなくコンテナ名で通信が行えるか確認してみます。

`docker attach alpine2`コマンドで`alpine2`のコンテナに接続してping通信を行ってみます。
```terminal: terminal
$ docker attach alpine2

/ # ping -w 3 alpine1
PING alpine1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.049 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.119 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.103 ms

--- alpine1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.049/0.090/0.119 ms
```

`alpine1`のコンテナにping通信してみたところ、レスポンスが返ってきているので、コンテナ名で通信を行えていることが確認できました。

これはユーザー定義のブリッジネットワークでは、Dockerデーモンの組み込みDNSが機能してコンテナ名で名前解決を行ってくれるためです。

コンテナからネットワークを切り離すには`docker network disconnect <ネットワーク名> <コンテナ名>`コマンドを使います。
```terminal: terminal
$ docker network disconnect bridge alpine2
```

次にノンネットワークとホストネットワークについてですが、こちらはあまり使用される機会がないと思われますので、簡単な説明にとどめます。まずノンネットワークからです。

## ノンネットワーク
ノンネットワークはnullドライバに接続された特殊なネットワークタイプです。ノンネットワークを使用すると、Dockerコンテナはネットワークへの接続を持たず、ホストマシンのネットワークスタックから完全に切り離されます。このため、コンテナはネットワーク通信を行うことができず、自身の内部でのみ動作する閉じた環境を提供します。

<details><summary>ノンネットワークとnullドライバの詳細</summary>
nullドライバは、ネットワーク機能を無効にするドライバです。これにより、Dockerコンテナはネットワークに接続されず、完全に孤立した状態になります。このドライバは、特定のネットワーキング要件を満たすために使用されることがあります。例えば、ホストマシンのネットワークとの完全な分離が必要な場合や、ネットワーク機能を無効化してコンテナ内でのネットワーク通信を制限したい場合に使用されます。

nullドライバは、ネットワーク機能を無効にするドライバです。これにより、Dockerコンテナはネットワークに接続されず、完全に孤立した状態になります。このドライバは、特定のネットワーキング要件を満たすために使用されることがあります。例えば、ホストマシンのネットワークとの完全な分離が必要な場合や、ネットワーク機能を無効化してコンテナ内でのネットワーク通信を制限したい場合に使用されます。
</details>

ノンネットワークに接続されたコンテナは完全に孤立した状態になり、他のコンテナや外部の通信ができないので用途としては限定されたものになります。

## ホストネットワーク
ホストネットワークは、Dockerコンテナがホストマシンのネットワークスタックに直接接続されるネットワーキングモードです。つまり、コンテナはホストマシンのネットワークインターフェースを直接使用し、ホストマシンと同じネットワーク上に存在します。

ホストネットワークモードでは、コンテナは独自のネットワーク名前空間を持たず、自身のIPアドレスを持ちません。代わりに、ホストマシンのネットワークインターフェース（通常はデフォルトのイーサネットインターフェース）のIPアドレスを使用します。これにより、コンテナはホストマシンと同じネットワークに所属し、ホストマシンと同じネットワーク上のリソースに直接アクセスすることができます。

## おわりに
ここまで記事を読んでいただきありがとうございました。

間違い等ありましたらご指摘いただけると幸いです:bow:

## 参考

https://docs.docker.jp/