可公开路由的 IPv6 Linux 容器

可公开路由的 IPv6 Linux 容器

我的目标是为每个 Docker 容器提供可路由的公共 IPv6 地址。我希望能够使用 IPv6 协议连接和退出我的容器。

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

2600:3c01:e000:00e2:: / 64 routed to 2600:3c01::f03c:91ff:feae:d7d7

该“路由到”地址由 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

我设置了 AAAA 记录以便ipv6.daaku.org于使用:

# nslookup -q=AAAA ipv6.daaku.org
ipv6.daaku.org  has AAAA address 2600:3c01:e000:e2::1

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

# 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

我现在可以从启用了 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

我删除了地址,因为我只想它在容器中,然后恢复到原始状态:

# 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

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

# docker run -it --rm --net=none debian bash
root@b96ea38f03b3:/#

为方便使用,将其 pid 保存在变量中:

CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' b96ea38f03b3)

为该 pid 设置 netns:

# mkdir -p /run/netns
# ln -s /proc/$CONTAINER_PID/ns/net /run/netns/$CONTAINER_PID

创建了一个新设备,并为其分配了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

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

# 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

这不起作用,我无法从容器连接(用作ping6 ipv6.google.com我的测试),也无法从我的家庭网络通过互联网 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

主机上的 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

容器中的 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

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

答案1

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

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

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

答案2

在 docker 1.0 中,有两种选项可用于启用 docker 容器的 IPv6 连接。我不得不使用 lxc 驱动程序而不是 libcontainer 来使这两种方法都起作用。您可能可以使用 RADVD。我没有尝试过。

1)让提供商将 /64 路由到你的 docker 主机。这是最简单的选择。启用 IPv6 转发并将 /64 分配给 docker0。除非您有多个 docker 网桥或多个 docker 主机,否则您不必将此网络拆分为较小的网络(即 /112)。

Andreas Neuhaus 的博客文章“Docker 容器中的 IPv6”深入讨论了此方法。请参阅http://zargony.com/2013/10/13/ipv6-in-docker-containers

请注意,只有极少数支持 IPv6 的 IaaS 提供商会将 /64 路由到虚拟机。第二种方法以一种不太成熟的方式克服了这一限制。

2)使用 docker bridge 上 LAN 接口的 /64 子集- 此方法不需要将 /64 路由到您的 docker 主机。LAN 上 /64 中的较小网络(例如 /112)分配给 docker0。NDP 配置为将 NDP 从 docker 桥代理到您的 LAN 接口(可能是 eth0)。

我在http://jeffloughridge.wordpress.com/2014/07/22/ipv6-in-docker-containers-on-digitalocean/

我没有使用过 1.0 以上的 docker 版本。新版本中的情况可能有所改变。

答案3

根据 RFC,子网中的所有地址都在 /64 范围内。此空间内的分配使用一个或多个 IPv6 地址。

您可能认为 IPv6 类似于 IPv4,但地址更大。我在这里告诉您,如果您以这种方式设计系统,则会增加设置成本,维护成本就是安全!

相关内容