IPv6 with Docker中文翻译

老师的项目要在Ipv6环境下跑,结果发现中文版却并没有对此篇文章的翻译,本瓜皮就来翻译一下。
原文地址

The information in this section explains IPv6 with the Docker default bridge. This is a bridge network named bridge created automatically when you install Docker.

这篇文章通过 Docker default bridge 来解释 IPv6 。这是一个 bridge 网络在你安装 Docker 的时候就自动创建。

As we are running out of IPv4 addresses the IETF has standardized an IPv4 successor, Internet Protocol Version 6 , in RFC 2460. Both protocols, IPv4 and IPv6, reside on layer 3 of the OSI model.

当我们的 IPv4 地址用尽的时候,IETF 在 RFC 2460 已经制定了一个 IPv4 的继承者———— IPv6,这两个协议都位于 OSI model(Open Systems Interconnection model) 的第三层。

How IPv6 works on Docker

By default, the Docker server configures the container network for IPv4 only. You can enable IPv4/IPv6 dualstack support by running the Docker daemon with the –ipv6 flag. Docker will set up the bridge docker0 with the IPv6 link-local address fe80::1.

默认情况下, Docker server 只配置了这个容器的 IPv4 网络. 你可以同时使用 IPv4/IPv6 通过添加 –ipv6 执行 Docker 进程 。Docker 会设置 bridge docker0 通过 IPv6 链接本地地址 fe80::1。

By default, containers that are created will only get a link-local IPv6 address. To assign globally routable IPv6 addresses to your containers you have to specify an IPv6 subnet to pick the addresses from. Set the IPv6 subnet via the –fixed-cidr-v6 parameter when starting Docker daemon:

默认情况下,创建的容器只会得到一个链接本地 Ipv6 地址。为了能够分配可全球路由的 IPv6 地址给你的容器,你不得不指定一个 IPv6 子网去建立地址表。当 Docker 进程启动时,通过 –fixed-cidr-v6 参数设置 IPv6 子网。

1
dockerd --ipv6 --fixed-cidr-v6="2001:db8:1::/64"

The subnet for Docker containers should at least have a size of /80. This way an IPv6 address can end with the container’s MAC address and you prevent NDP neighbor cache invalidation issues in the Docker layer.

Docker 容器的子网至少具有 /80 的形式。这样 IPv6 地址就能够以容器的 MAC 地址结尾并且防止在 Docker 层 NDP 缓存失效问题。

With the –fixed-cidr-v6 parameter set Docker will add a new route to the routing table. Further IPv6 routing will be enabled (you may prevent this by starting dockerd with –ip-forward=false):

通过 –fixed-cidr-v6 参数设置 Docker 会在路由表增加一个新路由。更多的 IPv6 路由将会启用(你通过用 –ip-forward=false 启动 Docker 来防止这种事情的发生)

1
2
3
4
5
$ ip -6 route add 2001:db8:1::/64 dev docker0

$ sysctl net.ipv6.conf.default.forwarding=1

$ sysctl net.ipv6.conf.all.forwarding=1

All traffic to the subnet 2001:db8:1::/64 will now be routed via the docker0 interface.

所有到 2001:db8:1::/64 子网的路由都会通过 docker0 接口路由。

Be aware that IPv6 forwarding may interfere with your existing IPv6 configuration: If you are using Router Advertisements to get IPv6 settings for your host’s interfaces you should set accept_ra to 2. Otherwise IPv6 enabled forwarding will result in rejecting Router Advertisements. E.g., if you want to configure eth0 via Router Advertisements you should set:

请注意 IPv6 转发会与 现存的 IPv6 配置连接:如果你正使用路由器广播来为你的主机接口获得 IPv6 设置,你应该设置 accept_ra=2 。否则 IPv6 转发会导致拒绝路由器广播。比如,如果你想配置 eth0 通过路由器广播,你应该这么设置。

1
$ sysctl net.ipv6.conf.eth0.accept_ra=2

Every new container will get an IPv6 address from the defined subnet. Further a default route will be added on eth0 in the container via the address specified by the daemon option –default-gateway-v6 if present, otherwise via fe80::1:

所有的容器都会从定义的子网获得一个 IPv6 地址。一个默认的路由将会增加到 eth0 如果存在进程选项 –default-gateway-v6,通过被特定化的地址,否则默认通过 fe80::1:

1
2
3
4
5
6
7
8
9
10
11
docker run -it ubuntu bash -c "ip -6 addr show dev eth0; ip -6 route show"

15: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500
inet6 2001:db8:1:0:0:242:ac11:3/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever

2001:db8:1::/64 dev eth0 proto kernel metric 256
fe80::/64 dev eth0 proto kernel metric 256
default via fe80::1 dev eth0 metric 1024

In this example the Docker container is assigned a link-local address with the network suffix /64 (here: fe80::42:acff:fe11:3/64) and a globally routable IPv6 address (here: 2001:db8:1:0:0:242:ac11:3/64). The container will create connections to addresses outside of the 2001:db8:1::/64 network via the link-local gateway at fe80::1 on eth0.

在这个例子当中 Docker 容器通过网络后缀 /64 (here: fe80::42:acff:fe11:3/64)和一个全局 IPv6 路由地址(here: 2001:db8:1:0:0:242:ac11:3/64)被分配了一个本地链接地址。通过这个本地链接网关 fe80::1,这个容器将会创造通往 2001:db8:1::/64 之外的网络地址连接。

Often servers or virtual machines get a /64 IPv6 subnet assigned (e.g. 2001:db8:23:42::/64). In this case you can split it up further and provide Docker a /80 subnet while using a separate /80 subnet for other applications on the host:

通常服务器或者虚拟机得到一个 /64 IPv6 子网分配 (比如: 2001:db8:23:42::/64)。当你想要给别的主机上的应用使用单独的 /80 子网,你可以分开它并提供给 Docker /80 子网

In this setup the subnet 2001:db8:23:42::/64 with a range from 2001:db8:23:42:0:0:0:0 to 2001:db8:23:42:ffff:ffff:ffff:ffff is attached to eth0, with the host listening at 2001:db8:23:42::1. The subnet 2001:db8:23:42:1::/80 with an address range from 2001:db8:23:42:1:0:0:0 to 2001:db8:23:42:1:ffff:ffff:ffff is attached to docker0 and will be used by containers.

2001:db8:23:42::/64 子网从 2001:db8:23:42:0:0:0:0 到 2001:db8:23:42:ffff:ffff:ffff:ffff 被赋给 eth0,在 2001:db8:23:42::1 被监听。子网 2001:db8:23:42:1::/80 从 2001:db8:23:42:1:0:0:0 to 2001:db8:23:42:1:ffff:ffff:ffff 将会被赋给 docker0 并且将会被容器使用。

Using NDP proxying

If your Docker host is the only part of an IPv6 subnet but does not have an IPv6 subnet assigned, you can use NDP proxying to connect your containers to the internet via IPv6. If the host with IPv6 address 2001:db8::c001 is part of the subnet 2001:db8::/64 and your IaaS provider allows you to configure the IPv6 addresses 2001:db8::c000 to 2001:db8::c00f, your network configuration may look like the following:

如果你的 Docker 主机仅是唯一的 IPv6 子网,没有 IPv6 子网被分配,你可以用 NDP peoxying 去连接你的容器到网络。如果主机有着 2001:db8::c001 地址是 2001:db8::/64 的一部分并且你的 IaaS 提供商允许你配置 IPv6 地址 2001:db8::c000 ~ 2001:db8::c00f,你的网络配置应像下面一样。

1
2
3
4
5
6
7
8
9
10
$ ip -6 addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2001:db8::c001/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::601:3fff:fea1:9c01/64 scope link
valid_lft forever preferred_lft forever

To slit up the configurable address range into two subnets 2001:db8::c000/125 and 2001:db8::c008/125, use the following daemon.json settings. The first subnet is used by non-Docker processes on the host, and the second is used by Docker.

将配置的地址分开成 2001:db8::c000/125 与 2001:db8::c008/125,用下面的 daemon.json。第一个子网会被用在主机上,而第二个会被 Docker 使用。

1
2
3
4
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8::c008/125"
}

The Docker subnet is within the subnet managed by your router and connected to eth0. All containers with addresses assigned by Docker are expected to be found within the router subnet, and the router can communicate with these containers directly.

Docker 子网被路由管理并且连接到 eth0。所有的具有这个地址的容器被 Docker 分配并且会在路由的子网里被找到。路由器可以和这些容器直接通信。

IPv6 NDP proxying

When the router wants to send an IPv6 packet to the first container, it transmits a neighbor solicitation request, asking “Who has 2001:db8::c009?” However, no host on the subnet has the address; the container with the address is hidden behind the Docker host. The Docker host therefore must listen for neighbor solicitation requests and respond that it is the device with the address. This functionality is called the NDP Proxy and is handled by the kernel on the host machine. To enable the NDP proxy, execute the following command:

1
$ sysctl net.ipv6.conf.eth0.proxy_ndp=1

Next, add the container’s IPv6 address to the NDP proxy table:

1
$ ip -6 neigh add proxy 2001:db8::c009 dev eth0

From now on, the kernel answers neighbor solicitation addresses for this address on the device eth0. All traffic to this IPv6 address is routed through the Docker host, which forwards it to the container’s network according to its routing table via the docker0 device:

1
2
3
4
$ ip -6 route show

2001:db8::c008/125 dev docker0 metric 1
2001:db8::/64 dev eth0 proto kernel metric 256

Execute the ip -6 neigh add proxy … command for every IPv6 address in your Docker subnet. Unfortunately there is no functionality for adding a whole subnet by executing one command. An alternative approach would be to use an NDP proxy daemon such as ndppd.

Docker IPv6 cluster

Switched network environment

Using routable IPv6 addresses allows you to realize communication between containers on different hosts. Let’s have a look at a simple Docker IPv6 cluster example:

IPv6 switched network example

The Docker hosts are in the 2001:db8:0::/64 subnet. Host1 is configured to provide addresses from the 2001:db8:1::/64 subnet to its containers. It has three routes configured:

  • Route all traffic to 2001:db8:0::/64 via eth0
  • Route all traffic to 2001:db8:1::/64 via docker0
  • Route all traffic to 2001:db8:2::/64 via Host2 with IP 2001:db8::2

Host1 also acts as a router on OSI layer 3. When one of the network clients tries to contact a target that is specified in Host1’s routing table Host1 forwards the traffic accordingly. It acts as a router for all networks it knows: 2001:db8::/64, 2001:db8:1::/64, and 2001:db8:2::/64.

On Host2 we have nearly the same configuration. Host2’s containers gets IPv6 addresses from 2001:db8:2::/64. Host2 has three routes configured:

  • Route all traffic to 2001:db8:0::/64 via eth0
  • Route all traffic to 2001:db8:2::/64 via docker0
  • Route all traffic to 2001:db8:1::/64 via Host1 with IP 2001:db8:0::1

The difference to Host1 is that the network 2001:db8:2::/64 is directly attached to Host2 via its docker0 interface whereas Host2 reaches 2001:db8:1::/64 via Host1’s IPv6 address 2001:db8::1.

This way every container can contact every other container. The containers Container1- share the same subnet and contact each other directly. The traffic between Container1- and Container2-* are routed via Host1 and Host2 because those containers do not share the same subnet.

In a switched environment every host needs to know all routes to every subnet. You always need to update the hosts’ routing tables once you add or remove a host to the cluster.

Every configuration in the diagram that is shown below the dashed line is handled by Docker: The docker0 bridge IP address configuration, the route to the Docker subnet on the host, the container IP addresses and the routes on the containers. The configuration above the line is up to the user and can be adapted to the individual environment.