可公开路由的 IPv6 linux 容器

daa*_*aku 7 ipv6 containers docker

我的目标是为我的每个 docker 容器拥有一个可路由的公共 IPv6 地址。我希望能够使用 IPv6 协议连接进出我的容器。

我正在使用 Linode 并且我被分配了一个公共 IPv6 池:

2600:3c01:e000:00e2:: / 64 routed to 2600:3c01::f03c:91ff:feae:d7d7
Run Code Online (Sandbox Code Playgroud)

该“路由到”地址是由 dhcp 自动配置的:

# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591987sec preferred_lft 604787sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

我设置了 AAAA 记录,ipv6.daaku.org以便更轻松地使用:

# nslookup -q=AAAA ipv6.daaku.org
ipv6.daaku.org  has AAAA address 2600:3c01:e000:e2::1
Run Code Online (Sandbox Code Playgroud)

为了测试,我手动分配了该地址:

# ip -6 addr add 2600:3c01:e000:00e2::1/64 dev eth0
# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01:e000:e2::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591984sec preferred_lft 604784sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

我现在可以从启用了 IPv6 的家庭网络 ping 这个:

# ping6 -c3 ipv6.daaku.org
PING6(56=40+8+8 bytes) 2601:9:400:12ab:1db7:a353:a7b4:c192 --> 2600:3c01:e000:e2::1
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=0 hlim=54 time=16.855 ms
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=1 hlim=54 time=19.506 ms
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=2 hlim=54 time=17.467 ms

--- ipv6.daaku.org ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 16.855/17.943/19.506/1.133 ms
Run Code Online (Sandbox Code Playgroud)

我删除了地址,因为我只想要它在容器中,然后回到原来的状态:

# ip -6 addr del 2600:3c01:e000:00e2::1/64 dev eth0
# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591987sec preferred_lft 604787sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

我在另一个终端中启动了一个没有网络的 docker 容器:

# docker run -it --rm --net=none debian bash
root@b96ea38f03b3:/#
Run Code Online (Sandbox Code Playgroud)

将其 pid 卡在一个变量中以便于使用:

CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' b96ea38f03b3)
Run Code Online (Sandbox Code Playgroud)

为该 pid 设置 netns:

# mkdir -p /run/netns
# ln -s /proc/$CONTAINER_PID/ns/net /run/netns/$CONTAINER_PID
Run Code Online (Sandbox Code Playgroud)

创建了一个新设备,为其分配了 IP:

# ip link add container0 link eth0 type macvlan
# ip link set container0 netns $CONTAINER_PID
# ip netns exec $CONTAINER_PID ip link set dev container0 name eth0
# ip netns exec $CONTAINER_PID ip link set eth0 up
# ip netns exec $CONTAINER_PID ip addr add 2600:3c01:e000:00e2::1/64 dev eth0
Run Code Online (Sandbox Code Playgroud)

回到我启动容器的另一个终端:

# ip -6 addr show eth0
22: eth0@gre0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500
    inet6 2600:3c01::a083:1eff:fea5:5ad2/64 scope global dynamic
       valid_lft 2591979sec preferred_lft 604779sec
    inet6 2600:3c01:e000:e2::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::a083:1eff:fea5:5ad2/64 scope link
       valid_lft forever preferred_lft forever

# ip -6 route
2600:3c01::/64 dev eth0  proto kernel  metric 256  expires 2591976sec
2600:3c01:e000:e2::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
default via fe80::1 dev eth0  proto ra  metric 1024  expires 67sec
Run Code Online (Sandbox Code Playgroud)

这不起作用,我无法从容器连接(ping6 ipv6.google.com用作我的测试),也无法从我的家庭网络通过 Internet ping 容器(ping6 ipv6.daaku.org用作我的测试)。

更新:我设法通过这样做使传出IPv6 工作:

ip -6 addr add 2600:3c01:e000:00e2::1111:1/112 dev docker0 &&
ip6tables -P FORWARD ACCEPT &&
sysctl -w net.ipv6.conf.all.forwarding=1 &&
sysctl -w net.ipv6.conf.all.proxy_ndp=1

CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' 4fd3b05a04bb)
mkdir -p /run/netns &&
ln -s /proc/$CONTAINER_PID/ns/net /run/netns/$CONTAINER_PID &&
ip netns exec $CONTAINER_PID ip -6 addr add 2600:3c01:e000:00e2::1111:20/112 dev eth0 &&
ip netns exec $CONTAINER_PID ip -6 route add default via 2600:3c01:e000:00e2::1111:1 dev eth0
Run Code Online (Sandbox Code Playgroud)

主机上的 IPv6 路由:

# ip -6 r
2600:3c01::/64 dev eth0  proto kernel  metric 256  expires 2582567sec
2600:3c01:e000:e2::1111:0/112 dev docker0  proto kernel  metric 256
2600:3c01:e000:e2::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev docker0  proto kernel  metric 256
fe80::/64 dev veth1775864  proto kernel  metric 256
fe80::/64 dev veth102096c  proto kernel  metric 256
fe80::/64 dev vethdf3a55b  proto kernel  metric 256
Run Code Online (Sandbox Code Playgroud)

容器中的 IPv6 路由:

# ip -6 r
2600:3c01:e000:e2::1111:0/112 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
default via 2600:3c01:e000:e2::1111:1 dev eth0  metric 1024
Run Code Online (Sandbox Code Playgroud)

仍然无法从我的家用机器 ping 它。

Mad*_*ter 2

我认为你的问题与路由有关。问题是您已被分配了一套公寓/64,但您已决定对 . 进行子网划分/112。这对于出站流量来说很好,因为您的容器主机知道所有单独的子子网,但是当您的 ISP 来处理返回数据包时,他们不知道您已经进行了分段2600:3c01:e000:e2::1111:0/112并且应该通过2600:3c01:e000:00e2::1. 他们只是希望整个系统2600:3c01:e000:00e2::/64都坐在那里,直接连接并通过单播访问。

问题在于,没有任何机制可以告诉您的 ISP 您已决定开始划分子网(实际上,这是一个谎言,有很多方法 - 但它们都需要您的 ISP 的合作)。最简单的选择可能是停止流量路由到容器,并开始桥接它。

我无法确切地告诉你该怎么做。我尝试过,有几个人善意地指出我错了。希望有人能澄清一下。但问题仍然是,您需要将容器桥接到下一跳路由,反之亦然,而不是路由它们。