【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 prune
IPアドレスの設定
ネットワークを作成する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 を使用する) |