可公开路由的IPv6 linux容器

我的目标是为每个docker集装箱设置可路由的公有IPv6地址。 我希望能够使用IPv6协议连接到我的容器和从我的容器中出来。

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

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

这个“路由到”地址是由dhcp自动configuration的:

 # 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 

我为ipv6.daaku.org设置了一个AAAAlogging,以便于处理:

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

为了testing,我手动分配了这个地址:

 # 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的家庭networking中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 

我在另一个terminal上build立了一个没有networking的docker集装箱:

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

卡住它的variables易于使用的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 

创build一个新的设备,分配给它的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 

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

 # 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作为我的testing),也不能从我的家庭networking通过互联网ping容器(使用ping6 ipv6.daaku.org作为我的testing)。

更新:我设法通过这样做得到传出的 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它。

我认为你的问题是路由相关的。 麻烦的是,你已经被分配了一个/64 ,但是你已经决定从一个/112子子网中分配出去。 这对出站stream量来说很好,因为您的容器主机知道所有单独的子子网,但是当您的ISP来处理返回数据包时,他们不知道您已经分段了2600:3c01:e000:e2::1111:0/112 ,那应该通过2600:3c01:e000:00e2::1路由。 他们只是期望整个2600:3c01:e000:00e2::/64坐在那里,直接连接,并通过单播访问。

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

我不能告诉你如何做到这一点。 我试了一下,有好几个人好心的指出我错了。 希望有人能澄清。 但问题仍然是,你需要将你的容器连接到下一跳路由,反之亦然,而不是路由它们。

在docker 1.0中,有两个选项可以启用到docker容器的IPv6连接。 我必须使用lxc驱动程序而不是libcontainer才能使这两种方法正常工作。 您可以使用RADVD。 我没有尝试。

1) 让提供者将/ 64发送到你的docker主机 。 这是最简单的select。 启用IPv6转发并将/ 64分配给docker0。 除非你有多个docker桥或多个docker主机,否则你不必把这个networking分成更小的networking(即/ 112)。

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

请注意,很less启用IPv6的IaaS提供程序会将a / 64路由到VM。 第二种方法以半惯性的方式克服了这个限制。

2) 使用docker网桥上LAN接口的/ 64子集 – 这种方法不需要将/ 64路由到docker主机。 在LAN上的/ 64(例如,/ 112)中的较小networking被分配给docker0。 NDPconfiguration为从代理桥到您的LAN接口(可能是eth0)代理NDP。

我在http://jeffloughridge.wordpress.com/2014/07/22/ipv6-in-docker-containers-on-digitalocean/上写了这个方法的详细描述&#x3002;

我还没有使用大于1.0的docker版本。 在新版本中,事情可能已经发生了变化。

通过RFC,子网中的所有地址都在a / 64之内。 这个空间内的分配使用一个或多个IPv6地址。

你认为IPv6就像IPv4一样,但是地址更大。 我在这里告诉你,如果你这样devise你的系统,期望增加你的设置成本,维护是安全的!