概要
squidでActiveDirectory連携とSSLインターセプトするProxyをdockerで手軽につくる で、squid4.4の構築時に
squidがIPv6で自分自身にアクセスするため、dockerもIPv6を有効化する必要がありました。
手順と通信経路について整理します。
dockerエンジン・デーモンのIPv6化
以下のファイルを作成し、デーモンを再起動します。
IPv6の表記はドキュメント用なので、適宜修正ください。
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
すでに daemon.json
がある場合には、上記を追記してください。
systemctl restart docker
止めたくないから reload
してみたけど、反映されなかったので、 restart
しました。
参考:https://docs.oracle.com/cd/E77565_01/E87205/html/docker_install_upgrade_ipv6.html
Dockerネットワークとコンテナ
IPv6を有効化したネットワークを作成し、そこに生成したコンテナを参加させる。
# docker network create --ipv6 --driver=bridge --subnet=fd5a:ceb9:ed8d:1::/64 br_ipv6_nw \
-o com.docker.network.bridge.name="br_ipv6_nw"
# docker run --network br_ipv6_nw --name cnt01 -it -d centos:centos8 /bin/bash
Dockerネットワークの状態
# docker network inspect br_ipv6_nw
[
{
"Name": "br_ipv6_nw",
"Id": "ae1e90ac38bbdd208394922263053e8cfac4d31d6d6bbfecf50c345f18606e30",
"Created": "2020-02-24T18:36:33.239261559+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": true,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.26.0.0/16",
"Gateway": "172.26.0.1"
},
{
"Subnet": "fd5a:ceb9:ed8d:1::/64"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"286e2d07ab7a0d04f061ffbe4451f2a5d0a6553ad4cf6063ab21f7cdb4f40441": {
"Name": "cnt01",
"EndpointID": "d057150483d194c0e95eca386189482b431cff3b351411b01cb0394b92dd1852",
"MacAddress": "02:42:ac:1a:00:02",
"IPv4Address": "172.26.0.2/16",
"IPv6Address": "fd5a:ceb9:ed8d:1::2/64"
}
},
"Options": {
"com.docker.network.bridge.name": "br_ipv6_nw"
},
"Labels": {}
}
]
DockerホストとDockerコンテナのインターフェース
Dockerホスト
インターフェース
ホストのインターフェースIDはsubnetの最若番になる。
と、リンクローカルも最若番のfe80::1になる。
# ip add
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:62:2e:fa brd ff:ff:ff:ff:ff:ff
inet 10.254.10.252/24 brd 10.254.10.255 scope global noprefixroute ens192
valid_lft forever preferred_lft forever
inet6 fd5a:ceb9:ed8d:fe0a:ed57:61d8:20eb:aba5/64 scope global dynamic noprefixroute
valid_lft 2591966sec preferred_lft 604766sec
inet6 fe80::f7f9:b2ce:3e89:7281/64 scope link noprefixroute
valid_lft forever preferred_lft forever
75: br_ipv6_nw: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:c1:de:82:5c brd ff:ff:ff:ff:ff:ff
inet 172.26.0.1/16 brd 172.26.255.255 scope global br_ipv6_nw
valid_lft forever preferred_lft forever
inet6 fd5a:ceb9:ed8d:1::1/64 scope global tentative
valid_lft forever preferred_lft forever
inet6 fe80::1/64 scope link tentative
valid_lft forever preferred_lft forever
ルーティング(関係ないdocker0は除外しています)
デフォルトはens192の対向先
# ip -6 route | grep -v docker0
::1 dev lo proto kernel metric 256 pref medium
fd5a:ceb9:ed8d:1::/64 dev br_ipv6_nw proto kernel metric 256 pref medium
fd5a:ceb9:ed8d:fe0a::/64 dev ens192 proto ra metric 100 pref medium
fe80::/64 dev ens192 proto kernel metric 100 pref medium
fe80::/64 dev br_ipv6_nw proto kernel metric 256 pref medium
fe80::/64 dev veth671b926 proto kernel metric 256 pref medium
default via fe80::1 dev ens192 proto ra metric 100 pref medium
Dockerコンテナ
インターフェース
ホストのインターフェースIDはDockerホストから昇順での割り当ての模様。
と、リンクローカルはMACアドレスからの自動採番かな。
# docker exec -it cnt01 bash
[root@45b84c2182a5 /]# ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
82: eth0@if83: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1a:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.26.0.2/16 brd 172.26.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fd5a:ceb9:ed8d:1::2/64 scope global nodad
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe1a:2/64 scope link
valid_lft forever preferred_lft forever
ルーティング
デフォルトはULAのDockerホストになるみたい。
# ip -6 route
fd5a:ceb9:ed8d:1::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
default via fd5a:ceb9:ed8d:1::1 dev eth0 metric 1024 pref medium
疎通確認
ホスト → コンテナ の通信確認
# ping6 -c 1 fd5a:ceb9:ed8d:1::2 | grep icmp_seq
64 bytes from fd5a:ceb9:ed8d:1::2: icmp_seq=1 ttl=64 time=0.297 ms
# ping6 -c 1 fe80::1%br_ipv6_nw | grep icmp_seq
64 bytes from fe80::1%br_ipv6_nw: icmp_seq=1 ttl=64 time=0.195 ms
コンテナ → ホスト の通信確認
# ping6 -c 1 fd5a:ceb9:ed8d:1::1 | grep icmp_seq
64 bytes from fd5a:ceb9:ed8d:1::1: icmp_seq=1 ttl=64 time=0.114 ms
# ping6 -c 1 fe80::1 | grep icmp_seq
64 bytes from fe80::1%eth0: icmp_seq=1 ttl=64 time=0.129 ms
コンテナ → ホスト → 外部 の通信確認
# ping6 -c 1 dns.google | grep icmp_seq
64 bytes from dns.google (2001:4860:4860::8844): icmp_seq=1 ttl=52 time=6.74 ms
通信経路
概略
dns.google に ping6 したとき、以下のように通信を行います。
HOSTではIPマスカレードして、srcアドレスをHOSTのアドレスに置き換えます。
GATEWAYでは、fd5a:ceb9:ed8d:fe0a::/64 を ROUTINGPREFIX:ff66/64 にNPTv6 しています。
HOSTの設定と動作
DockerホストのIPマスカレードは firewall-cmd --masquerade --zone=public --permanent
により以下のルールが追加されています。
# nft list chain ip6 firewalld nat_POST_public_allow
table ip6 firewalld {
chain nat_POST_public_allow {
oifname != "lo" masquerade
}
}
これによりコンテナからのパケットはホストでSNATされます。
conntrackで確認すると、以下のようになっています。
# conntrack -E -p icmpv6
[NEW] icmpv6 58 30 src=fd5a:ceb9:ed8d:1::2 dst=2001:4860:4860::8888 type=128 code=0 id=38 [UNREPLIED] src=2001:4860:4860::8888 dst=fd5a:ceb9:ed8d:fe0a:ed57:61d8:20eb:aba5 type=129 code=0 id=38
[UPDATE] icmpv6 58 30 src=fd5a:ceb9:ed8d:1::2 dst=2001:4860:4860::8888 type=128 code=0 id=38 src=2001:4860:4860::8888 dst=fd5a:ceb9:ed8d:fe0a:ed57:61d8:20eb:aba5 type=129 code=0 id=38
ROUTERの設定と動作
ROUTERのルーティングは以下のように設定されています。
(なんでfe80::1にしなかったんだっけ。。。)
Rdc01#sh run | in ::/0
ipv6 route ::/0 Vlan252 FD5A:CEB9:ED8D:FEFC::1
GATEWAYの設定と動作
GATEWAYのインターフェースは以下のように設定されています。
(いまだにCLI使いこなせない。。。)
admin@FWdc01> show interface all
(~省略~)
ethernet1/1.999 271 1 zUntrust vr:default 999 192.168.1.250/24
fe80::b60c:25ff:fe0f:df10/64
ROUTINGPREFIX:ffff:192:168:1:250/64
fe80::192:168:1:250/128
(~省略~)
ethernet1/2.252 260 1 zTrust vr:default 252 10.254.252.1/24
fe80::b60c:25ff:fe0f:df11/64
fd5a:ceb9:ed8d:fefc::1/64
fe80::1/128
(~省略~)
GATEWAYのNPTv6は以下のように設定されています。
本当は Prefix64bit ごとに NPTv6のトランスレータを準備しないといけないのですが、手抜きで2セグをまとめています。
"nat66_NPTv6_to_internet; index: 1" {
nat-type nptv6;
from zTrust;
source [ fd5a:ceb9:ed8d:fe0a:0:0:0:0/64 fd5a:ceb9:ed8d:fefc:0:0:0:0/64 ];
to zUntrust;
to-interface ethernet1/1.999 ;
destination any;
service 0:any/any/any;
translate-to "src: ROUTINGPREFIX:ff66:0:0:0:0/64 (static-ip) (pool idx: 0)";
terminal no;
}
これによりパケットはGATEWAYでSNATされます。
NAT後のトラフィックログは、以下のようになっています。
(CLIの確認方法がわからなかった。。。)