docker のコンテナをホストと同じネットワークに所属させる備忘録です.
いつもの通り結論から言うと,
macvlan を使う
で良いみたいですね.ただし,いくつか注意しないといけないことがあるので,以下その辺りをつらつらと書きたいと思います.
macvlan ってなに?
いきなりですが,macvlan というのは docker 特有のものではなくて,linux kernel で実現される
物理インターフェース(eth0とか)に重ねて使う別の mac アドレスを持つ仮想インターフェース
のことみたいです.日本語の分かり易い記事は,
にあり,macvlan とよく似た ipvlan と合わせて説明してある記事が,英語ですが,
にあります(ipvlan の L2 モードだと同じ mac アドレスで通信できる.つまり L2 ブリッジを実現できるのが ipvlan の L2 モード).重ねて使うんだから,当然,同じホストと同じネットワークに所属することになるわけですね.
利点と欠点は以下の通り.
まず,利点は,
- 別の mac を持つので DHCP でアドレスを割り当てられる
- 実際の通信は物理インターフェースのドライバで行われるのでソフトウェアで行われる veth に比べパフォーマンスに優れる.
みたいで,逆に欠点は,
- eth0 との直接通信はできない(仕組み上の制限).
だそう.ただし,docker で使う場合は,DHCP でのアドレス割り当ては(普通は)できないので最初の利点はあるようでないです.
そして,macvlan には,通信可能範囲の違う以下の4つのモードがある.
- bridge: 同じインターフェースに割り当てた macvlan どうしが直接通信できる.
- vepa: bridge と同じだが,vepa 機能を持つ(物理)スイッチの NIC 経由で通信する.ハードウェア処理されるので高速に通信できる.
- passthru: macvlan で tup デバイス (macvtup) が使える.
- private: 上記が不可能なモード
使い方が分かりにくいのが passthru なんですが,これはどうも macvlan に複数の仮想マシン(コンテナ)のネットワークをブリッジさせるときなんかに使うようです.あと,面白いのが vepa だと思います.同じインターフェースに割り当てた macvlan どうしの直接通信の高速化をハードウェアで行うためのモードということで,「へー」という感じですね.
docker での使い方
docker で macvlan を使う方法は,
が公式みたいですね.docker だと今のところ bridge モードでしか作れない?みたい.以下,この記事に従って色々試してみた結果です.
まずは作り方.labohyt.local ネットワークを bridge モードで作る場合は,
$ docker network create -d macvlan --subnet=192.168.0.0/24 --ip-range=192.168.0.212/31 --gateway=192.168.0.1 -o parent=enp1s0 labohyt.local d496dc4398b0e4f063e37ec7be5f077aa3f6ded1510301d83ea2db91b2eedab4 $ docker network ls NETWORK ID NAME DRIVER SCOPE 34474c7ff0f2 bridge bridge local 2ef24b2b41b9 host host local d496dc4398b0 labohyt.local macvlan local 6a5d6d137792 none
みたいな感じでしょうか.
- -o parent=enp1s0
ってのは,関連づける物理インターフェースの名称を指定する部分です.ものによっては enp1s0 じゃなくて eth0 とかだと思います.VLAN を指定する場合は,
- -o parent=enp1s0.10
みたいにやれば良い.
あと注意点として,
- –ip-range=192.168.100.212/31
みたいにコンテナが使うアドレスの範囲を(使われていないアドレスの範囲に)制限しておくべきです.macvlan の仕組みから言ってホストマシンと同じネットワークを使うので下手をするとアドレスが被ってしまうからです.
では,実際に使ってみます.本家サイトと同じく alpine linux を使います.
$ docker run --rm -itd --network labohyt.local --name alpine1 alpine:latest ash e37d2432fedd5a61d68ca1cf7e96b311f5c4d6dfb042b75fc5adbb1c3632382b $ docker run --rm -itd --network labohyt.local --name alpine2 alpine:latest ash d85d7d92c10af6316f7b3d29d6ebc9718cb18c41a4048d258974a0004f98e718 $ docker exec alpine1 ip a show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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 12: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN link/ether 02:42:c0:a8:64:d4 brd ff:ff:ff:ff:ff:ff inet 192.168.0.212/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::00:00ff:fe00:00d4/64 scope link valid_lft forever preferred_lft forever $ docker exec alpine1 ip route show default via 192.168.100.1 dev eth0 192.168.0.0/24 dev eth0 scope link src 192.168.0.212 $ docker exec alpine2 ip a show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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 13: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN link/ether 02:42:c0:a8:64:d5 brd ff:ff:ff:ff:ff:ff inet 192.168.0.213/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:c0ff:fea8:64d5/64 scope link valid_lft forever preferred_lft forever
と言うことで,きちんと,192.168.0.212 と 192.168.0.213 に別の mac アドレスが割り当てられていることが分かります.次に通信可能な範囲を見てみます.
$ docker attach alpine1 / # ping -c 3 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=119 time=5.730 ms 64 bytes from 8.8.8.8: seq=1 ttl=119 time=5.825 ms 64 bytes from 8.8.8.8: seq=2 ttl=119 time=8.226 ms --- 8.8.8.8 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 5.730/6.593/8.226 ms / # ping -c 3 192.168.0.213 PING 192.168.0.213 (192.168.0.213): 56 data bytes 64 bytes from 192.168.0.213: seq=0 ttl=64 time=0.363 ms 64 bytes from 192.168.0.213: seq=1 ttl=64 time=0.258 ms 64 bytes from 192.168.0.213: seq=2 ttl=64 time=0.221 ms --- 192.168.0.213 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.221/0.280/0.363 ms / # ping -c 3 192.168.0.14 PING 192.168.0.14 (192.168.0.14): 56 data bytes --- 192.168.0.14 ping statistics --- 3 packets transmitted, 0 packets received, 100% packet loss
最後の 192.168.0.14 は docker のホストです.これも予想した通り,
- ホストの所属するネットワーク経由でインターネットのホスト(8.8.8.8)と通信できる.
- macvlan を利用するコンテナと通信できる.
- docker のホストとは通信できない(macvlan の制限事項).
となっています.
ナルホド.かなり素直な感じですね.
以上!