Dockerのブリッジ・ネットワークを利用したコンテナ間通信を行う
概要
ブリッジ・ネットワークを利用したDockerコンテナのコンテナ間通信について、公式ドキュメントの内容を参考にしつつ解説します。
Dockerのネットワーク機能の種類
Dockerのネットワーク機能は以下の7種類に分類されます。
本記事ではこのうち、bridgeを用いた接続を行います。
参考:https://docs.docker.jp/network/index.html
- bridge
デフォルトのネットワーク・ドライバです。ネットワーク作成時にドライバを指定しなければ、このネットワークになります。 通常、ブリッジ・ネットワークは、アプリケーションがスタンドアロン・コンテナ内で動作する時、このコンテナが通信するために使います 。詳しくは ブリッジ・ネットワーク をご覧ください。
- host
- overlay
- ipvlan
- macvlan
- none
ブリッジ・ネットワークについて
Dockerにおけるブリッジは、単一ホスト内で動作するコンテナ同士の通信を可能にするネットワークドライバです。
単一ホスト内に複数のブリッジ・ネットワークを作成することができ、同じブリッジネットワークに接続されたコンテナ間では相互に通信を行うことができます。
デフォルトではbridgeという名前のブリッジ・ネットワークが存在しており、ネットワークのオプション指定なしで作成したコンテナはこのネットワークに接続されます。
Dockerのネットワーク一覧はdocker network ls
コマンドで確認できます。
ネットワークを作成していない状態で上記のコマンドを実行すると以下の3つが表示され、一番上に表示されているものがデフォルトのブリッジ・ネットワークです。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
38bcf0d1750a bridge bridge local
af1b8f32ee2a host host local
d1e9a5e4a34d none null local
実践
単一コンテナの起動
まずは単一のコンテナを作成して、デフォルトのbridgeに接続されていることを確認します。
確認には軽量のlinuxイメージであるalpineを使います。
以下のコマンドでalpineのコンテナが起動します。
詳細は省きますが、-i
および-t
オプションを付与することでコンテナ内でシェルを起動し、ホストマシンの標準入出力を通してコンテナのシェルを操作できるようになります。
また、-d
オプションを付与することでコンテナをバックグラウンドで起動できます。
docker run -dit --name alpine1 alpine
$ docker run -dit --name alpine1 alpine
f7f1a42b2db0666f37b2fb43ec1c84c5ffa9e83a7dff5aad6edfccc66c547ef6
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f7f1a42b2db0 alpine "/bin/sh" 4 seconds ago Up 3 seconds alpine1
コンテナが起動できていることを確認できました。
続いて、bridgeの詳細を確認して先程のコンテナが接続されていることを確認します。
ネットワークの詳細はdocker network inspect {ネットワーク名}
で確認できます。
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "38bcf0d1750a68312400606aa88bd0dba5b4a6bbc3fd7c4a95875e46c80d93ea",
"Created": "2023-08-19T00:23:45.468693593+09:00",
"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": {
"f7f1a42b2db0666f37b2fb43ec1c84c5ffa9e83a7dff5aad6edfccc66c547ef6": {
"Name": "alpine1",
"EndpointID": "0da982bcb71279848ba59b144b69d0e2c806f95dbceced7f6aba6e79aa06cf8b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"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": {}
}
]
IPAM
の欄を見るとサブネットアドレスやデフォルトゲートウェイの情報が確認できます。
172.17.0.0/16
がこのブリッジ・ネットワークのサブネットアドレスになっていることが分かります。
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
Containers
の欄を確認すると、先ほど作成したalpine1
が接続されていることが分かります。
ipv4Address
を確認すると127.17.0.2
が割り振られていることが分かります。
"Containers": {
"f7f1a42b2db0666f37b2fb43ec1c84c5ffa9e83a7dff5aad6edfccc66c547ef6": {
"Name": "alpine1",
"EndpointID": "0da982bcb71279848ba59b144b69d0e2c806f95dbceced7f6aba6e79aa06cf8b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
図にするとこんな感じです。
複数コンテナ
続いて、デフォルトネットワークにコンテナを追加してみます。
$ docker run -dit --name alpine2 alpine
04bb63f52c335b470eb1f5d663ee9f354e3230929b8245ca5dbd555ee13f51d8
先ほどと同様、docker network inspect bridge
で詳細を確認すると以下のようになっています。
(Containersの欄のみ抜粋)
"Containers": {
"04bb63f52c335b470eb1f5d663ee9f354e3230929b8245ca5dbd555ee13f51d8": {
"Name": "alpine2",
"EndpointID": "5b715b50e0668207b29f1919b12968a3a1b0f3f68543cd1ec3b27248b3b38b57",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"f7f1a42b2db0666f37b2fb43ec1c84c5ffa9e83a7dff5aad6edfccc66c547ef6": {
"Name": "alpine1",
"EndpointID": "0da982bcb71279848ba59b144b69d0e2c806f95dbceced7f6aba6e79aa06cf8b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
alpine2が追加されていることが分かります。
図にすると以下のようになります。
続いて、alpine1とalpine2の間で通信が行えることを確認します。
docker attach {コンテナ名}
コマンドでコンテナのシェルにアタッチできます。
$ docker attach alpine1
/ #
ping
コマンドでalpine2(172.17.0.3
)に通信できることを確認します。
-c
コマンドでパケットを送信する回数を指定できます。
/ # ping -c 2 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.146 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.159 ms
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.146/0.152/0.159 ms
確認が終了したら、Ctrl + p
Ctrl + q
コマンドでコンテナのシェルからデタッチできます。
このとき、exit
コマンドなどを実行してしまうとコンテナがシャットダウンされてしまうので注意してください。
複数コンテナ・複数ネットワーク
docker network create --driver bridge {ネットワーク名}
コマンドでブリッジ・ネットワークが新規に作成できます。--driver
オプションはデフォルトでbridgeになっているので今回の場合は無しでも結果は変わりません。
$ docker network create --driver bridge alpine-net
c54fb5965e677cf26fceca357767eac4210c1a67c22959ae45362ed6648ff504
alpine-netが作られていることを確認します。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c54fb5965e67 alpine-net bridge local
38bcf0d1750a bridge bridge local
af1b8f32ee2a host host local
d1e9a5e4a34d none null local
続いて、先程作成したalpine-netにコンテナを追加します。
$ docker run -dit --name alpine3 --network alpine-net alpine
6b17f38ef3ac75b6828b518f2fc51f820cf3b3b2d856ab21da9f24655b786112
$ docker run -dit --name alpine4 --network alpine-net alpine
72333b1c452b2f49f9cc7edf73ceb8b2a5fcf82c44781c50395e340985d580dc
alpine-netにコンテナが追加されていることを確認します。
$ docker network inspect alpine-net
[
{
"Name": "alpine-net",
"Id": "c54fb5965e677cf26fceca357767eac4210c1a67c22959ae45362ed6648ff504",
"Created": "2023-08-19T14:08:07.355322927+09:00",
"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": {
"6b17f38ef3ac75b6828b518f2fc51f820cf3b3b2d856ab21da9f24655b786112": {
"Name": "alpine3",
"EndpointID": "9e7b579e6cee6c78b2925bd56e750cf8c7b43ddfc03bfbedc1cf376e6f8aa0ff",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
},
"72333b1c452b2f49f9cc7edf73ceb8b2a5fcf82c44781c50395e340985d580dc": {
"Name": "alpine4",
"EndpointID": "97d58ebe62e7955bf02aefffe7fa1625f7c24e85a762f30897d69bf952b57dcb",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
ここまでで作成したものを図にすると以下のようになります。
alpine3とalpine4の間で通信が行えることを確認します。
$ docker attach alpine3
/ # ping -c 2 172.19.0.3
PING 172.19.0.3 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.181 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.176 ms
--- 172.19.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.176/0.178/0.181 ms
また、ユーザが作成したブリッジ・ネットワークではコンテナ名による名前解決ができます。
試しにalpine3からalpine4に向けて、コンテナ名を指定してping
を実行してみます。
/ # ping -c 2 alpine4
PING alpine4 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.110 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.170 ms
--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.110/0.140/0.170 ms
デフォルトのブリッジ・ネットワークではコンテナ名による通信が行えません。
alpine1にアタッチして、alpine2に向けてコンテナ名を指定してping
を実行してみます。
$ docker attach alpine1
/ # ping -c 2 alpine2
ping: bad address 'alpine2'
通信に失敗しました。
異なるブリッジネットワーク間での通信も行うことができないため、alpine1とalpine3の通信やalpine2とalpine4の通信もできません。
試しにalpine3にアタッチして、alpine1(172.17.0.2
)に向けてping
を実行してみます。
$ docker attach alpine3
/ # ping -c 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
パケットが届いていないことが分かります。
今回は取り上げませんでしたが、単一のコンテナが複数のブリッジ・ネットワークに所属することも可能です。
その場合、複数のブリッジネットワーク内に存在するすべてのコンテナと通信ができるようになります。
まとめ
Dockerのブリッジ・ネットワークを作成し、コンテナ間の通信が行えることを確認しました。
参考
Discussion