【Docker】Dockerネットワーク
Dockerネットワークとは
Dockerネットワークは、コンテナ間やホストマシンとの通信を行うための仕組みです。 例えば、Webサーバー、APサーバー、DBサーバーの三層構造でシステムを構築する場合、互いの通信無しでは構築できません。
Dockerではデフォルトで3つのネットワークが作成されます。
これらは、docker network lsコマンドを実行することで確認できます。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
84ee3eb8011a bridge bridge local
2608c71b8b1b host host local
08401ea912ba none null localこの中でNAMEがbridgeのネットワークがデフォルトとなっており、ネットワークを指定しないすべてのコンテナはbridgeに属します。
後述しますが、DRIVERがbridgeとあるのはブリッジネットワークであることを示しています。
ここでは主にこのブリッジネットワークについて説明をしていきます。
ポートの関連付け
ブリッジネットワークの説明の前に、ホストとコンテナのポートの関連付けについて説明をしておきます。
例えば、NGINXのコンテナを作成します。
NGINXではデフォルトで80番ポートが使用されますが、http://localhostとしてもページは表示されません。
よくよく考えてみると、仮に80番ポートを使用しているNGINXのコンテナが複数作成した場合に、どのコンテナにアクセスすればいいかわからなくなります。
そこで、ホストのポートとコンテナ及びコンテナのポートを関連づけます。
要はホストのXX番ポートにアクセスした場合、対象コンテナのXX番ポートにアクセスしたことにするといった感じです。
この設定は、docker container runコマンドの-pオプションで{ホストのポート}:{コンテナのポート}を指定することで行います。
$ docker container run -p 3000:80 -d --rm --name web1 nginx
$ docker container run -p 3001:80 -d --rm --name web2 nginx上記の場合、http://localhost:3000とすればweb1の80番ポートにアクセスしたことになり、http://localhost:3001とすればweb2の80番ポートにアクセスしたことになります。
このポートの設定は、docker portコマンドによって確認することができます。
$ docker port web1
80/tcp -> 0.0.0.0:3000デフォルトネットワーク
前述の通り、コンテナはデフォルトネットワークとしてbridgeという名前のブリッジネットワークに接続されます。
ブリッジネットワークは、同一ホスト内のコンテナ同士で通信を行うためのネットワークになります。
設定を確認するためにdocker container inspectでNetworkSettings.Networksの値を確認してみます。
$ docker container run -itd --name u1 ubuntu bash
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u1
{
"bridge": {
"IPAMConfig":null,
"Links":null,
"Aliases":null,
"NetworkID":"3990788d3dfb5317c7b2dbcfcb3bb22ac2524c3f9a6fe0de3c1de79f00dbcc20",
"EndpointID":"2cd95efbb28c0c6bd07a256d100a000f8d908b382f1bb216ebcc04ced1c4cb35",
"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
}
}最初のbridgeはネットワークの名前です。つまり、bridgeのネットワークに接続されていることを表します。
さらに、IPアドレスに172.17.0.2、ゲートウェイに172.17.0.1が設定されていることがわかります。
さらにもう1つコンテナを作成してみます。
$ docker container run -itd --name u2 ubuntu bash
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u2
{
"bridge": {
"IPAMConfig":null,
"Links":null,
"Aliases":null,
"NetworkID":"3990788d3dfb5317c7b2dbcfcb3bb22ac2524c3f9a6fe0de3c1de79f00dbcc20",
"EndpointID":"ea1efded02ba5851a53e5578236d677dd7fc2d72425a3eccc9144114d5bb1507",
"Gateway":"172.17.0.1",
"IPAddress":"172.17.0.3",
"IPPrefixLen":16,
"IPv6Gateway":"",
"GlobalIPv6Address":"",
"GlobalIPv6PrefixLen":0,
"MacAddress":"02:42:ac:11:00:03",
"DriverOpts":null
}
}設定からu1と同じくbridgeに接続されていることがわかります。
同じネットワーク上に存在することから、u1とu2は互いに通信できるはずです。
では実際にこの2つのコンテナが通信できることを確認してみます。
$ docker container exec u1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.061 ms% docker container exec u2 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.060 msデフォルトでは
pingコマンドはインストールされていないため、apt-get update,apt-get install iputils-pingを事前に実行しておきます。
互いにPING応答があることから通信できていることがわかります。
ネットワークの作成
コンテナはデフォルトネットワークであるbridgeに接続することになりますが、関連性のないコンテナ同士が通信できてしまうのはよくありません。
そこで、docker network createコマンドでネットワークを作成し、作成したネットワークに接続をします。
$ docker network create my-network
976249e112709ff51735b239f8e3b4535dfb3f99a42ea8d7724b0546b77b55d5
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
3990788d3dfb bridge bridge local
2608c71b8b1b host host local
976249e11270 my-network bridge local
08401ea912ba none null local上記コマンドにより、my-networkという名前のブリッジネットワークが作成できました。
作成したネットワークにコンテナを接続するには、docker container runコマンドの--networkオプションを指定します。
$ docker container run -itd --name u3 --network my-network ubuntu bash作成したコンテナのネットワーク設定を確認します。
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u3
{
"my-network": {
"IPAMConfig":null,
"Links":null,
"Aliases":["5ae5c71cb7be"],
"NetworkID":"976249e112709ff51735b239f8e3b4535dfb3f99a42ea8d7724b0546b77b55d5",
"EndpointID":"bbcfc63b2ae6a4c7a2054b2ec66edac0a0c3b210e4e6c89a1d93bbe5459a946d",
"Gateway":"172.19.0.1",
"IPAddress":"172.19.0.2",
"IPPrefixLen":16,
"IPv6Gateway":"",
"GlobalIPv6Address":"",
"GlobalIPv6PrefixLen":0,
"MacAddress":"02:42:ac:13:00:02",
"DriverOpts":null
}
}設定からmy-networkに接続されていることがわかります。
また先ほど作成したu1、u2とゲートウェイが異なっていることからも、別のネットワークであることがわかります。
念の為、u1と通信できないことを確認します。
$ docker container exec u1 ping -w 5 172.19.0.2
PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
--- 172.19.0.2 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4133ms$ docker container exec u3 ping -w 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4119ms次にmy-networkに接続するu4コンテナを作成し、u3と通信できることを確認します。
$ docker container run -itd --name u4 --network my-network ubuntu bash
#IPの確認は省略(172.19.0.3)$ docker container exec u3 ping 172.19.0.3
PING 172.19.0.3 (172.19.0.3) 56(84) bytes of data.
64 bytes from 172.19.0.3: icmp_seq=1 ttl=64 time=0.085 ms$ docker container exec u4 ping 172.19.0.2
PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
64 bytes from 172.19.0.2: icmp_seq=1 ttl=64 time=0.067 ms一般的にはデフォルトネットワークではなく、作成したネットワークを使用します。 理由の1つとして、デフォルトネットワークを使用していた場合、意図せず関連のないコンテナが介入することがあるからです。 明示的にネットワークを指定すれば、このようなミスは減るはずです。 またネットワークの管理や設定の自由度の観点からも作成したネットワークを使う方がよいとされています。
ネットワークの管理
これまでにネットワークの一覧表示(docker network ls)とネットワークの作成(docker network create)のコマンドを使用しました。
以下よりその他のネットワークに関するコマンドについて説明をします。
詳細表示
ネットワークの詳細表示は、docker network inspectコマンドを実行します。
Containersは接続されているコンテナの一覧になります。
$ docker network inspect my-network
[
{
"Name": "my-network",
"Id": "976249e112709ff51735b239f8e3b4535dfb3f99a42ea8d7724b0546b77b55d5",
"Created": "2024-02-24T12:09:50.304071296Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"2c98bc67ff22bd5455893bf520b9e1f44282cd8e21ce16bad1fa978c723e88f0": {
"Name": "u4",
"EndpointID": "4e4a401f108f76e53ccd46d45ac0ace49f01462726b9eb8c07d17ffd6933187a",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
},
"5ae5c71cb7be1298b232a0547283c40524f9c8915bfa594aa871ea94b07003b6": {
"Name": "u3",
"EndpointID": "bbcfc63b2ae6a4c7a2054b2ec66edac0a0c3b210e4e6c89a1d93bbe5459a946d",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]接続/切断
ネットワークの接続は、docker container runコマンドの--networkオプション以外に、docker network connectコマンドによって可能です。
あらかじめ作成されたコンテナに対してネットワークを接続する場合に使用します。
$ docker container run -itd --name u5 ubuntu bash
$ docker network connect my-network u5
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u5
{
"bridge": {
"IPAMConfig":null,
"Links":null,
"Aliases":null,
"NetworkID":"3990788d3dfb5317c7b2dbcfcb3bb22ac2524c3f9a6fe0de3c1de79f00dbcc20",
"EndpointID":"babc5aee02c971d7a99a3f96f113348aea4695059519baf328419839037cf35b",
"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
},
"my-network":{
"IPAMConfig":{},
"Links":null,
"Aliases":["c0c50bedecfb"],
"NetworkID":"976249e112709ff51735b239f8e3b4535dfb3f99a42ea8d7724b0546b77b55d5",
"EndpointID":"9a5e5368ec3f1128c6ba9a831cd5f251d63b0d26196662e9491bb0febc509ea1",
"Gateway":"172.19.0.1",
"IPAddress":"172.19.0.4",
"IPPrefixLen":16,
"IPv6Gateway":"",
"GlobalIPv6Address":"",
"GlobalIPv6PrefixLen":0,
"MacAddress":"02:42:ac:13:00:04",
"DriverOpts":{}
}
}上記は、新しく作成したu5コンテナをmy-networkに接続しています。
しかし、ネットワーク設定を見ての通りデフォルトのbridgeにも接続されてしまっています。そこで、docker network disconnectコマンドによって、不要なネットワークから切断をします。
$ docker network disconnect bridge u5
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u5
{
"my-network":{
"IPAMConfig":{},
"Links":null,
"Aliases":["c0c50bedecfb"],
"NetworkID":"976249e112709ff51735b239f8e3b4535dfb3f99a42ea8d7724b0546b77b55d5",
"EndpointID":"9a5e5368ec3f1128c6ba9a831cd5f251d63b0d26196662e9491bb0febc509ea1",
"Gateway":"172.19.0.1",
"IPAddress":"172.19.0.4",
"IPPrefixLen":16,
"IPv6Gateway":"",
"GlobalIPv6Address":"",
"GlobalIPv6PrefixLen":0,
"MacAddress":"02:42:ac:13:00:04",
"DriverOpts":{}
}
}削除
ネットワークを削除する場合は、docker network rmコマンドを使用します。
コンテナが接続されている場合は削除できません。
$ docker network rm test-networkまたdocker network pruneコマンドによって、接続のないネットワークを一括で削除することができます。
$ docker network pruneIPアドレスの設定
ネットワークを作成するdocker network createコマンドでは、オプションによって以下のようなIPアドレスに関する設定ができます。
--gateway: ゲートウェアいのIPアドレスを設定--ip-range: 自動でコンテナに割り当てるIPの範囲を設定--subnet: サブネットマスクを設定
$ docker network create --subnet '172.20.1.0/24' --gateway '172.20.1.254' --ip-range '172.20.1.1/30' test-network
0f7f8536b14d401ca09ecd25b0cbcc2741d457c4d8dea75c89683334f8eecd60
$ docker network inspect test-network
[
{
"Name": "test-network",
"Id": "d0a26f6bc7c37a601c6b776a458cfd08fd01476b822388259c9e433e57a66770",
"Created": "2024-02-24T14:39:46.415690044Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.1.0/24",
"IPRange": "172.20.1.1/30",
"Gateway": "172.20.1.254"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]--ip-rangeの設定はサブネットマスクと同じ考え方で、上記の場合だと172.16.20.0は使用できないため、172.20.1.1〜172.20.1.3までのIPがコンテナに割り当てられます。
$ docker container run -itd --name u6 --network test-network ubuntu bash
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u6
{
"test-network": {
"IPAMConfig": null,
"Links": null,
"Aliases": ["40e7faa9ca94"],
"MacAddress": "02:42:ac:14:01:01",
"NetworkID": "d0a26f6bc7c37a601c6b776a458cfd08fd01476b822388259c9e433e57a66770",
"EndpointID": "2dd9652f82e32d8fd064172c2f753dec041155865232b50c6d4a270c1c8dd60b",
"Gateway": "172.20.1.254",
"IPAddress": "172.20.1.1",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null
}
}上記のIPすべてが使用されている場合は以下のようにエラーになります。
$ docker container run -itd --name u9 --network test-network ubuntu bash
9e9e19d0c28ffbc0e0e0ca32b7ac1598ce06dcbe1c87fb9f417e8d7ff2566024
docker: Error response from daemon: no available IPv4 addresses on this network's address pools: test-network
/(d0a26f6bc7c37a601c6b776a458cfd08fd01476b822388259c9e433e57a66770).--ip-rangeはあくまで自動で設定されるIPアドレスの範囲です。
docker container runコマンドでは、--ipオプションによって自身のIPアドレスを設定することができます。
このようにIPアドレスを明示的に指定する場合は、--ip-rangeの範囲外でも設定できます。
$ docker container run -itd --name u9 --network test-network --ip '172.20.1.10' ubuntu bash
$ docker container inspect --format '{{json .NetworkSettings.Networks}}' u9
{
"test-network": {
"IPAMConfig": {
"IPv4Address": "172.20.1.10"
},
"Links": null,
"Aliases": ["e9855f0b09e9"],
"MacAddress": "02:42:ac:14:01:0a",
"NetworkID": "d0a26f6bc7c37a601c6b776a458cfd08fd01476b822388259c9e433e57a66770",
"EndpointID": "68082e7eee4fc519eabebab7aabfe3a6d679821ed70c5dc07a4108b71bb1ecd0",
"Gateway": "172.20.1.254",
"IPAddress": "172.20.1.10",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null
}
}名前解決
自身で作成したネットワークであれば、IPをコンテナ名で名前解決してくれます。 例えばu4 → u3のPINGをIPではなく、コンテナ名で実行しても応答が返ってきます。
$ docker container exec u4 ping u3
PING u3 (172.19.0.2) 56(84) bytes of data.
64 bytes from u3.my-network (172.19.0.2): icmp_seq=1 ttl=64 time=0.055 msデフォルトネットワークを使用している場合は、名前解決されない点に注意してください。
$ docker container exec u2 ping u1
ping: u1: Name or service not knownコンテナ名以外にエイリアスとして別名をつけることができます。
docker container runコマンドの場合は--network-aliasオプション、docker network connectコマンドの場合は--aliasオプションを使用します。
エイリアスを追加したとしても、コンテナ名での名前解決もそのまま使用できます。
$ docker container run -itd --name u21 --network my-network --network-alias 'test' ubuntu
$ docker % docker container exec u3 ping test
PING test (172.19.0.5) 56(84) bytes of data.
64 bytes from u21.my-network (172.19.0.5): icmp_seq=1 ttl=64 time=0.109 ms$ docker container run -itd --name u22 ubuntu
$ docker network connect --alias 'test2' my-network u22
$ docker container exec u3 ping test2
PING test2 (172.19.0.6) 56(84) bytes of data.
64 bytes from u22.my-network (172.19.0.6): icmp_seq=1 ttl=64 time=0.087 msネットワークの種類
最後にネットワークの種類について簡単に触れておきます。 これまで説明してきたブリッジネットワーク以外に以下のネットワークがあります。
| ネットワーク | ドライバー | 説明 |
|---|---|---|
| ホストネットワーク | host | ホストのネットワーク名前空間を共有する(Linux) |
| オーバーレイネットワーク | overlay | 異なるホストにあるDockerデーモン間の通信を行う |
| macvlanネトワーク | macvlan | 仮想NICを作成し、固有のMACアドレスを割り当てることで外部との通信を可能にする |
| 設定なし | null | ネットワークを利用しない(デフォルトで作成されているnoneを使用する) |