如何使用 docker-compose 分配 IPv6 地址

How to assign IPv6 address with docker-compose

我在 Ubuntu 16.04 上使用 docker 1.12.1,并且 docker-compose 1.8.1。我正在尝试将 Compose 文件从 https://docs.docker.com/compose/compose-file/#ipv4-address-ipv6-address 获取到 运行。作为参考,我创建了 docker-compose.yml,内容如下:

version: '2'

services:
  app:
    image: busybox
    command: ifconfig
    networks:
      app_net:
        ipv4_address: 172.16.238.10
        ipv6_address: 2001:3984:3989::10

networks:
  app_net:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "true"
    ipam:
      driver: default
      config:
      - subnet: 172.16.238.0/24
        gateway: 172.16.238.1
      - subnet: 2001:3984:3989::/64
        gateway: 2001:3984:3989::1

现在,运行宁docker-compose up生产

Creating network "tmp_app_net" with driver "bridge"
Creating tmp_app_1
Attaching to tmp_app_1
app_1  | eth0      Link encap:Ethernet  HWaddr 02:42:AC:10:EE:0A  
app_1  |           inet addr:172.16.238.10  Bcast:0.0.0.0  Mask:255.255.255.0
app_1  |           inet6 addr: fe80::42:acff:fe10:ee0a/64 Scope:Link
app_1  |           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
app_1  |           RX packets:4 errors:0 dropped:0 overruns:0 frame:0
app_1  |           TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
app_1  |           collisions:0 txqueuelen:0 
app_1  |           RX bytes:520 (520.0 B)  TX bytes:90 (90.0 B)
app_1  | 
app_1  | lo        Link encap:Local Loopback  
app_1  |           inet addr:127.0.0.1  Mask:255.0.0.0
app_1  |           inet6 addr: ::1/128 Scope:Host
app_1  |           UP LOOPBACK RUNNING  MTU:65536  Metric:1
app_1  |           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
app_1  |           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
app_1  |           collisions:0 txqueuelen:1 
app_1  |           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
app_1  | 
tmp_app_1 exited with code 0

未分配 IPv6 地址。

我已经试过了:

  1. 使用 --ipv6
  2. 启动 docker 守护进程
  3. --ipv6 --fixed-cidr-v6="2001:3984:3989::/64" 启动 docker 守护进程
    • 请注意 docker run -it busybox ifconfig 实际上在这里给了我一个 IPv6 地址(来自分配给默认 bridge 网络的 --fixed-cidr 子网)
  4. 使用我的实际 IPv6 子网而不是代码示例中的子网,并使用此子网重复 2.

没有成功。有什么想法吗?

事实证明这确实是一个 docker-compose bug,将在 1.9.0 中修复。

同时,通过使用 docker network 命令创建自定义网络有一个解决方法:

docker network create --subnet=172.16.2.0/24 --gateway=172.16.2.1 --ipv6 --subnet=<myV6Network/subnet> dockerbridge

... 然后可以通过编写

docker-composed.yml 中提供
networks:
  dockerbridge:
    external:
      name: dockerbridge

是的。 Docker compose 支持 IPv6 协议,它被引入到 docker engine 1.5 之后。还有issue with latest compose file format 3.3 所以你可以使用 2.1 格式。仍然 docker swarm 在高级网络配置方面还不够成熟,并且它不支持 IPv6,因此它不包含在 3.3 fil 格式中。 这是文件示例,

docker-compose.yml

version: ‘2.1’
services:
  app:
    image: busybox
    command: ping www.google.com
    networks:
      app_net:
        ipv6_address: 2001:3200:3200::20
networks:
  app_net:
    enable_ipv6: true
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 2001:3200:3200::/64
          gateway: 2001:3200:3200::1

此 docker 组合文件将基于子网 2001:3200:3200::/64 下的 IPv6 网络创建一个名为 testping_app_net 的新网络并且容器应该自动分配 IPv6 地址。

让我们使用 docker 启动服务-组合并查看服务是否通过 IPv6 协议进行通信:

docker-compose up -d

您可以使用

验证每个容器的 IPv6 地址
docker exec -it 905 ip addr

您会看到一个新容器获得了 IPv6 地址 – 2001:3200:3200::20,因此它们能够相互通信。

注意: 如果你想在主机上启用 IPv6,默认情况下使用 IPv4 地址,你需要将这两行添加到 daemon.json /etc/docker目录下:

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

并通过命令重新启动 docker 守护程序:

$ sudo systemctl restart docker

简答:

在您的 docker-compose.yml 文件中添加 (3) 个指令,(1) 到 daemon.json 然后重新构建您的容器并将 Docker 主机的 SLAAC 地址接口放到 docker-组成网桥,容器本身将收到一个 IPV6 SLAAC 地址。

此解决方案被证明与以下版本兼容:

  • docker-compose v. 2.1.1 和
  • docker-撰写文件格式 v. 3.9.

如果您不知道如何实现上述目标,请阅读下面较长的答案。其实并不难,也不费时。

简介:

(请随意跳过这个介绍 - 只是关于我正在尝试解决的问题的上下文)。

像访问此问题的其他人一样,我也遇到了 docker-compose 中的 IPv6 网络问题。据我所知,某些 IPV6 指令仅适用于更旧的 docker-compose 文件版本。我猜这可能会导致较旧的 docker-compose 文件版本不支持较新的指令。有些解决方案不适用于 swarm。

许多人似乎能够在他们的 docker-compose 配置中获得 IPV6 连接的唯一方法是使用一些沮丧的 Docker 用户编码的“IPV6 NAT”。顺便说一句,这不是批评:我们需要不会被打败的人,他们顽强地想方设法绕过 problems/limitations。但是 IPv6 应该可以解决 NAT 的问题 ;-)

我想:必须有更简单的方法!

还有……

我的设置:

如果您 运行 遇到困难,我将描述我的设置以启用比较分析:

  • 为 IPv6 SLAAC 寻址配置的 MikroTik 路由器连接到双栈 IPV4/V6 交换机。

  • A Raspberry Pi 4 运行ning 64bit Ubuntu 20.04 LTS 通过 eth0 连接到交换机,从中获得其 IPv6 全球单播地址(“GUA ") 来自路由器。

  • Docker 使用的版本 = Docker Engine Community v. 20.10.11

  • docker-compose = v.2.1.1

  • docker-撰写文件格式=v.3.9

docker-编写 IPv6 配置:

docker-compose.yml

我的 networks 部分:

networks:
  my-custom-network:
    name: my-custom-network
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: 192.168.XX.0/24
          gateway: 192.168.xx.1

请注意,唯一特定于 IPv6 的指令只是 enable_ipv6: true

接下来,我的 docker-compose.yml 文件的相关部分包含 services 部分中的其他 (2) IPv6 特定指令,用于我想要 IPV6 地址的容器是:

sysctls:
  - net.ipv6.conf.all.disable_ipv6=0
  - net.ipv6.conf.eth0.proxy_ndp=1

显然是 YAML,请注意使用正确的前导空格将该部分放入,否则当唯一的问题是指令的缩进时,它会产生误导性错误。

/etc/docker/daemon.json

我在这里添加了 (1) 特定于 IPv6 的指令:

  "ipv6": true, "fixed-cidr-v6": "2001:470:1d3f:8::/64",

此步骤是为我们的容器分配 IPv6 全球可路由 IPv6 地址所必需的。

最后,在完成调整后剪切一组新的容器(但先不要启动它们):

docker-compose build --no-cache

Docker 主机网络配置:

  1. 在执行 IPv6 Docker 配置之前,通过从您的 Docker 主机使用 ping6 ping 某些内容来验证路由器的 IPv6 配置是否正确:

    ping6 ipv6.google.com

如果成功返回响应,则表明 Docker 主机和路由器都可以解析和路由 IPv6 数据包。问题现在减少到只解决容器 IPV6 问题。

  1. 由于 Pi 的 eth0 接口本身是 IPv6 地址,并且很高兴地与我们的路由器对话 IPv6,我们将把它加入 docker-compose 桥:
  • 找到docker-compose bridge name "br-series-of-random-chars":

    ip addr list

  • 将 eth0 添加到网桥:

    ip link set dev eth0 master br-ckkde30ff0g

注意:上面的命令是NON-Persistent-它不会在重启后继续存在。添加eth0的过程可以完全自动化..

  • 检查 eth0 现已加入:

    ip link | grep "master br-ckkde30ff0g"

  1. 启动您的容器:

    docker-compose start

  2. 现在将容器验证为 IPv6 GUA:

    docker exec -it containerName bash 然后:

    hostname -I

您现在应该会看到 SLAAC 配置的 IPv6 GUA 地址。

  1. 在您的 IPv6 防火墙上打个洞以根据需要定制访问

安全:

谢天谢地,您看不到的内容:接收 IPv6 GUA 地址的任何其他容器。

只有在其配置中包含上述 sysctls 指令的容器才会收到 SLAAC IPv6 地址 - 没有其他地址。就我而言,我只想在 WordPress 站点前面公开代理容器,而不是其他容器、网络服务器和后备数据库。所以只有代理可以通过IPv6访问。

配置验证:

以下站点是使用上述过程配置的 100% docker-compose 装置,因此可以证明此处概述的过程可以正常工作:

http://[2001:470:1d3f:8:42:c0ff:fea8:1504]/

请注意:我将在下周更改 ISP,因此在配置新的 link 时可能会有一些停机时间。

您还可以使用 IPv6 测试站点验证容器 IPv6 寻址的 IPV6 配置:

https://ipv6-test.com/validate.php

  • 如果为裸域设置了 AAAA DNS 记录- domain.com- 然后将其作为 url 输入检查器。

  • 如果为子域 www 设置了 AAAA 记录,则输入 www.domain.com进入检查器。

结论:

就是这样:只有 docker-compose 中的 (3) IPv6 特定指令,daemon.json 中的 (1),一些桥接和正确配置 IPv6 的路由器。完毕。并且不需要 NATing。

同样,这不是一个完美的解决方案,也不是理想的解决方案,但它是解决 IPv6 连接问题的另一种方法。如果我错过了某个地方的步骤,请给我评论。