项目需求需要利用 docker 支持 ipv6 网络环境。 于是简单研究了一下 docker 针对 ipv6 的部署情况。 官网写的挺简单,https://docs.docker.com/config/daemon/ipv6/ 如下:
Edit /etc/docker/daemon.json and set the ipv6 key to true. { "ipv6": true } Save the file.
Reload the Docker configuration file. $ systemctl reload docker
You can now create networks with the --ipv6 flag and assign containers IPv6 addresses using the --ip6 flag.
结果发现这样配置后,随意 run 一个 docker 镜像,并没有发现 docker 内部会自动获取 ipv6 地址(开发环境中已存在 ipv6 的 dhcp 服务器,host 主机会自动获取 ipv6 地址)。 于是继续观摩官网 https://docs.docker.com/v17.09/engine/userguide/networking/default_network/ipv6/#how-ipv6-works-on-docker 发现如下信息: How IPv6 works on Docker By default, the Docker daemon configures the container network for IPv4 only. You can enable IPv4/IPv6 dualstack support by running the Docker daemon with the --ipv6 flag. Docker will set up the bridge docker0 with the IPv6 link-local address fe80::1.
By default, containers that are created will only get a link-local IPv6 address. To assign globally routable IPv6 addresses to your containers you have to specify an IPv6 subnet to pick the addresses from. Set the IPv6 subnet via the --fixed-cidr-v6 parameter when starting Docker daemon:
You can run dockerd with these flags directly, but it is recommended that you set them in the daemon.json configuration file instead. The following example daemon.json enables IPv6 and sets the IPv6 subnet to 2001:db8:1::/64.
{ "ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64" } The subnet for Docker containers should at least have a size of /80, so that an IPv6 address can end with the container ’ s MAC address and you prevent NDP neighbor cache invalidation issues in the Docker layer.
By default, --fixed-cidr-v6 parameter causes Docker to add a new route to the routing table, by basically running the three commands below on your behalf. To prevent the automatic routing, set ip-forward to false in the daemon.json file or start the Docker daemon with the --ip-forward=false flag. Then, to get the same routing table that Docker would create automatically for you, issue the following commands:
$ ip -6 route add 2001:db8:1::/64 dev docker0
$ sysctl net.ipv6.conf.default.forwarding=1
$ sysctl net.ipv6.conf.all.forwarding=1 All traffic to the subnet 2001:db8:1::/64 will now be routed via the docker0 interface.
大概意思就是 docker 会自动获取 ipv4 地址,ipv6 地址需要开启 v6 服务。即使开启 v6 服务,也只是会获取本地局域类型的 v6 地址(非全球公网 ipv6 地址),公网 ipv6 的地址需要手动配置。
按照这个思路观察原有 v4 环境下项目的部署,的确 docker 环境中确实只要 host 寄主机能够访问公网,docker 容器不需要配置公网 v4 地址就可以访问公网( docker 镜像获取的都是私网地址,例如 172.17..)。寄主机会自动路由容器内部的公网访问请求。
但是!!!
目前发现 docker 在 ipv6 的环境下就不一样了。即使 host 寄主机已经自动获取到 v6 的公网地址,如果不手动配置 docker ipv6 的路由地址,不管是 docker run 还是 docker-compose 启动的容器,内部都不能访问 v6 的公网。进入到容器内部查看网络配置,你会发现容器只获取到了 link-local IPv6 address (如官网所说)。然后这个 v6 的本地地址和 v4 的私网地址不同,v6 中已经没有私网地址这个概念了。
按 v4 的使用习惯,寄主机应该自动路由容器内部对于公网 ipv6 请求的路由信息,即使容器内部并没有获取到动网 ipv6 地址。结果确并不是这样。。。
最后试着利用 docker-compose 的配置去手动设置了 ipv6 地址,如下: networks: app_net: driver: bridge enable_ipv6: true ipam: driver: default config: - subnet: 172.19.0.0/24 gateway: 172.19.0.1 - subnet: 2123:abcd:1234:5678::0/120 gateway: 2123:abcd:1234:5678::1
其中 subnet 和 gateway 需要参考寄主机自动获取的 v6 地址进行适度更改。
并且还要将寄主机的自动获取到 ipv6 的网口做成路由网口(栗子为 ens160 ),并且配置 docker 的 NDP 邻居发现,如下:
sysctl net.ipv6.conf.default.forwarding=1 sysctl net.ipv6.conf.all.forwarding=1 sysctl net.ipv6.conf.ens160.accept_ra=2 sysctl net.ipv6.conf.ens160.proxy_ndp=1
重启 docker 服务 systemctl reload docker
并将对应的容器获取到的 v6 地址映射到寄主机的网口上: ip -6 neigh add proxy 2123:abcd:1234:5678::2 dev ens160
添加完后不需要重启 docker 实例,直接生效;
经过这样一番折腾后,容器内部才能 ping6 ipv6.baidu.com 这个地址,也就是能正常访问 ipv6 的公网了。
总结: docker 有没有像 v4 那样,只需要寄主机获取到 ipv6 的公网地址(并且能够正常访问),容器内部只要支持 v6 并不需要!不需要!不需要! 配置 v6 的公网地址就可以访问到外部的 ipv6 公网资源。 每次这样手配地址真的很麻烦,而且不知道有没有和别的 v6 设备地址冲突...
求各位大神指点迷津
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.