VPS配了IPv6,Docker容器里却死活连不上

VPS本身IPv6配置得妥妥当当,ping -6一测宿主机畅通无阻,装进容器里的服务却怎么都连不上IPv6,docker exec进去一试,IPv6网络对这个容器来说压根不存在。折腾半天以为是容器内部网络设置有问题,其实Docker默认根本不会把宿主机的IPv6能力传给容器,这是设计上的默认行为,不是哪里配错了。

Docker压根没把IPv6当默认选项

Docker对IPv6的支持长期不如IPv4积极,容器网络默认走的是私有的IPv4段,宿主机有没有IPv6跟容器能不能用IPv6,是两件完全不搭界的事。想让容器拿到IPv6能力,得手动改Docker的配置文件:

1
vi /etc/docker/daemon.json

加上这两项:

1
2
3
4
{
"ipv6": true,
"fixed-cidr-v6": "fd00:db8:1::/64"
}

fixed-cidr-v6给的是一个私有IPv6网段,容器之间用这个网段互相通信;fd00::/8这类前缀是IPv6里对应IPv4私有地址(10.0.0.0/8那种)的等价物,专门留给内网场景用,照抄这个格式就行,不用自己纠结换成别的网段。

改完重启Docker服务让配置生效:

1
systemctl restart docker

确认有没有真的生效

1
docker network inspect bridge

看输出里EnableIPv6这一项是不是trueIPAM.Config里有没有出现你刚才配的那个IPv6网段。这一步能省掉后面很多冤枉排查——如果这里显示没生效,再怎么折腾容器内部网络设置都是白费功夫。

光配置daemon.json,可能还不够

如果宿主机的网关分配的是私网IPv6(不是公网直连),上面这套配置一般能直接生效;但如果宿主机拿到的是公网IPv6网关,情况会复杂一些,理论上还得配合iptables(准确说是IPv6对应的ip6tables)做地址映射才能真正打通,光改daemon.json不一定够用,具体取决于VPS服务商分配IPv6的方式。

确认改动生效后,实际测试一下:

1
docker run --network=bridge --rm -it busybox ping -6 -c4 google.com

只是临时用一下,也可以走host网络模式

如果不想动全局的Docker配置,只是某个容器临时需要用IPv6,还有个更简单的旁路方案——用host网络模式跑这个容器,直接借用宿主机自己的网络协议栈,宿主机能访问IPv6,容器立刻就能访问,不需要额外配置:

1
docker run --network=host 镜像名

缺点是host模式下容器和宿主机共用同一套网络命名空间,端口映射这些跟bridge模式的逻辑不一样,适合临时验证或者单容器场景,如果是多容器长期跑的生产环境,还是建议老老实实按上面的方式把daemon.json配好,更规范也更好维护。

顺带一提

这种"宿主机能力齐全,但容器/子系统默认不继承"的情况,跟之前写的VPS重启后Docker容器为什么没有自动启动是同一个脾气——Docker很多行为默认都偏保守,不会自作主张帮你把宿主机的能力透传进去,重启策略是这样,IPv6支持也是这样,新装的服务多留意一下默认值,别想当然。如果这台VPS本身的IPv6配置就有问题(不只是Docker层面),可以先看VPS防火墙规则设置了,IPv6那边却像没设一样那篇,排查一下宿主机这一层的IPv6是不是真的健康,再往Docker这一层深入。