DockerとIPv6
IPv6環境でDockerを使うときの使い方と実装の(一部の)説明です。
環境はCentOS7付属の1.8、IPv4での設定、操作が出来ることを前提としています。
現行バージョン(1.10)ではいくつか実装が異なりますので後述します。
公式ドキュメント
ドキュメントが公開されています
https://docs.docker.com/engine/userguide/networking/default_network/ipv6/
日本語はこちら
http://docs.docker.jp/engine/userguide/networking/default_network/ipv6.html
設計
アドレス空間
ドキュメントの記述では/80以上の空間を推奨しています。
これはLink local address同様の仕組みでMACアドレスからIPv6アドレスを生成しているためです。
※128(IPv6 len) - 48(MAC len) = 80
# ip addr show
・・・
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff
inet6 2001:db8:ffff::242:ac11:1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:1/64 scope link
valid_lft forever preferred_lft forever
MACアドレスとIPv6(2001:db8:ffff::/64)の下位が一致しています。
link localのアドレスバッティングを避けるために/80以上にするようですが、よほど広大なL2セグメントを作らない限りこれより小さいセグメントでも問題はありません。実際より/124などの小さいセグメントでも設定可能です。
またMACから生成されたlink localとは別にfe80::1/64がdocker0にアサインされます。
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:1d:5d:12:0b brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:1dff:fe5d:120b/64 scope link
valid_lft forever preferred_lft forever
inet6 fe80::1/64 scope link
ルーティング
ドキュメントに記述されているコンテナへのルーティングは
- routed(IPv6 nativeなルーティング)
- NDP Proxy(IPv4のproxy arp)
の二つです。
IPv6は全てのコンテナにグローバルアドレスを割り当ててもおつりがくるくらいのアドレス空間を持つことから、クライアントとコンテナはダイレクトに通信することを想定しているようです。
ポートフォワードも設定自体は出来ますがIPv4とは挙動が異なりますので後述します。
docker engine起動時のホスト側ルーティングテーブルは以下のようになります。
# ip -6 route show
2001:db8:1::/64 dev eno16780032 proto kernel metric 256
2001:db8:ffff::/64 dev docker0 metric 1024
fe80::/64 dev eno16780032 proto kernel metric 256
fe80::/64 dev docker0 proto kernel metric 256
コンテナ側はdefault-gateway-v6若しくは指定しない場合はfe80::1に向けられます。
# ip -6 route show
2001:db8:ffff::/64 dev eth0 proto kernel metric 256
fe80::/64 dev eth0 proto kernel metric 256
default via 2001:db8:ffff::1 dev eth0 metric 1024
パラメータ、設定内容など
ホスト
アドレスアサイン、フォワーディング、ルーティング、ゲートウェイ設定など、IPv6の一般的な設定が必要ですがOSとして設定することはアドレスくらいです。
docker engineがいろいろと設定してくれたりします。
Docker engine
コンテナに払いだすIPv6セグメント、ゲートウェイなどの設定を行います。
関連するパラメータ
--ipv6
IPv6の有効化。ホスト側のフォワーディングも設定されます。
※sysctl net.ipv6.conf.all.forwarding=1 相当--fixed-cidr-v6
コンテナにアサインするIPv6アドレスブロック--default-gateway-v6
コンテナに設定するdefault gateway
コンテナ
IPv6のプロトコルスタック自体はホスト側の実装をそのまま使いますのでイメージ側のアプリケーションがIPv6に対応するだけです。コンテナ側にネットワーク系のコマンド(ip, ifconfig, netstatなど)が入っていると確認が楽です。
docker hubのイメージならばIPv6関連コマンドが入っているubuntuが楽かもしれません。
設定
実際に設定してみます。
構成
以下のようなネットワークを想定してみます。
Docker engine
ホスト側の設定ファイル
OPTIONS='--selinux-enabled --ipv6 --fixed-cidr-v6="2001:db8:ffff::/64" --default-gateway-v6="2001:db8:ffff::1"'
CentOS7は標準でselinux-enabledが指定されていますが、必要に応じて変更して下さい。
ホスト
# ip -6 addr add 2001:db8:1::1/64 dev eth0
検証時にはfirewalldは止めておいた方がいいかと思います。
# systemctl stop firewalld
ルータ
IPv6アドレスは2001:db8:1::2/64とします。
2001:db8:ffff::/64へののルーティングの追加を忘れずに。
起動
ホストで以下のコマンドを投入
# systemctl start docker
# ip -6 addr add 2001:db8:ffff::1/64 dev docker0
# docker run -it ubuntu /bin/bash
それぞれ
- docker engineの立ち上げ
- docker0にIPv6アドレスをアサイン
- コンテナ起動
です。
docker engine起動時にdocker0の作成及びIPv4アドレスがアサインされますが、IPv6アドレスはアサインされないため手動で設定する必要があります。
疎通確認は立ち上げたコンテナのIPv6アドレスに対して、対向からping6などのIPv6用のコマンドで確認します。
# ip addr show
・・・
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 2001:db8:ffff::242:ac11:1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:1/64 scope link
valid_lft forever preferred_lft forever
> ping6 2001:db8:ffff::1
疎通できないときはfirewalld(iptables)、selinux、ルーティング、セグメント長、docker0へのアドレス付与忘れあたりを確認すればいいかと思います。
ポートフォワード
ドキュメントには記述がありませんがIPv6でポートフォワードも可能です。IPv6の場合はクライアント⇔コンテナがIPv6⇔IPv4のtranslateになります。
L3で変換されるためWebサーバなどではX-Forwardなどのヘッダは一切付加されません。
クライアントのIPv6アドレスが必要ならばホスト側でnginxなどのアプリケーションプロキシを立てる必要があります。
変換するのはホスト側のdocker-proxyになります。
ex. -p 8080:8080でコンテナを立ち上げた場合のホスト側のポートlisten状況
# netstat -anp|grep 8080
tcp6 0 0 :::8080 :::* LISTEN 12671/docker-proxy
外部からのリクエストはホスト側でIPv6として終端しコンテナ側にIPv4として渡されます。その際のソースアドレスはホスト側ブリッジ(docker0)のアドレスが使われます。
ex. コンテナで立ち上げたapacheのログ
192.168.0.2 - - [28/Jan/2016:00:20:53 +0000] "GET / HTTP/1.1" 200 12 "-" "curl/7.29.0"
172.17.42.1 - - [28/Jan/2016:00:21:32 +0000] "GET / HTTP/1.1" 200 12 "-" "curl/7.29.0"
上がIPv4クライアント(192.168.0.2)、下がIPv6でのログになります。
IPv6でアクセスするとdocker0(172.17.42.1)のアドレスを始点としたIPv4アドレスにtranslateされることが確認できます。
またIPv4の場合はホスト側のiptablesでコンテナへのnatが設定されますが、IPv6の場合はdocker-proxyプロセスがIPv6で受けコンテナ側IPv4へ転送されます。ip6tablesの設定は行われません。
# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere !loopback/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 anywhere
MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:webcache
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- anywhere anywhere tcp dpt:webcache to:172.17.0.2:8080
# ip6tables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
docker network
docker 1.9以降でネットワークまわりの機能が大幅に拡張されています。
しかしIPv6の対応状況はこれからという状況なので、現時点(2016/2, docker1.10)では
- IPv4ネットワークはdocker networkで一元管理
- IPv6ネットワークは自前管理、dockerで管理するのはコンテナだけ
というのが現実的な解になります。
またdocker engineもネットワークまわりで手が入ったためかパラメータ設定次第で動いたり動かなかったりと挙動が1.8以前と異なる点があり、ホスト側はそのままでは移行できない場合があります。
1.8以前と1.9以降との差分で確認している範囲では以下のものがあります
default-gateway-v6を指定するとdocker engineが起動しない
fixed-cidr-v6を設定すると、docker0に若番をアサイン、コンテナ側のdefault gatewayも指定されます。
ex. --fixed-cidr-v6=2001:db8:cccc::/80
# ip addr show
11: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:5a:b2:44:1d brd ff:ff:ff:ff:ff:ff
inet 172.17.0.16/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 2001:db8:cccc::1/80 scope global
# ip -6 route show
2001:db8:cccc::/80 dev eth0 proto kernel metric 256
fe80::/64 dev eth0 proto kernel metric 256
default via 2001:db8:cccc::1 dev eth0 metric 1024
ここでオプションに--default-gateway-v6に2001:db8:cccc::1を追加するとすでにアドレスがアサインされているとのメッセージが出力されdocker engineが起動しません。
docker0へのアドレスアサインが強制的に行われるため回避策としては以下のものが挙げられます
- default-gateway-v6を指定しなければfe80::1(docker0)が利用されるのでこちらを使う。
- aliasとして2001:db8:ffff::2などの別のIPv6を付与しこちらをgatewayに指定する(xxx::1でなければ起動可能)
- docker側ではなくホスト側のDHCPv6やRAなどからIPv6設定を行う
別途指定しなくてもルーティングは行われるので、1番目の「指定しない」というのが良いかもしれません。
その他
接続できないとき
アドレスやルーティングの追加はdocker engineがうまくやってくれますが削除に関しては原則行われないため、検証などでアドレスやセグメント長などを変更する場合、ホスト側のブリッジやルーティングテーブルが汚れてくるのでうまく動かないときはホストの再起動であっさりうまくいくことが多々あります。
設定コマンド
原則dockerコマンドのみで済ませるように設計すべきです。
ネットワークに限らず各リソース(name space)をdockerが独自に管理しているものがほとんどなので、docker管理外のコマンドで操作した場合、不整合が発生することが多々あります。
残念ながらIPv6に関しては未実装のものが多く外部コマンドの力を借りなければなりませんが、dockerが設定してしまうモノ・自前で設定するモノを把握したうえで各操作をする必要があります。
Author And Source
この問題について(DockerとIPv6), 我々は、より多くの情報をここで見つけました https://qiita.com/_norin_/items/7b9eac9fc31a8b02073f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .