Docker Network - Network drivers
Native Network Drivers
まず以下では Docker Native Network Drivers について解説。
- bridge
- host
- overlay
- macvlan
- none
bridge
概要
デフォルトのネットワークドライバ。
Linux における network interface の bridge を利用する。
デフォルトでは、コンテナ同士は互いに通信可能。
以下を見ても分かる通り、 namespace が分離される。
イメージ図 ([1]より)

挙動
Linux bridge として docker0 という名前の bridge が作られる。 (Docker on Mac では異なる。[3])
コンテナ内部としては bridge driver に作られた eth0 に対して Docker native IPAM driver によりアドレスが与えられる。
※ IPAM Drivers
Docker は native IP Address Management Driver を持っている。
これによりデフォルトのサブネットやネットワークに対する IP アドレスが与えられる。また、 IP アドレスは手動でも設定が可能。
Remote IPAM drivers も存在しており、既存の IPAM tools との連携を提供している。
動作確認
アドレスが割り振られていることを確認可能。
host $ docker run -it --name c1 busybox sh
c1 # ip address
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
...
※ コンテナインターフェースの MAC アドレス
コンテナインターフェースの MAC アドレスは動的に割り当てられるが、衝突を避けるため IP アドレスを埋め込んだ形になる。
上の例では `ac:11:00:02` が `172.17.0.2` に対応する形となっている。
brctl コマンドにより、 Linux bridge の設定を確認できる。
docker0 は vetha3788c4 というインターフェースを 1 つだけ持っており、これが bridge とコンテナ内の eth0 の疎通性を提供している。
host $ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242504b5200 no vethb64e8b8
コンテナ内のルーティングテーブルを見ると、直接コンテナの eth0 、つまりは docker0 bridge にトラフィックを流している。
c1# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 src 172.17.0.2
As shown in the host routing table, the IP interfaces in the global network namespace now include docker0.
以下はホストのルーティングテーブルだが、 global network namespace が docker0 を含んでいることがわかる。
つまり、これにより docker0 と external な eth0 間の疎通性が提供され、コンテナ内部から external なネットワークへの通信を可能にしている。
host $ ip route
default via 172.31.16.1 dev eth0
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.42.1
172.31.16.0/20 dev eth0 proto kernel scope link src 172.31.16.102
User-Defined Bridge Networks
ホストに新しく bridge を作成することで、新たに user-defined ネットワークを追加できる。
デフォルトの bridge と異なり、 IP アドレスの手動設定やサブネットの設定をサポートする。

以下のような形で、特定のサブネットを持つネットワークを作成し、 IP アドレスを設定できる。
c2 については IPAM driver が IP addressing を行い、 c3 については自分で設定している。
$ docker network create -d bridge --subnet 10.0.0.0/24 my_bridge
$ docker run -itd --name c2 --net my_bridge busybox sh
$ docker run -itd --name c3 --net my_bridge --ip 10.0.0.254 busybox sh
brctl で 2 つ目の Linux bridge が見れる。
my_bridge は Linux bridge br-b5db4578d8c9 に対応しており、 c2 と c3 用の veth が 2 つ付いている。
$ brctl show
bridge name bridge id STP enabled interfaces
br-b5db4578d8c9 8000.02428d936bb1 no vethc9b3282
vethf3ba8b5
docker0 8000.0242504b5200 no vethb64e8b8
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b5db4578d8c9 my_bridge bridge local
e1cac9da3116 bridge bridge local
...
Use bridge networks
https://docs.docker.com/network/bridge/
External Access for Standalone Containers
デフォルトでは、同じ Docker network (multi-host swarm scope or local scope) に所属するコンテナはすべてのポートにおいて互いに疎通性がある。
bridge と overlay を含む多くの Docker ネットワークタイプでは、アプリケーションに対応する外部からの ingress については明示的に許可する必要がある。
これは、 internal portmapping により実現される。 Docker はホストのインターフェースに公開されているポートをコンテナ内部のインターフェースに伝える。
以下の図を例に説明する。

Egress について
- コンテナからの egress はデフォルトで許可されている
- コンテナから initiate されるコネクションはエフェメラルポートに masqueraded/SNATed される
- Return トラフィックについては許可される (引き続きエフェメラルポートが使われる)
Ingress について
- コンテナへの Igress は明示的に設定 (port publishing) することで提供される
- Port publishing は Docker Engine か、 UCP (Universal Control Plane) または Engine CLI から実施できる
- サービスまたはコンテナに対して特定のまたはランダムなポートを公開できる
- そのポートはホスト側のインターフェースで listen され、コンテナ内のポートとマッピングされる
External acces は --publish / -p にて設定される。
こんな感じ↓
$ docker run -d --name C2 --net my_bridge -p 5000:80 nginx
host
概要
host ドライバでは、ホスト側のネットワークスタックを利用する。
namespace の分離はなく、ホストのすべてのインターフェースはコンテナから直接利用可能になる。
イメージ的には Docker を使わないときのネットワーキングと同じ感じなので、理解しやすい。
挙動
基本的に他の networking drivers では、それぞれのコンテナは固有の namespace に所属しており、ネットワーク的には互いに隔離されたものになる。
host driver のコンテナはすべて同じ namespace に所属し、ホストと同じインターフェースを使い、ホストと同じ IP スタックを利用する。また、 host のインターフェースとも互いに疎通性が提供される。
ネットワーク的な観点から見ると、複数のプロセスがコンテナ無しで稼働してるのと同じような意味合いになる。なぜなら、それらは同じインターフェースを利用し、同じ TCP ポートに 2 つのコンテナが紐付けられることはないからである。そのため、 port の競合が発生する可能性もある。
動作確認
イメージ図 ([1]より)

#Create containers on the host network
$ docker run -itd --net host --name C1 alpine sh
$ docker run -itd --net host --name nginx
#Show host eth0
$ ip add | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
inet 172.31.21.213/20 brd 172.31.31.255 scope global eth0
#Show eth0 from C1
$ docker run -it --net host --name C1 alpine ip add | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP qlen 1000
inet 172.31.21.213/20 brd 172.31.31.255 scope global eth0
#Contact the nginx container through localhost on C1
$ curl localhost
!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
上の例に沿って説明する。
C1 と nginx コンテナは、ホストの eth0 を共有している。
host モードのコンテナは他のコンテナやホストに対して疎通性を持つ。また、コンテナ間の通信も localhost で実施が可能で、 C1 から nginx サーバを curl localhost で確認することもできる。
host モードでは、 Docker はポートマッピングやルーティングのルールなどを操作することはない。つまり、 host driver については -p や --icc といったオプションは意味を持たず、無視される。これにより、 host driver は最もシンプルでレイテンシの少ないものとなっている。コンテナ化されたプロセスであってもベアメタルのようなパフォーマンスを提供する。
host にフルアクセス可能な点や自動的にポリシーを管理できない点は、あまり一般的なユースケースにマッチしない。しかし、ハイパフィーマンスが要求される場合や、アプリケーションのトラブルシューティングには向いている。
Use host networking
https://docs.docker.com/network/host/
overlay
概要
multi-host な環境向けのネットワーク。
local Linux bridge と VXLAN を組み合わせて、物理的なネットワークを超えた範囲でコンテナ同士の疎通を行う。
挙動
コンテナの通信を VXLAN header でカプセル化することで、物理的な L2 または L3 ネットワークを横断することができる。物理的なトポロジにとらわれることなく、動的にまた簡単にネットワークを分けることができる。
また、標準の IETF VXLAN header を利用することで調査や分析を行いやすくしている。
VXLAN は Linux kernel 3.7 から組み込まれており、 Docker はネイティブの VXLAN を使っている。そのため、パフォーマンス面でも CPU のオーバヘッドやレイテンシが少ない。
※ IETF VXLAN
IETF VXLAN (RFC 7348) は L3 ネットワーク上に L2 のセグメントを重ねるような data-layer カプセル化フォーマットである。
VXLAN は通常の IP ネットワークで利用されることを想定されており、大規模でマルチテナントなネットワークを物理的なインフラストラクチャ上に構築できる。オンプレとクラウドを透過的に接続することも可能である。
RFC 7348
https://tools.ietf.org/html/rfc7348
※ VXLAN
L3 ネットワーク上に論理的な L2 ネットワークを構築するトンネリングプロトコル。
VXLAN は MAC-in-UDP カプセル化と定義される。つまり、 Docker の L2 フレームが underlay IP/UDP でカプセル化される。 underlay IP/UDP ヘッダは underlay ネットワークにおけるホスト間の通信を提供する。
overlay は、 overlay network 上のホスト間における point-to-multipoint な stateless VXLAN tunnel である。なぜなら overlay は underlay のトポロジやアプリケーションに依存しないので。
※ ちなみに Kubernetes の Flannel も VXLAN を使う。
FlannelのVXLANバックエンドの仕組み | めもめも
http://enakai00.hatenablog.com/entry/2015/04/02/173739
動作確認
イメージ図 ([1]より)

上のイメージ図を例とし、 overlay ネットワークを通って c1 から c2 にパケットを送信する状況をシミュレーションする。
- c1 は c2 の名前解決を行う。このとき、両方のコンテナは同じ overlay network にいるので Docker Engine の local DNS サーバは c2 の名前を overlay IP アドレスである 10.0.0.3 として返す。
- overlay network は L2 セグメントなので c1 は c2 の MAC アドレスを宛先とした L2 フレームを生成する。
- フレームは overlay network driver により VXLAN header でカプセル化される。 overlay control plane はそれぞれの VXLAN tunnel endpoint の場所やステートを管理しているので、 c2 が host-B で動いており、物理的なアドレスが 192.168.0.3 であることを知っている。
- カプセル化されたパケットが送出される。物理的なネットワークは正しいホストにパケットを送信する。
- パケットが host-B の eth0 に到達し、 overlay network driver により decapsulate される。 c1 から送信された、もとの L2 フレームは c2 の eth0 に渡され、そしてリッスンしているアプリケーションに渡される。
macvlan
概要
macvlan driver はコンテナのインターフェースとホストのインターフェース間のコネクションを MACVLAN bridge モードで確立するモードである。これは、物理的なネットワークからルーティング可能な IP アドレスをコンテナの IP として提供することができる機能である。
さらに、 VLAN を macvlan ドライバにトランキングして、 L2 コンテナのセグメンテーションを強制することができる。
MACVLAN はユニークな特徴や機能を多数備えている。
非常にシンプルで軽量なアーキテクチャで実現されているため、パフォーマンス面で非常にメリットがある。ポートマッピングを行うのではなく、 macvlan driver はコンテナと物理的なネットワークの直接的な接続を提供する。(概要にも記載したが、物理的なネットワークからルーティング可能な IP アドレスを、コンテナの IP アドレスとして利用できる)
ユースケースとしては以下のようなものが該当する。
- 非常にレイテンシの少ないアプリケーション
- コンテナが、外側のホストのネットワークと同じサブネットに所属している必要があるようなネットワーク構成
挙動
macvlan driver は親インターフェースの仕組みを利用する。このインターフェースは、物理的なインターフェースの eth0 や、 802.1q VLAN tagging たとえば eth0.10 (.10 representing VLAN 10) 用のサブインターフェース、または 2 つの Ethernet インターフェースを単一の論理インターフェースに紐付けた host adaptor のいずれも利用できる。
MACVLAN のネットワーク設定を利用する際はゲートウェイアドレスが必要となる。ゲートウェイアドレスは必ずホスト側のネットワークインフラストラクチャにより提供されるものでないとならない。
MACVLAN ネットワークは、同じネットワーク上のコンテナ間の疎通を可能にする。また、同じホスト上の異なる MACVLAN ネットワーク間については、ホストの外側にルーティングしないと通信できない。
動作確認
イメージ図 ([1]より)

上の例では、 MACVLAN ネットワークをホストの eth0 に紐づけている。また、それぞれのコンテナは mvnet という名前の MACVLAN ネットワークにアタッチされている。
それぞれのコンテナは 192.168.0.0/24 内の IP アドレス (つまり物理的なネットワークの subnet と同じ範囲) を持っており、またデフォルトゲートウェイは物理的なネットワークのインフラストラクチャ上にある。
#Creation of MACVLAN network "mvnet" bound to eth0 on the host
$ docker network create -d macvlan --subnet 192.168.0.0/24 --gateway 192.168.0.1 -o parent=eth0 mvnet
#Creation of containers on the "mvnet" network
$ docker run -itd --name c1 --net mvnet --ip 192.168.0.3 busybox sh
$ docker run -it --name c2 --net mvnet --ip 192.168.0.4 busybox sh
/ # ping 192.168.0.3
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.052 ms
VLAN Trunking with MACVLAN
Linux ホスト上に Trunking 802.1q を実現するのはかなり面倒。たとえば設定ファイルを変更して永続的に適用するにも reboot が必要になる。
もし bridge が絡んでると、物理的 NIC を bridge に移動するいつようがあり、その後 bridge は IP アドレスを取得する。
Docker の macvlan driver は、 sub-interfaces や、作成や削除また reboot を必要とする MACVLAN のコンポーネントについて管理を行う。
イメージ図 ([1]より)

macvlan driver がサブインタフェースによりインスタンス化されると、ホストと L2 のコンテナセグメントについて VLAN トランキングが可能になる。 macvlan driver は自動的にサブインターフェースを作成し、それらをコンテナーインターフェースに接続する。その結果、各コンテナは異なる VLAN に所属し、トラフィックが物理ネットワークでルーティングされない限り、コンテナ間の通信は不可能になる。
#Creation of macvlan10 network in VLAN 10
$ docker network create -d macvlan --subnet 192.168.10.0/24 --gateway 192.168.10.1 -o parent=eth0.10 macvlan10
#Creation of macvlan20 network in VLAN 20
$ docker network create -d macvlan --subnet 192.168.20.0/24 --gateway 192.168.20.1 -o parent=eth0.20 macvlan20
#Creation of containers on separate MACVLAN networks
$ docker run -itd --name c1--net macvlan10 --ip 192.168.10.2 busybox sh
$ docker run -it --name c2--net macvlan20 --ip 192.168.20.2 busybox sh
上記の設定では、サブインターフェイスを親インターフェイスとして使用するように設定した macvlan driver を使用して、 2 つの別々のネットワークを作成している。
macvlan driver はサブインターフェースを作成し、ホストの eth0 とコンテナインターフェースを接続する。
ホストのインターフェースと upstream switch は VLAN インターフェースをまたいでがタグ付けされるように switchport mode trunk に設定する必要がある。
1 つ以上のコンテナを特定の MACVLAN ネットワークに接続して、 L2 を介してセグメント化される複雑なネットワークポリシーを作成できる。
なお、複数の MAC アドレスが単一のホスト側のインターフェースに存在するために、 NIC の MAC フィルタリング設定によってはプロミスキャスモードを有効にしないといけない場合がある。
※ IEEE 802.1Q
IEEE 802.1 にて策定されているタグ VLAN の規格。
802.1Q は実際には元のフレームをカプセル化するわけではなく、その代わりに送信元 MAC アドレスのフィールドとイーサタイプ/長さのフィールドの間に 32 ビットのフィールドを追加する。
この VLAN タグフィールドは、初めの 16 ビットが TPID (Tag Protocol Identifier) 、次の 16 ビットは TCI (Tag Control Information) と呼ばれる。

- TPID (Tag Protocol Identifier)
IEEE 802.1Q によるタグ付きフレームであることを示すため、 0x8100 という値を置く 16 ビットのフィールド。 - PCP (Priority Code Point)
IEEE 802.1p で定義された優先度を指定する 3 ビットのフィールド。フレームの優先度を 0(最低)から 7(最高)で示し、各種トラフィック (音声、動画、データなど) の優先順位付けに利用できる。 - CFI (Canonical Format Indicator)
1 ビットのフィールドで、 1 であれば MAC アドレスは正規フォーマットではないことを示す。 0 であれば、 MAC アドレスは正規フォーマットである。イーサネットの場合は常に 0 である。これはイーサネットとトークンリングの相互接続時に使われる。イーサネットポートで CFI が 1 のフレームを受信した場合、そのフレームはタグ付けされていないポートへはブリッジされない。 - VID (VLAN Identifier)
12 ビットのフィールドで、そのフレームが属する VLAN を指定する。 0 の場合、どのVLANにも属していないことを意味し、そのよう な802.1Q タグは単なる優先度タグ (priority tag) として使われていることになる。
https://ja.wikipedia.org/wiki/IEEE_802.1Q
none
概要
none driver はコンテナ自身に固有のネットワークスタックおよび namespace を与える。また、コンテナ内のインターフェースについても何も設定しない。 追加で設定しない限り、コンテナは完全にホスト側ネットワークスタックから切り離される。
詳細
host driver と同様、基本的にネットワークの設定をとくに管理しないものである。
Docker エンジンはコンテナ内部に、インターフェース、ポートマッピング、疎通のためのルーティング設定などを作成しない。
コンテナが --net=none の設定を利用すると、完全に他のコンテナやホストから切り離された状態になる。そのため、管理者やツールはこのように切り離された状態を正しく管理しないといけない。
none を使うコンテナは、 loopback のみ持っており、他のインターフェースは持たない。
host driver と異なる点として、 none driver はそれぞれのコンテナで分離された固有の namespace を持つ。これにより、 host および他のコンテナから隔離されることを保証する。
Remote Network Drivers
- contiv
- weave
- calico
- kuryr
Ref docs
[1] Docker Reference Architecture: Designing Scalable, Portable Docker Container Networks
https://success.docker.com/article/networking
[2] Networking overview
https://docs.docker.com/network/
[3] Networking features in Docker Desktop for Mac
https://docs.docker.com/docker-for-mac/networking/
