Dockerのbridgeドライバネットワークの通信について調べる

Pocket

Dockerのbridgeネットワークの覚書です。

検証環境

  • AWS EC2
  • Ubuntu 20.04.4 LTS (Focal Fossa)

bridgeネットワークの予備知識

  • Dockerはネットワークドライバがbridgehostnoneのネットワークがあります
  • 本記事ではネットワークドライバがbridgeのネットワークをブリッジネットワークと記載します
  • Dockerインストール時にデフォルトでbridgeというブリッジネットワークが作成されます
  • デフォルトのbridgeネットワークのネットワークインターフェースがdocker01になります
  • docker runなどでネットワークを指定しない場合は、コンテナはデフォルトのブリッジネットワークであるbridgeに配置されます

今回はブリッジネットワークを新規に作成して、Dockerネットワークの通信を見ていきます。

ネットワーク構成図

作成するネットワークは以下のようになります。

ネットワーク作成前を確認

まずは新規にネットワークを作成する前のホストのネットワークインターフェースとルートテーブルを確認しておきます。
以降コマンドの発行結果は本記事に直接関係のない内容を適宜省略しています。

ネットワークインターフェースを確認します。

$ 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
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
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

ネットワークインターフェースは3つです。

  • 1: lo: ループバック(127.0.0.1)のネットワークインターフェース
  • 2: eth0:デフォルトゲートウェイと接続された10.3.0.183/24のデフォルトのネットワークインターフェース
  • 4: docker0:Dockerをインストールした時に作成されるネットワークインターフェース(172.17.0.1/16

ルートテーブルを確認します。

$ 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

ネットワークを作成

新しくブリッジネットワークを作成します。
ネットワーク名はsampleにします。

$ sudo docker network create sample
29faca36a6b4...
  • ホストに仮想ブリッジ(br-29faca36a6b4)が作成されます
  • ホストに仮想ブリッジのネットワークインターフェース(br-29faca36a6b4)が作成されます

例ではブリッジとブリッジのネットワークインターフェースが同じ名前になっています。
ブリッジを確認します。

$ sudo brctl show
bridge name bridge id STP enabled interfaces
br-29faca36a6b4 8000.0242846801c8 no

ブリッジbr-29faca36a6b4が作成されています。
ネットワークインターフェースを確認します。

$ 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
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
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
5: br-29faca36a6b4: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 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

br-29faca36a6b4インターフェース(172.168.0.1)が追加されています。

ルートテーブルを確認します。

$ 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

ルートテーブルに172.18.0.0/16のルートが追加されています。

コンテナを追加(1つめ)

sampleネットワークにコンテナを追加します。
コンテナ名はcontainer1にします。

$ sudo docker run -itd --name container1 --net sample  ubuntu:latest
daf864877355...
$ sudo docker ps --all
CONTAINER ID   IMAGE           COMMAND   CREATED      STATUS          PORTS     NAMES
daf864877355   ubuntu:latest   "bash"    2 days ago   Up 58 minutes             container1

ネットワークインターフェースを確認します。

$ 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
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
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
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
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

ホストにコンテナ(container1)とブリッジを接続するveth(仮想イーサネット)のブリッジ側ネットワークインターフェースveth7a0c3b1@if6が追加されています。
(仮想イーサネットは両端にネットワークインターフェースを持つます。)

コンテナ内のネットワークインターフェースを確認します。

$ 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
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

コンテナにeth0@if7ネットワークインターフェースが作成されています。
eth0@if7ネットワークインターフェースはブリッジ側のveth7a0c3b1@if6ネットワークインターフェースと接続されています2

コンテナのルートテーブルを確認します。
ゲートウェイに172.18.0.1が設定されています。

$ 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

コンテナを追加(2つめ)

コンテナを追加します。
コンテナ名はcontainer2にします。

$ sudo docker run -itd --name container2 --net sample  ubuntu:latest
31abe1533cfe...
$ sudo docker ps --all
CONTAINER ID   IMAGE           COMMAND   CREATED      STATUS             PORTS     NAMES
31abe1533cfe   ubuntu:latest   "bash"    2 days ago   Up About an hour             container2

ネットワークインターフェースを確認します。

$ 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
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
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
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
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
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

ホストにコンテナ(container2)とブリッジを接続するvethのブリッジ側ネットワークインターフェース(veth2a5f404@if8)が追加されています。

コンテナ内のネットワークインターフェースを確認します。

$ 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

コンテナにブリッジのveth2a5f404@if8ネットワークインターフェースと接続されたeth0@if9が作成されていることが分かります。

コンテナのルートテーブルを確認します。
ゲートウェイに172.18.0.1が設定されています。

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

ブリッジを確認

コンテナを2つ追加したので、ブリッジbr-29faca36a6b4の現状を確認してみます。

$ brctl show br-29faca36a6b4
bridge name bridge id       STP enabled interfaces
br-29faca36a6b4     8000.0242c107547f   no      veth2a5f404
                                                                veth7a0c3b1

コンテナを2つ追加したのでブリッジとコンテナを繋ぐ2つのveth用のネットワークインターフェースがそれぞれveth2a5f404veth7a0c3b1として追加されています。

ここまででsampleネットワークに閉じた通信はブリッジおよびネットワークインターフェースを使って通信できるようになりました。

ネットワーク内通信を確認

container1からcontainer2にpingを発行してsampleネットワーク内の通信をみます。
ICMP echo requestパッケットは以下順番でネットワークインターフェースを通ってcontainer2に到達します。

  1. container1のeth0@if7ネットワークインターフェース
  2. ブリッジ側のcontainer1に対応するveth7a0c3b1@if6ネットワークインターフェース
  3. ブリッジのbr-29faca36a6b4ネットワークインターフェース
  4. ブリッジ側のcontainer2に対応するveth2a5f404@if8ネットワークインターフェース
  5. container2のeth0@if9ネットワークインターフェース

ICMP echo replyは逆の順序を通ってcontainer2からcontainer1に到達します。

ICMP echo request

参考までにtcpdumpでそれぞれのインターフェースの通信をキャプチャします。

1. container1のeth0@if7ネットワークインターフェースをキャプチャ

# tcpdump -tnl -i eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 1, seq 1, length 64

2. ブリッジ側のveth7a0c3b1ネットワークインターフェースをキャプチャ

$ sudo tcpdump -tnl -i veth7a0c3b1 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth7a0c3b1, link-type EN10MB (Ethernet), capture size 262144 bytes

IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 1, seq 1, length 64

3. ブリッジのbr-29faca36a6b4ネットワークインターフェースをキャプチャ

$ sudo tcpdump -tnl -i br-29faca36a6b4 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-29faca36a6b4, link-type EN10MB (Ethernet), capture size 262144 bytes

IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 2, seq 1, length 64

4. ブリッジ側のveth2a5f404ネットワークインターフェースをキャプチャ

$ sudo tcpdump -tnl -i veth2a5f404 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth2a5f404, link-type EN10MB (Ethernet), capture size 262144 bytes

IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 1, seq 1, length 64

5. container2のeth0ネットワークインターフェースをキャプチャ

# tcpdump -tnl -i eth0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 1, seq 1, length 6

birigeネットワークと外部との通信

最後にbridgeネットワークと外部の通信について確認します。

ブリッジネットワークは、(ブリッジネットワークの)br-29faca36a6b4ネットワークインターフェースからホストeth0ネットワークインターフェースを経由して外部と通信します。
IPマスカレードによってホストのIPに変換されまてホストのeth0から送信されます。

※ IPマスカレードはNATのLinuxの実装です。

iptableを確認してます。

$ 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

IPマスカレードの該当部分は以下のようになります。

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

外部への通信

container1から93.184.216.34(example.org)にpingを発行してsampleネットワークと外部との通信を確認します。

  1. container1のeth0@if7ネットワークインターフェース
  2. ブリッジ側のcontainer1に対応するveth7a0c3b1@if6ネットワークインターフェース
  3. ブリッジのbr-29faca36a6b4ネットワークインターフェース
  4. ホストのeth0ネットワークインターフェース

ICMP echo replyは逆の順序でcontainer2のeth0@if7ネットワークインターフェースに届きます。

ICMP echo request

1. container1のeth0@if7ネットワークインターフェースをキャプチャ

sudo docker exec -it container1 /bin/bash
root@daf864877355:/# tcpdump -tnl -i eth0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

IP 172.18.0.2 > 93.184.216.34: ICMP echo request, id 5, seq 1, length 64
IP 93.184.216.34 > 172.18.0.2: ICMP echo reply, id 5, seq 1, length 64

2. ブリッジ側のcontainer1に対応するveth7a0c3b1@if6ネットワークインターフェースをキャプチャ

$ sudo tcpdump -tnl -i veth7a0c3b1 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth7a0c3b1, link-type EN10MB (Ethernet), capture size 262144 bytes

IP 172.18.0.2 > 93.184.216.34: ICMP echo request, id 5, seq 1, length 64
IP 93.184.216.34 > 172.18.0.2: ICMP echo reply, id 5, seq 1, length 64

3. ブリッジのbr-29faca36a6b4ネットワークインターフェースをキャプチャ

sudo tcpdump -tnl -i br-29faca36a6b4 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-29faca36a6b4, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 172.18.0.2 > 93.184.216.34: ICMP echo request, id 8, seq 1, length 64
IP 93.184.216.34 > 172.18.0.2: ICMP echo reply, id 8, seq 1, length 64

4. ホストのeth0ネットワークインテーフェースをキャプチャ

IPマスカレードによってIPが10.3.0.183に書き換えられて送信。

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 > 93.184.216.34: ICMP echo request, id 9, seq 1, length 64
IP 93.184.216.34 > 10.3.0.183: ICMP echo reply, id 9, seq 1, length 64

以上となります。


  1. Macではbridge0になります(Macの場合も基本的な仕組みは同じですがコマンドの実行結果はことなります)。 

  2. eth0@if7@if7はホストの7のインターフェースであるveth7a0c3b1と接続という意味。逆にveth7a0c3b1@if6はコンテナの6`のインターフェースeth0と接続という意味。 

コメント

No comments yet.

コメントの投稿

改行と段落タグは自動で挿入されます。
メールアドレスは表示されません。