単一ホスト内での Docker のネットワークの仕組みをまとめてみる。
全体像
まず、Docker のネットワークは以下の図ような構成になっている。
ざっとポイントをまとめるとこんな感じ。
- ホストには docker0 という仮想ブリッジが作成される
- コンテナは veth を介して仮想ブリッジに接続される
- コンテナ内からは eth0 というNIC があるように見える(実体は veth)
- コンテナ内の eth0 には、空いているIPアドレスが自動で割り当てられる(なので、IPアドレスは不定)。
- コンテナからホストの外部に通信するには、NAT(IPマスカレード)が使われる
- 単一ホスト上のコンテナ間の通信は、仮想ブリッジを経由して行われる(なので、コンテナ内で見える 172.17.0.0/16 のアドレスを使って通信できる)
もう少し詳しく
分からないところを調べてみた。
仮想ブリッジ
Linux 上に仮想的なL2スイッチを構成する機能(VMware ESXi でいえば、仮想スイッチのことかな)。Docker をインストールしたLinuxホストでは docker0 という仮想ブリッジが作られる。
# インターフェイスの表示
$ ifconfig -a
docker0 Link encap:Ethernet HWaddr 56:84:7A:FE:97:99
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
(略...)
eth0 Link encap:Ethernet HWaddr 06:D8:0E:5D:B8:C9
inet addr:10.0.0.73 Bcast:10.0.0.255 Mask:255.255.255.0
(略...)
# 仮想ブリッジの情報を表示してみる。
$ sudo yum install bridge-utils
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.56847afe9799 no
veth
veth とは、仮想的なネットワークインターフェース(仮想NIC)。ただ、単純な仮想NICではなく、veth を作成すると2つの仮想NICのペアができ、この2つの間で通信ができるようになる(2つのNICをクロスケーブルで直結して通信する感じ)。
2つの veth のうち、1つはコンテナのネットワーク名前空間に入れられて、コンテナ内からのみ見えるようになる。また、名前も、コンテナ内では veth から eth0 に変更されている。
もう1つの veth は、ホスト側の仮想ブリッジ(docker0)に接続される。
コンテナを起動した後、ホストからは以下のように veth が作られていることが見れる。
$ ifconfig -a
docker0 Link encap:Ethernet HWaddr 56:84:7A:FE:97:99
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
(略...)
eth0 Link encap:Ethernet HWaddr 06:D8:0E:5D:B8:C9
inet addr:10.0.0.73 Bcast:10.0.0.255 Mask:255.255.255.0
(略...)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
(略...)
# コンテナを起動したら作成された(ホスト側の veth)
vethbe8a6db Link encap:Ethernet HWaddr E6:B0:26:46:48:C6
inet6 addr: fe80::e4b0:26ff:fe46:48c6/64 Scope:Link
UP BROADCAST RUNNING MTU:9001 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:508 (508.0 b) TX bytes:438 (438.0 b)
# たぶん、ホスト側の veth が仮想ブリッジ(docker0)に接続されていることを表している
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.56847afe9799 no vethbe8a6db
また、コンテナ内からは eth0 が見える。そして、Default Gateway(DGW) は、ホスト側の docker0 の IPアドレスになっており、この DGW を経由して NAT で外部と通信することになる。
# ifconfig -a
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
(略...)
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.17.42.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 * 255.255.0.0 U 0 0 0 eth0
コンテナへのIPアドレスの割り当て
コンテナには、Docker が管理しているアドレス空間から空いている(使われていない)IPアドレスが自動で割り当てられる。なので、コンテナ内のIPは不定となる。
そのため、同一ホスト上に2つのコンテナがあるとして、一方から他方に通信したい場合は、リンクの機能 を使って接続先のIPアドレスを取得し、接続するという方法を取ることになる。
参考サイト
KVMで始めるプライベート・クラウドへの第一歩
第6回 Linuxカーネルのコンテナ機能[5] ─ネットワーク
Docker入門: コンテナ型仮想化技術の仕組みと使い方