Featured image of post docker swarm 到底支不支持ipv6

docker swarm 到底支不支持ipv6

docker

要搞清楚这个问题我们首先需要搞清楚,在集群中的容器和非集群的容器,数据流向到底是怎样的

数据包流转:

下面我假设一个数据包从客户端发起到应用,当容器处于不同的网络中时:

docker容器(bridge网络)

ipv4

外部请求进入宿主机
  • 路径:外部用户访问主机

    • 流量首先进入宿主机的iptablesPREROUTING链。

    • 通过PREROUTING 的DNAT规则转发到docker0网卡(即把目标ip修改为容器IP)

目标容器接收请求
  • 路径: 数据进入容器

    • 通过veth,veth连接了主机网络命名空间和容器命名空间,数据发送到容器内eth0

    • 应用监听的端口取得数据,响应数据按反向路径返回

ipv6

外部请求进入宿主机
  • 路径:外部用户访问主机

    • 流量首先进入宿主机的ip6tablesPREROUTING链。

    • 通过PREROUTING 的DNAT规则转发到docker0网卡(即把目标ip修改为容器IP)

目标容器接收请求
  • 路径: 数据进入容器

    • 通过veth,veth连接了主机网络命名空间和容器命名空间,数据发送到容器内eth0

    • 应用监听的端口取得数据,响应数据按反向路径返回

可以看到基本是一致的,只是ipv6使用了ip6tables,而ipv4使用的iptables。

docker swarm中的容器(overlay网络)

ipv4

外部请求进入宿主机
  • 路径:外部用户访问任意Swarm节点
  • 关键动作
    • 流量首先进入宿主机的iptablesPREROUTING链。
    • 通过DOCKER-INGRESS自定义链的DNAT规则,将目标端口的流量转发至ingress-sbox网络命名空间的IP。
    • ingress-sbox是一个特殊的网络命名空间,连接了docker_gwbridge(172.18.0.0/16)和ingress Overlay网络。
Ingress网络处理负载均衡
  • 路径ingress-sbox命名空间 → IPVS负载均衡
  • 关键动作
    • iptables对访问流量打上标记,触发IPVS负载均衡机制。
    • IPVS根据标记查询路由表,通过轮询(rr)策略将流量分发到实际服务容器的虚拟IP(如10.0.0.5和10.0.0.6)。
    • 此阶段实现了Swarm的Routing Mesh特性,确保请求可被集群中任意节点的服务实例处理。
Overlay网络跨节点传输
  • 路径:源节点 → 目标节点(容器所在节点)
  • 关键动作
    • 若目标容器在其他节点,数据包通过VXLAN隧道封装,在ingress Overlay网络(10.0.0.0/24)中跨主机传输。
    • docker_gwbridge负责宿主机与Overlay网络的桥接,确保跨节点通信的隔离性和安全性。
目标容器接收请求
  • 路径:目标节点 → 服务容器
  • 关键动作
    • 数据包通过目标节点的docker_gwbridge解封装,转发至对应容器的虚拟网络接口。
    • 容器通过自定义网络(如Overlay网络)直接接收请求,响应数据按反向路径返回

ipv6

理论上同上(只是NAT由ip6talbes完成),但是我发现根本就docker engine 根本就不写ipv6这个栈的规则。具体看下面

二、docker swarm到底对ipv6支持如何?

个人实践

网络上说可以支持的

以如下这篇文章:配置docker swarm网络支持访问ipv6-天翼云开发者社区 - 天翼云 最为典型,整个中文互联网其他的说支持的,基本也是抄的这个文章。

实际情况

主要有两个大问题:

  • docker engine压根不写ipv6的规则,即使手动加上也无济于事(加上规则也依旧不能访问应该是vxlan的实现有问题) 这是同一个服务的ipv4规则:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    [root@geosmarter01 ~]# iptables -t nat -nL
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    DOCKER-INGRESS  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match src-type LOCAL
    MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match src-type LOCAL
    MASQUERADE  all  --  162.168.1.0/24       0.0.0.0/0
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match src-type LOCAL
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    DOCKER-INGRESS  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    
    Chain DOCKER-INGRESS (2 references)
    target     prot opt source               destination
    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:30000 to:172.17.0.2:30000
    RETURN     all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain DOCKER (2 references)
    target     prot opt source               destination
    

    这是同一个服务的ipv6规则:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    [root@geosmarter01 ~]# ip6tables -t nat -nL
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    DOCKER     all      ::/0                 ::/0                 ADDRTYPE match dst-type LOCAL
    
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    MASQUERADE  all      ::/0                 ::/0                 ADDRTYPE match src-type LOCAL
    MASQUERADE  all      2001:db8:1::/64      ::/0
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    DOCKER     all      ::/0                 ::/0                 ADDRTYPE match dst-type LOCAL
    
    Chain DOCKER (2 references)
    target     prot opt source               destination
    
  • 分配ipv6地址报错(我试了几十个保留地址段都是如此):

    1
    
    2月 12 17:32:57 geosmarter01 dockerd[1205697]: time="2025-02-12T17:32:57.608232468+08:00" level=error msg="Failed allocation for network vweecm9pd8vn3mfogpaxv2kti" error="failed allocating pools and gateway IP for network vweecm9pd8vn3mfogpaxv2kti: cannot find address pool for poolID:2001:db8:9::/64/invalid Prefix" module=node node.id=lwae3e2a1pqf7bvxlqwjqdor4
    

github和开源社区反馈

  • 结论是最后这个人使用了socat另外开辟了端口转发到ipv4端口

Docker swarm, traefik 2.0 and IPv6 issue - #2 by daniel.tomcej - Traefik v2 - Traefik Labs Community Forum

因此,从我发现的情况来看,当您使用 docker swarm 时,覆盖网络驱动程序对 IPv4 和 IPv6 的工作方式似乎不同。
对于 IPv4,它会自动将机器 IP 后面的每个暴露端口进行 NAT。
对于 IPv6,不会执行 NAT。

真正痛苦的是,尽管 docker 只对 IPv4 执行 NAT,但它却同时监听 IPv4 和 IPv6 套接字。

  • 这个问题在docker官方论坛无结论

Support for ipv6 in docker swarm mode - General - Docker Community Forums

我们能够在 ipv4 中创建带有覆盖网络的 docker swarm,但是在创建覆盖网络期间启用 ipv6 支持时,将覆盖网络连接到容器时遇到问题。

  • 这个问题在docker官方论坛根本没有人理

https://forums.docker.com/t/cant-attach-container-to-overlay-network-with-ipv6-enabled/141593

我在 Debian 上使用 Docker 版本 26.1.2。我一直在尝试在 Swarm 覆盖网络上运行的某些容器内启用 IPv6。我能够让它在默认桥接驱动程序上工作,但当我使用覆盖驱动程序(这是我需要的)时,它要么失败,要么…

  • 这是docker-ce开源项目的issue中,有人遇到相同问题,结论就是目前docker 支持有问题

https://github.com/moby/moby/issues/43615

Rudios81

为什么这个问题仍然存在。
我正在测试一个全新的 docker 安装 27.4.1,但我仍然无法创建一个有效的启用 IPV6 的覆盖网络。
启动连接到默认网桥的容器时,容器会获得正确的 IPv6 地址。
创建启用 IPv6 的覆盖网络时,网络本身会被创建,但如果连接到此覆盖网络,容器将无法启动。

troykelly

Docker 对 IPv6 功能不感兴趣。它“意外地”在版本 25 中运行,但不受支持。Docker 和 Docker Swarm 永远不应该在生产环境中使用;它们不是生产工具。Docker 适用于容器化开发(VSCode 等),但绝对不适用于需要可靠且一致地工作的系统。

  • 这个人的博客提供了一些办法,但是我试了其实也是行不通的,他自己在文章末尾也吐槽

Docker Networks Part 2: Customize the network for Docker Swarms

但即便如此,它仍然不起作用!启用 IPv6 后(--ipv6 标志),不会为群集内的节点分配任何 IP 地址。然后出现了一个令人沮丧的认识:docker swarm 集群尚不支持 IPv6 

替代方案

k8s或者轻量化k8s(k3s)

可以使用成熟的k8s体系,能够k8s支持很完整的CNI生态,可以支持ipv6。具体部署方案,可以跟我商量,原理上我已经走通。

使用socat转发流量

因为ipv4和ipv6是完全独立的两个网络栈,数据包发到ipv4的话是没办法流转到ipv6体系中的,Socat 是 Linux 下的一个多功能的网络工具,可以监听一个ipv6的端口,把数据转发到ipv4的某个端口上。

如果使用socat的话,docker swarm 各个节点中间配置ipv4通信即可,数据流转就是: 客户端主机socat端口(ipv6)主机中服务的端口(ipv4)以ipv4在服务中流转数据主机socat端口(ipv6)客户端

建议使用第一种,第二种socat的规则维护需要每个机器都维护,并且需要我们自己代码实现来维护它的规则,还需要多开一倍的端口。