ブリッジの一般的な意味。
ブリッジ(Bridge/L2スイッチ) ネットワークをデータリンク層で延長する装置
-- マスタリングTCP/IP 入門編 p38
コンテナから外部へはセグメントをまたぐ(例 docker0 172.16.0.0/16 から ホストのネットワーク 10.3.0.0/16)ためにパケット転送net.ipv4.ip.forward=1が使われて10.3.0.0/16から外にる際にIPマスカレード(NAT)が使われます。
// 有効
$ sudo sysctl -w net.ipv4.ip_forward=1
// 無効
$ sudo sysctl -w net.ipv4.ip_forward=0
Docker Network(例 172.16.0.0/16)がホストネットワーク(例 10.3.0.0/16)を通してが外部と通信できるのはnet.ipv4.ip.forwardが有効になっているため。
同じPCの場合net.ipv4.ip.forwardがtrueなら転送される。
https://tanke25616429.hatenablog.com/entry/2021/01/17/011553
ホストOSのnet.ipv4.ip.forwardはDockerが自動で有効化する。
コンテナのカーネルパラメータは起動後には変更できない。
変更するには起動時に--sysctlオプションで設定する。
$ docker run --sysctl net.ipv4.ip_forward=1 someimage
ref. 実行時に名前空間のカーネル・パラメータ(sysctl)を設定
IPマスカレードのわかりやすい記事。
http://blog.livedoor.jp/harukisan7/archives/17114894.html?utm_source=pocket_mylist
docker0とeth0は、DockerホストのOS機能であるiptablesによるIPマスカレードが行われています。
ホストのネットワークインターフェースdocker0とeth0はホストのiptablesでIPマスカレードを実現しています。
sudo iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.19.0.0/16 0.0.0.0/0
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
RETURN all -- 0.0.0.0/0 0.0.0.0/0
https://docs.docker.jp/engine/userguide/networking/default_network/binding.html
上記ドキュメントで分かりやすく解説されています。
コンテナが外部から内部への接続を受け付けたいならdocker runのpまたは--publishオプション、Docker Composeのportsプロパティでポートを公開します。
DockerがiptablesにDNATを追加します。
例えばNginxコンテナをrunするときにpオプションで8000を指定したときの例です(コンテナは172.17.0.2で稼働していると仮定します)。
$ docker run -d --name web -p 8000:80 nginx:latest
$ iptables -t nat -L -n
.....
Chain DOCKER-INGRESS (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.17.0.2:80
.....
任意の場所(0.0.0.0)からのポート8000でのアクセスを172.17.0.2のポート80に接続します。
bridgeネットワークに接続bridgeネットワークのネットワークインターフェースはdocker0^docker0bridgeネットワークに接続されたコンテナ間はIPアドレスで通信可能bridgeネットワークに接続されたコンテナ間はコンテナ名で通信不可(デフォルトのbridgeネットワークは内蔵DNSサーバを持たないため)bridgeネットワークに接続されたコンテナ間はコンテナ名で通信可能Docker Composeは、自動でbridgeネットワークを新規作成するのでservice名`[^service名]で通信可能[^service名]:Docker Composeは各コンテナをserviceと呼びます。
Dockerインストール時にデフォルトでネットワーク名がbridge、host、nullのネットワークが作成されます。
$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
abf0a3a6242a bridge bridge local <--- このネットワークのネットワークインターフェースがUbuntuはdocker0、Macはbridge0になります
5647050e2ccb host host local
f17799accf48 none null local
上述したとおりUbuntuの場合デフォルトで作成されるbridgeネットワークのネットワークインターフェースがdoker0になります(Macはbridge0)。
Docker のインストールは、自動的に3つのネットワークを作成します。
https://docs.docker.jp/engine/userguide/networking/dockernetworks.html
Docker をインストールした全ての環境には、 docker0 と表示されるブリッジ( bridge )ネットワークが現れます。オプションで docker run --net=<ネットワーク名> を指定しない限り、Docker デーモンはデフォルトでこのネットワークにコンテナを接続します。ホスト上で ifconfig コマンドを使えば、ホストネットワーク上のスタックの一部として、このブリッジを見ることができます。
https://docs.docker.jp/engine/userguide/networking/dockernetworks.html
$ docker inspect {{NETWORK ID}}
# コンテナのIPアドレス
$ docker inspect {{コンテナID or NAME}}
bridgeネットワークのネットワークインターフェースはdocker0になりますbridgeネットワークに接続されますホストは以下のネットワークインターフェースを持つと仮定します。
bridgeネットワークのネットワークインターフェースIPアドレス[^docker-ip]を使ったコンテナ間通信においてdocker0に発生するデータをキャプチャしてみます。
[^docker-ip]:サービス名で通信する場合はdocker0ではなく、docker network create {{network_name}}で作成したネットワークを設定してコンテナを起動します。
$ docker run -itd --name alpine-sample1 alpine:latest
$ docker run -itd --name sample-sample2 alpine:latest
コンテナのIPアドレスを確認します。
$ sudo docker exec -it alpine-sample1 /bin/sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
...
※ docker inspect alpine-sample1でも確認できます。
172.17.0.2です 172.17.0.3としますコンテナ間はdocker0で通信していることを確認します^docker0-2。
$ sudo tcpdump -tnl -i docker0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
alpine-sample1からalpine-sample2にpingを発行します。
$ docker exec -it alpine /bin/sh
/ # ping -c 1 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.110 ms
予想どおりdocker0に通信が発生しています。
$ sudo tcpdump -tnl -i docker0 icmp [15/84]
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
.....
IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 12, seq 0, length 64
IP 172.17.0.3 > 172.17.0.2: ICMP echo reply, id 12, seq 0, length 64
外部との通信を確認します。
例としてGoogleが提供するフルサービスリゾルバ8.8.8.8にpingを発行します。
$ sudo docker exec -it alpine-sample1 /bin/sh
/ # ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=101 time=3.000 ms
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 3.000/3.000/3.000 ms
予想どおりdocker0に通信が発生しています。
$ sudo tcpdump -tnl -i docker0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
.....
IP 172.17.0.2 > 8.8.8.8: ICMP echo request, id 27, seq 0, length 64
IP 8.8.8.8 > 172.17.0.2: ICMP echo reply, id 27, seq 0, length 64
加えてホストのデフォルトのネットワークインターフェースeth0にも通信が発生していることが分かります。
$ sudo tcpdump -tnl -i eth0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
...
IP 10.3.0.183 > 8.8.8.8: ICMP echo request, id 27, seq 0, length 64
IP 8.8.8.8 > 10.3.0.183: ICMP echo reply, id 27, seq 0, length 64
外部からコンテナにアクセスする際の通信をみます。
例としてhttpd:latestを稼働しているホストに外部からアクセスした際の通信をみます。
203.0.113.1192.0.2.1/24eth0 docker0172.17.0.4eth0203.0.113.150httpd:latestはifconfigがインストールされていないのでapt install net-toolsでインストールします。
$ sudo docker run -d -p 8000:80 --name httpd-sample httpd
クライアントのブラウザで http://203.0.113.1:8000 にアクセスします。
ホストのeth0の通信をみます。
クライアントとホストはポート8000番で通信しています。
$ sudo tcpdump -tnl -i eth0 tcp port 8000 [19/1972]
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 203.0.113.150.64640 > 192.0.2.1.8000: Flags [S], seq 218777360, win 65535, options [mss 1394,nop,wscale 6,nop,nop,TS val 3364579648 ecr 0,sackOK,eol], length 0
IP 192.0.2.1.8000 > 203.0.113.150.64640: Flags [S.], seq 1645943187, ack 218777361, win 65160, options [mss 1460,sackOK,TS val 2400436806 ecr 3364579648,nop,wscale 6], length 0
IP 203.0.113.150.64639 > 192.0.2.1.8000: Flags [.], ack 1, win 2051, options [nop,nop,TS val 1426504603 ecr 2400436806], length 0
ホストのdocker0の通信をみます。
コンテナとポート80番で通信しています。
$ sudo tcpdump -tnl -i docker0 tcp port 80 [19/1804]
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 203.0.113.150.64640 > 172.17.0.4.80: Flags [S], seq 218777360, win 65535, options [mss 1394,nop,wscale 6,nop,nop,TS val 3364579648 ecr 0,sackOK,eol], length 0
IP 172.17.0.4.80 > 203.0.113.150.64640: Flags [S.], seq 1645943187, ack 218777361, win 65160, options [mss 1460,sackOK,TS val 2400436806 ecr 3364579648,nop,wscale 6], length 0
IP 203.0.113.150.64639 > 172.17.0.4.80: Flags [.], ack 1, win 2051, options [nop,nop,TS val 1426504603 ecr 2400436806], length 0
コンテナのeth0の通信をみます。
予想どおりポート80番で通信しています。
# tcpdump -tnl -i eth0 tcp port 80
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 203.0.113.150.64640 > 172.17.0.4.80: Flags [S], seq 218777360, win 65535, options [mss 1394,nop,wscale 6,nop,nop,TS val 3364579648 ecr 0,sackOK,eol], length 0
IP 172.17.0.4.80 > 124.18.121.200.64640: Flags [S.], seq 1645943187, ack 218777361, win 65160, options [mss 1460,sackOK,TS val 2400436806 ecr 3364579648,nop,wscale 6], length 0
IP 124.18.121.200.64639 > 172.17.0.4.80: Flags [.], ack 1, win 2051, options [nop,nop,TS val 1426504603 ecr 2400436806], length 0
簡単ですが外部からのコンテナに対するアクセスついて確認しました。
https://cacoo.com/diagrams/0jEiiI3UonJoOn6D/C8EAD
bridgeネットワークを作成したときにホストに追加されるブリッジの仮想ネットワークインターフェースbridgeネットワークにコンテナを追加したときにホストに追加されるブリッジ側のネットワークインターフェースホストのネットワークインターフェースとルートテーブルを確認します。
ネットワークインターフェースを確認します。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
link/ether 06:b5:10:1f:21:cd brd ff:ff:ff:ff:ff:ff
inet 10.3.0.183/24 brd 10.3.0.255 scope global dynamic eth0
valid_lft 2700sec preferred_lft 2700sec
inet6 fe80::4b5:10ff:fe1f:21cd/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:bc:b0:20:a7 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
ルートテーブルを確認します。
$ ip route
default via 10.3.0.1 dev eth0 proto dhcp src 10.3.0.183 metric 100
10.3.0.0/24 dev eth0 proto kernel scope link src 10.3.0.183
10.3.0.1 dev eth0 proto dhcp scope link src 10.3.0.183 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
$ route -ne
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 10.3.0.1 0.0.0.0 UG 0 0 0 eth0
10.3.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.3.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
birdgeドライバのsampleネットワークを作成します。
$ sudo docker network create sample
29faca36a6b48487a16a1071c20dbe0b0b0bab3f6695d5d96324b80a9c3da773
ホストには仮想ブリッジが作成されて、仮想ブリッジのネットワークインターフェースが追加されます。ホストのネットワークインターフェースを確認します。
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
link/ether 06:b5:10:1f:21:cd brd ff:ff:ff:ff:ff:ff
inet 10.3.0.183/24 brd 10.3.0.255 scope global dynamic eth0
valid_lft 2360sec preferred_lft 2360sec
inet6 fe80::4b5:10ff:fe1f:21cd/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:bc:b0:20:a7 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
5: br-29faca36a6b4: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default <--- sampleの仮想ネットワークインターフェース
link/ether 02:42:c1:07:54:7f brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-29faca36a6b4
valid_lft forever preferred_lft forever
sampleを作成したことによってbr-29faca36a6b4が作成されて、ブリッジのネットワークインターフェースbr-29faca36a6b4(172.168.0.1)が追加されました。
(ブリッジとブリッジのネットワークインターフェースは同一名になっています)
ルートテーブルを確認します。
$ ip route
default via 10.3.0.1 dev eth0 proto dhcp src 10.3.0.183 metric 100
10.3.0.0/24 dev eth0 proto kernel scope link src 10.3.0.183
10.3.0.1 dev eth0 proto dhcp scope link src 10.3.0.183 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-29faca36a6b4 proto kernel scope link src 172.18.0.1 linkdown
$ route -ne
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 10.3.0.1 0.0.0.0 UG 0 0 0 eth0
10.3.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.3.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-29faca36a6b4
sampleネットワークにコンテナを追加します。 コンテナ名はcontainer1にします。
$ sudo docker run -itd --name container1 --net sample ubuntu:latest
daf864877355b6444832408add4afe7819c2e75446259aec9ca66ed399f692af
ホストにコンテナ(container1)とブリッジを接続するvethのブリッジ側ネットワークインターフェース(veth7a0c3b1@if6)が追加されています。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
link/ether 06:b5:10:1f:21:cd brd ff:ff:ff:ff:ff:ff
inet 10.3.0.183/24 brd 10.3.0.255 scope global dynamic eth0
valid_lft 1949sec preferred_lft 1949sec
inet6 fe80::4b5:10ff:fe1f:21cd/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:bc:b0:20:a7 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
5: br-29faca36a6b4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c1:07:54:7f brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-29faca36a6b4
valid_lft forever preferred_lft forever
inet6 fe80::42:c1ff:fe07:547f/64 scope link
valid_lft forever preferred_lft forever
7: veth7a0c3b1@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-29faca36a6b4 state UP group default <----- container1のネットワークインターフェース
link/ether 12:b9:a1:ec:09:76 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::10b9:a1ff:feec:976/64 scope link
valid_lft forever preferred_lft forever
sampleネットワークを確認します。
$ sudo docker network inspect sample
[
{
"Name": "sample",
"Id": "29faca36a6b48487a16a1071c20dbe0b0b0bab3f6695d5d96324b80a9c3da773",
"Created": "2022-06-08T11:33:26.165225737Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1" <--- ブリッジのIP
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"daf864877355b6444832408add4afe7819c2e75446259aec9ca66ed399f692af": {
"Name": "container1",
"EndpointID": "8233bb298d5fe7ef0d06af692a87c013677bdff42be7c22fbaa382105f3255c6",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
container1が追加されています。
コンテナを追加します。
$ sudo docker run -itd --name container2 --net sample ubuntu:latest
31abe1533cfed576910011ca990445da30dc641e2447ad63663b91175e52ea15
ホストにコンテナ(container2)とブリッジを接続するvethのブリッジ側ネットワークインターフェース(veth2a5f404@if8)が追加されています。
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
link/ether 06:b5:10:1f:21:cd brd ff:ff:ff:ff:ff:ff
inet 10.3.0.183/24 brd 10.3.0.255 scope global dynamic eth0
valid_lft 3439sec preferred_lft 3439sec
inet6 fe80::4b5:10ff:fe1f:21cd/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:bc:b0:20:a7 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
5: br-29faca36a6b4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c1:07:54:7f brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-29faca36a6b4
valid_lft forever preferred_lft forever
inet6 fe80::42:c1ff:fe07:547f/64 scope link
valid_lft forever preferred_lft forever
7: veth7a0c3b1@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-29faca36a6b4 state UP group default
link/ether 12:b9:a1:ec:09:76 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::10b9:a1ff:feec:976/64 scope link
valid_lft forever preferred_lft forever
9: veth2a5f404@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-29faca36a6b4 state UP group default <----- container2のネットワークインターフェース
link/ether 3a:aa:3b:e3:ed:9b brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::38aa:3bff:fee3:ed9b/64 scope link
valid_lft forever preferred_lft forever
sampleネットワークにコンテナが追加されています。
$ sudo docker network inspect sample
[
{
"Name": "sample",
"Id": "29faca36a6b48487a16a1071c20dbe0b0b0bab3f6695d5d96324b80a9c3da773",
"Created": "2022-06-08T11:33:26.165225737Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"31abe1533cfed576910011ca990445da30dc641e2447ad63663b91175e52ea15": {
"Name": "container2",
"EndpointID": "63366b86e00fae9705030e42606dd311807cd03330678d73372cb715d6b74d22",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"daf864877355b6444832408add4afe7819c2e75446259aec9ca66ed399f692af": {
"Name": "container1",
"EndpointID": "8233bb298d5fe7ef0d06af692a87c013677bdff42be7c22fbaa382105f3255c6",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
ブリッジbr-29faca36a6b4
$ brctl show br-29faca36a6b4
bridge name bridge id STP enabled interfaces
br-29faca36a6b4 8000.0242c107547f no veth2a5f404
veth7a0c3b1
apt install iproute2 ipコマンドapt install net-tools -y routeコマンドsudo docker exec -it container1 /bin/bash
root@daf864877355:/#
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
コンテナのネットワークインターフェースeth0@if7はブリッジのネットワークインターフェースveth7a0c3b1@if6とvethで接続。
ルートテーブルを確認。
$ route -ne
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 172.18.0.1 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
sudo docker exec -it container2 /bin/bash
root@31abe1533cfe:/#
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
コンテナのネットワークインターフェースeth0@if9とブリッジのネットワークインターフェースveth2a5f404@if8が仮想イーサネットで接続。
root@31abe1533cfe:/# route -ne
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 172.18.0.1 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
ホストのIPテーブルを見る。 ブリッジの仮想NICからホストの物理NICにIPマスカレードさえることを確認。
$ sudo iptables -t nat -nL -v
Chain PREROUTING (policy ACCEPT 21 packets, 1034 bytes)
pkts bytes target prot opt in out source destination
22 938 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 13 packets, 554 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 50 packets, 4834 bytes)
pkts bytes target prot opt in out source destination
0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 50 packets, 4834 bytes)
pkts bytes target prot opt in out source destination
8 480 MASQUERADE all -- * !br-29faca36a6b4 172.18.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- br-29faca36a6b4 * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
デフォルトのネットワークを再度確認してみます。
$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
abf0a3a6242a bridge bridge local <--- このネットワークのネットワークインターフェースがUbuntuはdocker0、Macはbridge0
5647050e2ccb host host local
f17799accf48 none null local
$ docker network create {{network_name}}
br-で始まるネットワーク・インターフェースがホストに作成されますdocker network lsで確認します例)
$ docker network create sample
$sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
abf0a3a6242a bridge bridge local
5647050e2ccb host host local
f17799accf48 none null local
8fe0215332a8 sample bridge local <--- 新規に作成
ホストでifconfigを発行してネットワークインターフェースを確認します。
br-8fe0215332a8が追加されていますbr-8fe0215332a8のIPアドレスは172.18.0.1です$ ifconfig
br-8fe0215332a8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 // <--- 追加
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
inet6 fe80::42:87ff:fe57:24b2 prefixlen 64 scopeid 0x20<link>
ether 02:42:87:57:24:b2 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 526 (526.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:37ff:fe8d:b952 prefixlen 64 scopeid 0x20<link>
ether 02:42:37:8d:b9:52 txqueuelen 0 (Ethernet)
RX packets 1392 bytes 85837 (85.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2875 bytes 13382135 (13.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 10.3.0.183 netmask 255.255.255.0 broadcast 10.3.0.255
inet6 fe80::4b5:10ff:fe1f:21cd prefixlen 64 scopeid 0x20<link>
ether 06:b5:10:1f:21:cd txqueuelen 1000 (Ethernet)
RX packets 66248 bytes 76218429 (76.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 96440 bytes 23585335 (23.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
netオプションで作成したbridgeネットワークを指定してコンテナを起動します。
$ sudo docker run -itd --name alpine-sample1 --net sample alpine:latest
$ sudo docker run -itd --name alpine-sample2 --net sample alpine:latest
alpine-sample1に入ってネットワークインターフェースのIPアドレスを確認してみます。
docker exec -it alpine-sample1 /bin/sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1392 (1.3 KiB) TX bytes:656 (656.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
IPアドレスは172.18.0.2です。
同様にalpine-sample2のネットワークインターフェースのIPアドレスは172.18.0.3です。
ネットワークをまとめると以下になります。
br-8fe0215332a8のIPアドレスは172.18.0.1ではネットワークインターフェースbr-8fe0215332a8の通信をキャプチャして使用を確認します。
$ sudo tcpdump -tnl -i br-8fe0215332a8 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-8fe0215332a8, link-type EN10MB (Ethernet), capture size 262144 bytes
コンテナ名alpine-sample2にアクセスします(デフォルトのbridgeネットワークインターフェースdocker0を使う場合はIPアドレスでしかアクセスできません)。
コンテナ名でアクセスできるのは、bridgeネットワーク(デフォルトのbridgeネットワークを除く)が内蔵DNSサーバを持っているからです^bridge-net。
デフォルトの「bridge0」という名称のブリッジ・ネットワークでは、この名前解決機能がありません。コンテナ間の通信でサービス・ディスカバリを有効化するには、自分でブリッジ・ネットワークを作成する必用があります。これをDockerではUser Defined Bridge Network(ユーザ定義ブリッジ・ネットワーク)と呼びます。
内蔵DNSサーバを使用してコンテナ名(Docker Composeではservice名)でアクセスする機能をサービス・ディスカバリと呼びます。
$ sudo docker exec -it alpine1 /bin/sh
/ # ping -c 1 alpine-sample2 // <------------------------ コンテナ名でPingを発行
PING alpine2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.103 ms
--- alpine-sample2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.103/0.103/0.103 ms
sudo tcpdump -tnl -i br-8fe0215332a8 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-8fe0215332a8, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 172.18.0.3 > 172.18.0.2: ICMP echo request, id 14, seq 0, length 64
IP 172.18.0.2 > 172.18.0.3: ICMP echo reply, id 14, seq 0, length 64
新規に作成したbridgeネットワークは内蔵DNSサーバ利用できます。
内蔵DNSはDocker デーモンが提供します。
Docker デーモンは内蔵 DNS サーバを動かし、ユーザ定義ネットワーク上でコンテナがサービス・ディスカバリを自動的に行えるようにします。コンテナから名前解決のリクエストがあれば、内部 DNS サーバを第一に使います。リクエストがあっても内部 DNS サーバが名前解決できなければ、外部の DNS サーバにコンテナからのリクエストを転送します。割り当てできるのはコンテナの作成時だけです。内部 DNS サーバが到達可能なのは 127.0.0.11 のみであり、コンテナの resolv.conf に書かれます。ユーザ定義ネットワーク上の内部 DNS サーバに関しては ユーザ定義ネットワーク用の内部 DNS サーバ をご覧ください。
-- https://docs.docker.jp/engine/userguide/networking/dockernetworks.html
上述のalpine-sample1コンテナにdigを入れて内蔵DNSサーバを確認します。
$ sudo docker exec -it alpine-sample1 /bin/sh
/ # apt update
/ # apk add --no-cache bind-tools // <---------------------- digをインストール
fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/main/x86_64/APKINDEX.tar.gz
.....
OK: 13 MiB in 29 packages
/ # dig alpine-sample2 // <------------------------ サービス・ディスカバリを見る
; <<>> DiG 9.16.27 <<>> alpine2
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35236
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;alpine-sample2. IN A
;; ANSWER SECTION:
alpine-sample2. 600 IN A 172.18.0.2
;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11) <---- 内蔵DNSサーバ
;; WHEN: Sat May 14 07:26:26 UTC 2022
;; MSG SIZE rcvd: 48
hostネットワークは文字通りホストとネットワークを共有します。
そのためネットワークインターフェースもホストのeth0を使用します(ホストのネットワークインターフェースがeth0の場合)。
hostネットワークの特徴は以下のとおりです。
hostネットワークは1つしか存在できないhostネットワークはDockerインストール時に作成されるのでユーザーは作成できない。hostネットワークを作成しようとするとエラーが発生する$ sudo docker network create -d host sample
Error response from daemon: only one instance of "host" network is allowed
$ sudo docker run -d --name httpd --net host httpd:latest
hostネットワークはホストのネットワークを共有するのでifconfigもホストと同じです。
ネットワークインターフェースもホストのeth0を使用します。
$ sudo docker exec -it httpd /bin/bash
root@ip-10-3-0-183:/usr/local/apache2# apt install net-tools // ifconfigインストール
....
root@ip-10-3-0-183:/usr/local/apache2# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:37ff:fe8d:b952 prefixlen 64 scopeid 0x20<link>
ether 02:42:37:8d:b9:52 txqueuelen 0 (Ethernet)
RX packets 1392 bytes 85837 (85.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2875 bytes 13382135 (13.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 10.3.0.183 netmask 255.255.255.0 broadcast 10.3.0.255
inet6 fe80::4b5:10ff:fe1f:21cd prefixlen 64 scopeid 0x20<link>
ether 06:b5:10:1f:21:cd txqueuelen 1000 (Ethernet)
RX packets 87575 bytes 94433872 (94.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 105846 bytes 24945855 (24.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 574 bytes 61238 (61.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 574 bytes 61238 (61.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ブラウザでアクセスするとeth0に通信が発生していることが確認できます(docker0には発生しない)。
$ sudo tcpdump -tnl -i eth0 tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 203.0.113.150.51221 > 10.3.0.183.80: Flags [S], seq 251437622, win 65535, options [mss 1394,nop,wscale 6,nop,nop,TS val 1967450493 ecr 0,sackOK,eol], length 0
IP 10.3.0.183.80 > 203.0.113.150.51221: Flags [S.], seq 3651188619, ack 251437623, win 62643, options [mss 8961,sackOK,TS val 14863613 ecr 1967450493,nop,wscale 6], length 0
IP 203.0.113.150.51222 > 10.3.0.183.80: Flags [.], ack 1, win 2051, options [nop,nop,TS val 1589689261 ecr 14863612], length 0
docker0には通信は発生していません。
sudo tcpdump -tnl -i docker0 tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
// ブラウザでアクセスしても通信は発生しない
/etc/hostname/に記載された名前。hostnameコマンドで確認できる。同一のユーザー定義bridgeネットワークでは、IPアドレス、サービス名、ホスト名で通信できる。
sudo docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd1d6037c81e httpd "httpd-foreground" 29 minutes ago Up 29 minutes 0.0.0.0:9000->80/tcp, :::9000->80/tcp web-httpd2
b44bfea6fb4d httpd "httpd-foreground" 48 minutes ago Up 48 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp web-httpd
2b4840ca369d nginx "/docker-entrypoint.…" 53 minutes ago Up 53 minutes 0.0.0.0:8000->80/tcp, :::8000->80/tcp web-nginx
Dockerの場合ホスト名はコンテナIDになる。 bd1d6037c81eにexecしてホスト名b44bfea6fb4dの80ポートからHTMLを取得する例。
root@bd1d6037c81e:/usr/local/apache2# curl --head b44bfea6fb4d:80
HTTP/1.1 200 OK
Date: Fri, 22 Jul 2022 23:53:54 GMT
Server: Apache/2.4.53 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html