共计 1530 个字符,预计需要花费 4 分钟才能阅读完成。
编辑/etc/docker/daemon.json
写入如下内容
{
"ipv6": true,
"fixed-cidr-v6": "fd00::/80",
"experimental": true,
"ip6tables": true
}
重启docker
systemctl restart docker
开启 IPv6 转发
编辑/etc/sysctl.conf,写入如下内容:
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
操作完这两步,大部分情况下,docker容器内ipv6应该就通了,验证如下:
进入容器:
docker exec -t -i [容器id] /bin/bash
ping6 -c2 2400:3200::1 # 阿里 IPv6 DNS
curl -6 https://ipv6.google.com # 应能通
如果还不通,继续往下
用 NAT66 给 ULA 出口 (能用但不优雅)
可以做 NAT66(MASQUERADE),把 fd00::/80 翻译成宿主的公网 IPv6。Docker 对 IPv6 不默认 NAT,但内核支持 ip6tables -t nat
。我们已经 "experimental": true
、"ip6tables": true
了,可以按下面做:
# 1) 开启转发(同 A-1)
# 2) 清理/设置 NAT66 规则(示例)
ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE
# 允许转发(同 A-3)
ip6tables -A FORWARD -s fd00::/80 -j ACCEPT
ip6tables -A FORWARD -d fd00::/80 -m state --state RELATED,ESTABLISHED -j ACCEPT
最优雅方案
用“全球单播前缀(GUA)”给容器(推荐,纯路由,无 NAT) ,理想做法是给 docker 网桥分一个 /64 公网前缀,上游把这个 /64 路由到你的宿主机。在常见云上这通常需要“申请一个额外 /64 并设置路由到实例”,如果你的供应商支持:
假设你拿到了 2403:18f0:3:30a::/64
并路由到宿主 eth0
。改 daemon.json
:
{
"ipv6": true,
"fixed-cidr-v6": "2403:18f0:3:30a::/64",
"ip6tables": true,
"experimental": true
}
重启 Docker:
systemctl restart docker
相关说明
其实做完第二步开启 IPv6 转发,大部分情况下应该也就够用了,这里解释下,为什么开启转发就能通公网?
你的主机本身已经有公网 IPv6(/64 前缀)
- 你的
eth0
地址是 公网ipv6,在运营商的全球单播前缀里。 - 这意味着宿主机具备完整的 IPv6 出口能力。
Docker 给容器分配了一个 ULA 子网 fd00::/80
- 一旦开启
net.ipv6.conf.all.forwarding=1
,宿主机就会把来自docker0
的 IPv6 包直接路由出去。 - 如果运营商的网关不做过滤,那么即使源地址是
fd00::/80
(ULA),包也会被转发到公网。 - 一些云环境会“宽松处理”源地址检查 → 导致 容器用 ULA 也能访问公网。
没有 NAT66,但依然能出去
- 正常来说,ULA(fd00::/8)是“只在本地有效”,外网不应该接受。
- 你能通,说明:
- 要么是出口网关自动给这些包做了 SNAT(NAT66),把源地址换成宿主的公网地址;
- 要么运营商的路由策略比较“宽松”,直接放行了。
- 开启 IPv6 转发 后,容器能用 IPv6 出公网 → 说明出口网关帮你做了隐藏的地址处理。
- 在逻辑上,你相当于“白捡了 NAT66 功能”,Docker 不需要自己配置 NAT 规则。