- 最近 Docker ネットワークについて調べたので、内容をまとめました.
- Docker のバージョンは
20.10.12
です。 - 何かお気づきの点があればコメント頂けるとありがたいです。
抑えておきたいポイント・用語
- Docker ネットワークを理解する上で押さえておきたい用語や概念をまとめました
OSI 参照モデル
-
国際標準化機構(ISO)がコンピュータの通信方法を統一するために策定した規格
-
ネットワークを 7 階層に分け、各層のルール(プロトコル)を規定している
-
Docker のネットワークを理解する上で「第 2 層:データリンク層」「第 3 層:ネットワーク層 」を抑える必要がある
層 特徴 伝送単位 ネットワーク層(L3) IP アドレスをもとに、通信相手を識別する パケット データリンク層(L2) MAC アドレスをもとに、ネットワーク内の隣接する機器間の通信を制御する フレーム -
L3:ネットワーク層のデータの転送単位を「パケット」と呼び、「データ」+「ヘッダー(IPアドレス等)」から構成される
-
L2:データリンク層のデータの転送は「フレーム」と呼び、「パケット」+「ヘッダー(MACアドレス等)」から構成される
ブリッジ
- 複数のネットワーク・セグメントの中継器
- データリンク層(L2)で動作する
- どの端末のMACアドレスがどのセグメントに属するかを記憶している
- データを転送する時は、フレームの MAC アドレスを参照し、宛先の端末が属するセグメントにのみそのフレームを転送する。
- この時、送信対象のセグメントに属する全ての端末にフレームをブロードキャストする。送信されたフレームは、宛先の端末のみが処理し、それ以外の端末は無視する
仮想ブリッジ
- ホスト上に仮想的な L2 ネットワークを構成する機能
- Docker をインストールすると、ホストに
docker0
とい名前の仮想ブリッジが作成される
仮想NIC (veth)
- 仮想的なネットワークインターフェース
- コンテナを起動すると 下記の veth ペアが作成される
- ホストの仮想ブリッジに接続される veth
- コンテナに作成される NIC (実体は veth)
- コンテナとホストの通信はこのveth間で行われる
IPマスカレード
- グローバルIPアドレスとプライベートIPアドレスを変換する技術
- 1つのグローバルIPアドレスと複数のポート番号を組み合わせることで、複数のプライベートIPアドレスを変換できる
- NAPTとも呼ばれる
名前空間
- 各コンテナのネットワーク空間は独立している。コンテナが属するネットワーク空間を識別する概念。
Docker ネットワーク
- Dockerネットワークの概念図は以下
- ホストのNICに仮想ブリッジが接続される。Dockerが利用する仮想ブリッジのデフォルトは
docker0
- ホストの仮想ブリッジに仮想NIC(veth)が接続される
- ホストの仮想NIC(veth)とコンテナのNICが通信する
- 各コンテナのネットワークは分離している(名前空間が異なる)
- コンテナが外部と通信する際、コンテナのプライベートIPが、ホスト側のグローバルIPでIPマスカレードされる
Dockerネットワークの種類
bridge
- ホストの仮想ブリッジを利用するネットワーク
- Dockerをインストールすると、デフォルトで
bridge
という名前のbridgeネットワークが作成される -
docker network create
でDockerネットワークを作成する際、-d
オプションに未指定 またはbridge
を指定した場合、bridgeネットワークが作成される -
docker run
でコンテナを起動する際、--net
に未指定 またはbridge
を指定した場合、デフォルトのbridgeネットワークが利用される。- デフォルトの
bridge
に対応する仮想ブリッジはdocker0
- デフォルトの
host
- ホストの物理NICを直接利用して外部と接続するネットワーク (ホストとコンテナのネットワーク設定が同じ)
- Dockerをインストールすると、デフォルトで
host
という名前のhostネットワークが作成される
none
- コンテナをホストのネットワークに接続しない
- Dockerをインストールすると、デフォルトで
none
という名前で空のネットワークが作成される
docker-compose を利用する場合
-
docker-compose
でコンテナを起動する際、networks
を指定しなかった場合、<Composeファイルの配置先ディレクトリ>_default
という名前のbridgeネットワークが作成される - この時作成されるbridgeネットワークに対応する仮想ブリッジは、docker-composeでコンテナを起動した際、自動で作成される
-
docker-compose
で起動したコンテナをhost
ネットワークに接続する場合、network_mode
にhost
を指定する
動作検証1( docker コマンドを利用する場合)
ホストのDocker ネットワーク一覧
-
ホストに作成されているDockerネットワークを確認する。
docker network ls
を実行 -
結果は以下。bridge / host / none のネットワークが作成されていることがわかる
NETWORK ID NAME DRIVER SCOPE 64f5cef2d77d bridge bridge local f887f0e6ecc7 host host local 8d87bf258e89 none null local
ホストのネットワークを確認する
-
ip a
を実行。 -
結果は以下。docker0 仮想ブリッジが作成されていることがわかる
-
docker0に割り当てられているIPアドレスは
172.17.0.1/16
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:9b:df:82:32 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 <略>
コンテナを起動する
-
下記のコマンドでコンテナを起動する
docker run -d --name my-nginx -p 8081:80 nginx
ホストのDocker ネットワークの一覧
-
再度、ホストに作成されているDockerネットワークを
docker network ls
で確認する -
結果は以下。コンテナ起動前と同じ。新たなネットワークは作成されていない
NETWORK ID NAME DRIVER SCOPE 64f5cef2d77d bridge bridge local f887f0e6ecc7 host host local 8d87bf258e89 none null local
Docker ネットワークの確認
-
docker network inspect bridge
で、bridgeネットワークの詳細を確認する - 結果は以下の通り
- ゲートウェイアドレスが
172.17.0.1
で、docker0
に設定されているアドレスと一致している - コンテナには
172.17.0.2/16
のアドレスが割り振られている
- ゲートウェイアドレスが
$ docker network inspect bridge [
{
"Name": "bridge",
"Id": "1e38e4596ba1f79f4b29cfd865b0572e0dcda647eddb68d34639f0c6717b2393",
"Created": "2022-04-09T23:39:22.72754133Z",
"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": {
"eab19be6f0a5267829d26c93143214cc9b384383506439a7bbdc067e2a1196c5": {
"Name": "my-nginx",
"EndpointID": "6679fdcf5b08cde2019cbeb75cfa5f0a3cae8155087508be5c7c89317689ab1d",
"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": {}
}
]
コンテナのネットワークを確認する
-
docker exec -it
により、起動したコンテナにログインし、ip a
によりネットワーク設定を確認する - 結果は以下の通り。
(docker inspect
の実行結果から確認した)、コンテナに割り振られたIPアドレス172.17.0.2
がコンテナのNICのIPアドレスに設定されている
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
<略>
動作検証2( docker-compose を利用する場合)
確認用の docker-compose の作成
-
sample001 ディレクトリを作成し、下記の docker-compose ファイルを直下に配置する
services: nginx1: container_name: my-nginx1 image: nginx:latest ports: - 8081:80/tcp nginx2: container_name: my-nginx2 image: ngninx:latest ports: - 8082:80/tcp
docker-compose でコンテナを起動する
-
docker-compose up -d --build
を実行 - 結果は以下。
- デフォルトのドライバ設定(=bridge)で、
sample001_default
ネットワークを作成していることがわかる
Creating network "sample001_default" with the default driver Pulling nginx1 (nginx:latest)... : 略 : Status: Downloaded newer image for nginx:latest Creating my-nginx1 ... done Creating my-nginx2 ... done
- デフォルトのドライバ設定(=bridge)で、
Docker ネットワークの一覧
-
docker network ls
を実行。 - 結果は以下。
sample001_default
という bridge ネットワークが新たに作成されているNETWORK ID NAME DRIVER SCOPE 64f5cef2d77d bridge bridge local f887f0e6ecc7 host host local 8d87bf258e89 none null local a2808b008bb9 sample001_default bridge local ★ 新たに作成されたネットワーク
ホストのネットワークを確認する
-
ホストのネットワークを確認する。
ip a
を実行 -
結果は以下の通り。
- 仮想ブリッジ(16: br-f03cb12e5aff) と 仮想NICが2つ (18, 20:vetchXXX) 作成されている
- 各仮想NIC(vethXXXX)は仮想ブリッジ(br-f03cb12e5aff)に接続されている
16: br-f03cb12e5aff: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:69:48:b3:f7 brd ff:ff:ff:ff:ff:ff inet 172.20.0.1/16 brd 172.20.255.255 scope global br-f03cb12e5aff 略 18: vethe513542@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-f03cb12e5aff state UP group default link/ether ca:a3:f2:32:c4:bc brd ff:ff:ff:ff:ff:ff link-netnsid 0 略 20: veth251227c@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-f03cb12e5aff state UP group default link/ether 0a:7a:ad:98:98:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 1 略
ネットワークブリッジを確認する
-
brctl show
で、ホストのネットワークブリッジの設定を確認する -
結果は以下。
- 仮想ブリッジ(16: br-f03cb12e5aff)に仮想NIC(vethe513542/veth251227c)が接続されていることがわかる
bridge name bridge id STP enabled interfaces br-f03cb12e5aff 8000.02426948b3f7 no veth251227c vethe513542
Dockerネットワークの詳細を確認する
-
sample001_default
の詳細を確認する。docker network inspect sample001_default
を実行。 - 結果は以下の通り。
- サブネットは、172.20.0.0
- ゲートウェイは、172.20.0.1。これは、
docker-compose
で作成された仮想ブリッジ(br-5870201d8e2b)のIPアドレスと一致 - コンテナには、
172.20.0.3
と172.20.0.2
が設定されている。
[ { "Name": "sample001_default", "Id": "f03cb12e5affb4261fd8c8959596848b5d2b82efa9e0b7fd777446f74c27b8d7", "Created": "2022-04-10T08:58:16.43048963+09:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.20.0.0/16", "Gateway": "172.20.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "c2030004bc1daeb7b266715035fd9bbc4b97d03dc9c39199bb9ed04a00b43896": { "Name": "my-nginx1", "EndpointID": "9191d6c32b88b3642b95869084133e009e24f48e2c94bf79d670fa98a2295e5a", "MacAddress": "02:42:ac:14:00:03", "IPv4Address": "172.20.0.3/16", "IPv6Address": "" }, "e73a7929bc179c2e308674b1f71c722bf6f88ce7add8cb6db056a72dbd412dba": { "Name": "my-nginx2", "EndpointID": "590b155e49faab6ea091bb1f32af55241fa9d338250baa3f7dbaead29ce791c9", "MacAddress": "02:42:ac:14:00:02", "IPv4Address": "172.20.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": { "com.docker.compose.network": "default", "com.docker.compose.project": "sample001", "com.docker.compose.version": "1.25.0" } } ]
コンテナのネットワークを確認する
-
docker exec -it
で各コンテナに入り、ip a
でネットワークを確認する。 - 結果は以下の通り。
-
docker inspect
で表示されている通り、各コンテナに割り振られた IP アドレスが NIC に設定されている。
# コンテナ1(my-nginx1) 19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.20.0.3/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever
# コンテナ2(my-nginx2) 17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.20.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever
-
以上