Dockerのネットワーク構成

Dockerのネットワーク構成について整理する。

図1: Dockerネットワーク全体図

http://d.hatena.ne.jp/miyakawa_taku/files/2017-01-10_dockernw-01-whole.png?d=.png

物理NICが1個ついたDockerホストに2つのコンテナを立てると、図1のようになる。コンテナは172.17.X.Xのネットワーク内にいて、ホスト側には172.17.0.1のIPアドレスが付く。この構成自体は、VirtualBoxで言うところのホストオンリーネットワークと同じようなもの。異なる点として、Dockerネットワークは、ハードウェア仮想化ではなく、Linuxカーネルの機能であるvethペアとブリッジを組み合わせて実現される。

図2: vethペア

http://d.hatena.ne.jp/miyakawa_taku/files/2017-01-10_dockernw-02-veth.png?d=.png

veth (virtual Ethernet) は、図2のように、仮想NICのペアと、それをつなぐ仮想ケーブルを作る機能。ふたつの仮想NICイーサネットで直接通信できる。

図3: ブリッジ

http://d.hatena.ne.jp/miyakawa_taku/files/2017-01-10_dockernw-03-bridge.png?d=.png

ブリッジとは、LinuxマシンがL2スイッチ(スイッチングハブ)として動作するように構成する機能。図3のように、ブリッジに紐付けられたNICは仮想L2スイッチのポートとなり、それぞれのNICにつながったホスト同士はイーサネットで通信できる。NICをブリッジに紐付けると、そのMACアドレスを使ったイーサネット通信はできなくなり、またIPアドレスを割り当てることもできなくなる。その代わり、ブリッジに対してMACが割り当てられるので、ブリッジを構成したホスト(図中のBridger Host)は、ブリッジのMACを使って、各NICの対向にいるホストとイーサネットで通信できる。

Bridger Host / Other Host 1 / Other Host 2は、イーサネットで相互に通信できるので、ひとつのネットワークセグメントが構成できる。

図4: Dockerネットワーク全体図(詳細)

http://d.hatena.ne.jp/miyakawa_taku/files/2017-01-10_dockernw-04-whole-detailed.png?d=.png

再度全体図に戻ると(図4)、Dockerホスト内にはひとつのブリッジが構成されて、そのMACIPアドレス172.17.0.1が割り当てられる。また、コンテナごとに1つのvethペアが構成されて、片方の仮想NICはブリッジに紐付けられる。もう片方の仮想NICには172.17.X.XのIPアドレスが割り当てられて、コンテナに所属させられるもう片方の仮想NICはコンテナに所属させられて、172.17.X.XのIPアドレスが割り当てられる *1。vethペアは相互に通信でき、ホスト側の仮想NICはブリッジにつながっているので、ブリッジを通じてコンテナ/コンテナ間、コンテナ/ホスト間のイーサネット通信ができる。したがって、これらをまとめてひとつのネットワークセグメントとできる。

ホスト側でifconfigコマンドを普通に実行しても、コンテナに所属する仮想NICは見えない。また、ホスト側のプロセスがそのNICに紐付けられたIPアドレスを使って通信することも、普通にはできない。一方、コンテナ内のプロセスから見えるのは、コンテナに紐付けられた仮想NICだけで、たとえばホストの物理NICは見えない。これは、Linuxのネットワーク名前空間機能によって実現されている。コンテナごとにネットワーク名前空間がひとつ作られ、各コンテナ内のプロセスはこの名前空間上で実行される。仮想NICは、ホスト側のデフォルトの名前空間からコンテナの名前空間に移動されることによって、コンテナに所属する。ホストのシェルからコンテナに所属するNICを見るためには、netnsコマンドやnsenterコマンドで名前空間を切り替える。

ルーティング、NAPT、ポートフォワーディングは、Linuxカーネルのルーティング機能をそのまま使う。ここについては、Docker特有の論点も仮想化特有の論点もないと思う。

参考文献:

*1:2017-01-28に修正。IPアドレスの割り当てはコンテナのネットワーク名前空間で行われるため、元の記述は不正確でした。