我的环境:

  • OS: CentOS 7.9
  • Docker:20.10.7

1. 启用Docker守护进程对ipv6的支持

要想在Docker容器或者Swarm服务中使用ipv6,首先需要在Docker守护进程中启用对ipv6的支持,具体做法如下:

  1. 编辑docker守护进程的配置文件/etc/docker/daemon.json (若不存在需要手动创建该文件)

     {
        "experimental": true,
        "ip6tables": true,
        "ipv6": true,
        "fixed-cidr-v6": "2001:db8:1::/64"
     }
    

    ipv6设置为true,启用对ipv6的支持。
    fixed-cidr-v6,配置ipv6子网。
    ip6tables,启用ip6tables,docker会在ip6tables中配置docker网络相关的规则链。
    experimental,启用实验特性,ip6tables是docker的一个实验功能,所以需要设为true。

  2. 重载配置文件

     sudo systemctl reload docker && sudo systemctl restart docker
    

    现在你可以使用docker network create --ipv6 ... 创建一个支持ipv6的网络了。另外你也可以在启动容器时使用--ip6参数来使容器支持ipv6。

  3. 审查默认bridge网络

     sudo docker network inspect bridge
    

    在这里插入图片描述
    可以看到已经配置成功!

接下来就可以在容器中使用ipv6了!

2. 在Docker容器中使用ipv6

注意:以下演示依赖于上一步的配置

2.1 创建一个容器

使用nginx做演示:
启动一个容器,此处并没有指定网络所以默认使用名为bridge的网络,该网络在上一步已经支持ipv6了!

docker run --name test -p 81:80 -d nginx:1.21.6

进入容器内部查看网阔配置:

$ docker exec -it test ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.156.10.2  netmask 255.255.255.0  broadcast 10.156.10.255
        inet6 fe80::42:aff:fe9c:a02  prefixlen 64  scopeid 0x20<link>
        inet6 2001:db8:1::242:a9c:a02  prefixlen 64  scopeid 0x0<global>
        ether 02:42:0a:9c:0a:02  txqueuelen 0  (Ethernet)
        RX packets 3923  bytes 9184337 (8.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2836  bytes 192127 (187.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

容器内部已经分配了一个ipv6地址!

2.2 容器与宿主机通信

在上一步容器已经有一个ipv6地址了,但是如果宿主机没有一个合适的ipv6地址还是不能通过ipv6与宿主机通信。比如下面我用的宿主机网络配置:

$ ifconfig ens192
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.30.72  netmask 255.255.0.0  broadcast 192.168.255.255
        inet6 fe80::54f2:a4e2:f5cc:711a  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:c7:26:f5  txqueuelen 1000  (Ethernet)
        RX packets 38098236  bytes 6981689290 (6.5 GiB)
        RX errors 0  dropped 3567426  overruns 0  frame 0
        TX packets 953026  bytes 578286181 (551.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

尽管该接口有一个ipv6地址fe80::54f2:a4e2:f5cc:711a但是它是本地链路上的私有地址(fe80开头的地址属于私有地址)。私有地址是允许在本地链路上使用,且数据包不会跨链路转发。

所以,容器要想和宿主机通信,宿主机必须有一个非私有ipv6地址,如果默认没有就需要手动配置一个:
编辑网络接口配置文件/etc/sysconfig/network-scripts/ifcfg-ifName,例如我的测试宿主机网卡名称为ens192,那就编辑/etc/sysconfig/network-scripts/ifcfg-ens192:

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6_DEFROUTE=yes
IPV6_PRIVACY=no
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
IPV6ADDR=2018::27
NAME=ens192
UUID=08b8bead-340c-4708-8656-2af2394a7c1c
DEVICE=ens192
ONBOOT=yes
IPADDR=192.168.30.72
PREFIX=16
GATEWAY=192.168.30.1
DNS1=223.5.5.5

保存,执行网络服务重启:

sudo systemctl restart network

查看网卡配置:

$ ifconfig ens192
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.30.72  netmask 255.255.0.0  broadcast 192.168.255.255
        inet6 2018::27  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::54f2:a4e2:f5cc:711a  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:c7:26:f5  txqueuelen 1000  (Ethernet)
        RX packets 38106119  bytes 6982319769 (6.5 GiB)
        RX errors 0  dropped 3568059  overruns 0  frame 0
        TX packets 953451  bytes 578328655 (551.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

再次进行容器内ping宿主机:

$ sudo docker exec -it test ping6 2018::27
PING 2018::27(2018::27) 56 data bytes
64 bytes from 2018::27: icmp_seq=1 ttl=64 time=0.135 ms
64 bytes from 2018::27: icmp_seq=2 ttl=64 time=0.137 ms
64 bytes from 2018::27: icmp_seq=3 ttl=64 time=0.145 ms
64 bytes from 2018::27: icmp_seq=4 ttl=64 time=0.137 ms
64 bytes from 2018::27: icmp_seq=5 ttl=64 time=0.152 ms
^C
--- 2018::27 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4000ms
rtt min/avg/max/mdev = 0.135/0.141/0.152/0.006 ms

已经通了!

3. 使docker-compose 编排文件启动的服务支持ipv6

以下操作也须在docker引擎开启ipv6下进行。

3.1 对于版本2的编排文件

对于版本2的编排文件,可以直接在networks配置节点下启用ipv6,下面是个例子:

version: '2'
 #  其他services定义省略。。。 
networks:
  example:
    enable_ipv6: true
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "true"
    ipam:
      config:
       - subnet: 172.23.0.0/16
       - subnet: "2607:f0d0:1002:51:4000::/66"

3.2 对于版本3的编排文件

对于版本3的编排文件,无法像上边那样直接在编排文件中配置网络并开启ipv6,需要按照下面的方式进行:
首先需要通过命令行创建一个网络并启用ipv6:

$ sudo docker network create -d bridge \
     --ipv6 --subnet 2001:db8:1::1/64 \
     --subnet 10.156.11.0/24 extnetwork

通过上面的命令创建了一个子网为2001:db8:1::1/64的名字为extnetwork的ipv6网络且支持ipv4。

编排文件:

version: '3'
services:
  app:
    image: app:7.16.1
    container_name: app
    restart: always
    privileged: true
    networks:
      - extnetwork 
  #省略其他服务。。。

networks:
  extnetwork:
    external: true
Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐