IPvlan 网络驱动程序

IPvlan 驱动程序让用户完全控制 IPv4 和 IPv6 寻址。 VLAN 驱动程序在此基础上,为操作员提供了对二层 VLAN 标记的完全控制,甚至为对底层网络集成的用户提供了 IPvlan 三层路由。对于抽象物理约束的覆盖部署,请参阅 多主机覆盖 驱动程序。

IPvlan 是一种对经过验证的网络虚拟化技术的全新改进。 Linux 实现非常轻量级,因为它们不使用传统的 Linux 网桥进行隔离,而是关联到 Linux 以太网接口或子接口,以强制网络之间的隔离以及与物理网络的连接。

IPvlan 提供了许多独特的功能,并在各种模式下为未来的创新提供了广阔的空间。这些方法的两个主要优势是,绕过 Linux 网桥带来的积极性能影响,以及由于减少了移动部件而带来的简单性。移除了传统上位于 Docker 主机网卡和容器接口之间的网桥,留下了一个简单的设置,由容器接口直接连接到 Docker 主机接口。这种结果使得面向外部的服务易于访问,因为在这些场景中不需要端口映射。

选项

下表描述了在使用 ipvlan 驱动程序创建网络时,可以传递给 --option 的特定于驱动程序的选项。

选项默认描述
ipvlan_model2设置 IPvlan 操作模式。可以是以下之一:l2l3l3s
ipvlan_flagbridge设置 IPvlan 模式标志。可以是以下之一:bridgeprivatevepa
parent指定要使用的父接口。

示例

前提条件

  • 本页上的示例均为单主机。
  • 所有示例都可以在运行 Docker 的单个主机上执行。任何使用子接口(如 eth0.10)的示例都可以替换为 eth0 或 Docker 主机上的任何其他有效父接口。带有 . 的子接口是动态创建的。-o parent 接口也可以完全从 docker network create 中省略,驱动程序将创建一个 dummy 接口,使本地主机能够连接以执行示例。
  • 内核要求:
    • IPvlan Linux内核 v4.2+(支持更早的内核版本,但存在错误)。要检查当前的内核版本,请使用 uname -r

IPvlan L2 模式示例用法

IPvlan L2 模式拓扑的示例如下图所示。 该驱动通过 -d driver_name 选项指定。在这种情况下 -d ipvlan

Simple IPvlan L2 Mode Example

下一个示例中的父接口 -o parent=eth0 配置如下:

$ ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0

使用主机接口的网络作为 --subnetdocker network create 中。容器将连接到与通过 -o parent= 选项设置的主机接口相同的网络。

创建 IPvlan 网络并运行连接到它的容器:

# IPvlan  (-o ipvlan_mode= Defaults to L2 mode if not specified)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o ipvlan_mode=l2 \
    -o parent=eth0 db_net

# Start a container on the db_net network
$ docker run --net=db_net -it --rm alpine /bin/sh

# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.

IPvlan 的默认模式是 l2。如果未指定 -o ipvlan_mode=, 则将使用默认模式。同样,如果 --gateway 为空,则 网络上的第一个可用地址将被设置为网关。例如,如果 在网络创建中提供的子网是 --subnet=192.168.1.0/24,那么 容器接收到的网关是 192.168.1.1

为了帮助理解该模式如何与其他主机交互,下图展示了两个 Docker 主机之间的相同二层网段,适用于 IPvlan L2 模式。

Multiple IPvlan hosts

以下内容将创建与之前创建的网络 db_net 完全相同的网络,并使用 --gateway=192.168.1.1-o ipvlan_mode=l2 的默认驱动程序。

# IPvlan  (-o ipvlan_mode= Defaults to L2 mode if not specified)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    -o parent=eth0 db_net_ipv

# Start a container with an explicit name in daemon mode
$ docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh

# Start a second container and ping using the container name
# to see the docker included name resolution functionality
$ docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
$ ping -c 4 ipv1

# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.

驱动程序还支持 --internal 标志,该标志将完全隔离网络上的容器与该网络之外的任何通信。由于网络隔离与网络的父接口紧密相关,因此在 docker network create 上省略 -o parent= 选项的结果与 --internal 选项完全相同。如果未指定父接口或使用了 --internal 标志,则会为用户创建一个 netlink 类型 dummy 的父接口,并将其用作父接口,从而完全隔离网络。

以下两个 docker network create 示例生成的网络相同,您可以将容器附加到该网络:

# Empty '-o parent=' creates an isolated network
$ docker network create -d ipvlan \
    --subnet=192.168.10.0/24 isolated1

# Explicit '--internal' flag is the same:
$ docker network create -d ipvlan \
    --subnet=192.168.11.0/24 --internal isolated2

# Even the '--subnet=' can be left empty and the default
# IPAM subnet of 172.18.0.0/16 will be assigned
$ docker network create -d ipvlan isolated3

$ docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
$ docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
$ docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh

# To attach to any use `docker exec` and start a shell
$ docker exec -it cid1 /bin/sh
$ docker exec -it cid2 /bin/sh
$ docker exec -it cid3 /bin/sh

IPvlan 802.1Q 中继 L2 模式使用示例

从架构上讲,IPvlan L2模式中继在网关和L2路径隔离方面与Macvlan相同。 在ToR交换机的CAM表压力、每个端口一个MAC以及主机父NIC上的MAC耗尽等方面,存在一些细微的差别。 802.1Q中继场景看起来是一样的。 两种模式都遵循标记标准,并且与物理网络无缝集成,用于底层集成和硬件供应商插件集成。

同一 VLAN 上的主机通常位于同一子网中,并且几乎总是根据其安全策略进行分组。在大多数场景中,多层应用程序被划分为不同的子网,因为每个进程的安全配置需要某种形式的隔离。例如,将信用卡处理托管在与前端 Web 服务器相同的虚拟网络中会违反监管合规要求,同时也违背了长期存在的纵深防御架构最佳实践。VLAN 或在使用 Overlay 驱动程序时的等效 VNI(虚拟网络标识符),是隔离租户流量的第一步。

Docker VLANs in-depth

带有 VLAN 标记的 Linux 子接口可以已经存在,或者在您调用 docker network create 时创建。docker network rm 将删除子接口。诸如 eth0 之类的父接口不会被删除,仅删除 netlink 父索引 > 0 的子接口。

为了驱动程序能够添加/删除 VLAN 子接口,格式需要为 interface_name.vlan_tag。可以使用其他子接口命名作为 指定的父接口,但当 docker network rm 被调用时,链接不会自动删除。

选择使用现有的父VLAN子接口或让Docker管理它们,使用户能够完全管理Linux接口和网络,或者让Docker创建和删除VLAN父子接口(netlink ip link),而无需用户付出任何努力。

例如:使用 eth0.10 表示 eth0 的一个子接口,该子接口带有 VLAN id 10。等效的 ip link 命令将是 ip link add link eth0 name eth0.10 type vlan id 10

该示例创建带有 VLAN 标签的网络,然后启动两个容器以测试容器之间的连通性。在没有路由器在两个网络之间进行路由的情况下,不同的 VLAN 无法相互 ping 通。根据 IPvlan 的设计,默认命名空间不可达,以便将容器命名空间与底层主机隔离。

VLAN ID 20

在由 Docker 主机标记和隔离的第一个网络中,eth0.20 是带有 VLAN id 20 的父接口,该 id 是通过 -o parent=eth0.20 指定的。 可以使用其他命名格式,但需要使用 ip link 或 Linux 配置文件手动添加和删除链接。 只要 -o parent 存在,只要符合 Linux netlink,就可以使用任何内容。

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.20.0/24 \
    --gateway=192.168.20.1 \
    -o parent=eth0.20 ipvlan20

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
$ docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh

VLAN ID 30

在第二个网络中,由Docker主机标记和隔离,eth0.30是带有VLAN id 30的父接口,由-o parent=eth0.30指定。ipvlan_mode=默认为l2模式ipvlan_mode=l2。它也可以显式设置,结果相同,如下一个示例所示。

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged.
$ docker network create -d ipvlan \
    --subnet=192.168.30.0/24 \
    --gateway=192.168.30.1 \
    -o parent=eth0.30 \
    -o ipvlan_mode=l2 ipvlan30

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
$ docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh

网关在容器内部被设置为默认网关。该网关通常是网络上的外部路由器。

$$ ip route
  default via 192.168.30.1 dev eth0
  192.168.30.0/24 dev eth0  src 192.168.30.2

示例:在多子网 IPvlan L2 模式下启动两个位于同一子网的容器并互相进行 ping 测试。为了使 192.168.114.0/24 能够到达 192.168.116.0/24,在 L2 模式下需要外部路由器。L3 模式可以在共享公共 -o parent= 的子网之间进行路由。

在网络路由器上使用辅助地址是很常见的,当地址空间耗尽时,可以在L3 VLAN接口上添加另一个辅助地址,通常称为“交换虚拟接口”(SVI)。

$ docker network create -d ipvlan \
    --subnet=192.168.114.0/24 --subnet=192.168.116.0/24 \
    --gateway=192.168.114.254 --gateway=192.168.116.254 \
    -o parent=eth0.114 \
    -o ipvlan_mode=l2 ipvlan114

$ docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
$ docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh

一个关键要点是,操作员能够将其物理网络映射到虚拟网络中,以便将容器集成到其环境中,而无需进行运营 overhaul。NetOps 将一个 802.1Q trunk 放入 Docker 主机。该虚拟链路将是网络创建中传递的 -o parent=。对于未标记(非 VLAN)的链路,就像 -o parent=eth0 一样简单;对于带有 VLAN ID 的 802.1Q trunks,每个网络都会映射到网络中相应的 VLAN/子网。

例如,NetOps 提供了 VLAN ID 和关联的子网,这些 VLAN 通过以太网链路传递到 Docker 主机服务器。这些值被插入到 docker network create 命令中,用于配置 Docker 网络。这些是持久化配置,每次 Docker 引擎启动时都会应用,从而避免了管理通常复杂的配置文件的需要。网络接口也可以通过预先创建来手动管理,Docker 网络不会修改它们,并将它们用作父接口。从 NetOps 到 Docker 网络命令的示例映射如下:

  • VLAN: 10, 子网: 172.16.80.0/24, 网关: 172.16.80.1
    • --subnet=172.16.80.0/24 --gateway=172.16.80.1 -o parent=eth0.10
  • VLAN: 20, IP子网: 172.16.50.0/22, 网关: 172.16.50.1
    • --subnet=172.16.50.0/22 --gateway=172.16.50.1 -o parent=eth0.20
  • VLAN: 30, 子网: 10.1.100.0/16, 网关: 10.1.100.1
    • --subnet=10.1.100.0/16 --gateway=10.1.100.1 -o parent=eth0.30

IPvlan L3 模式示例

IPvlan 需要将路由分发到每个端点。驱动程序仅构建 IPvlan L3 模式端口并将容器连接到接口。在整个集群中分发路由超出了此单主机范围驱动程序的初始实现范围。在 L3 模式下,Docker 主机非常类似于在容器中启动新网络的路由器。它们位于上游网络在未分发路由的情况下无法知道的网络中。对于那些好奇 IPvlan L3 如何融入容器网络的人,请参阅以下示例。

Docker IPvlan L2 mode

IPvlan L3 模式会丢弃所有广播和多播流量。这一特点使得 IPvlan L3 模式成为那些追求大规模和可预测网络集成的首选方案。它是可预测的,并且因为不涉及桥接,从而能带来更高的正常运行时间。桥接环路曾导致一些备受关注的故障,这些故障可能难以定位,具体取决于故障域的大小。这是由于 BPDU(桥端口数据单元)的级联特性,它们在整个广播域(VLAN)中泛洪以发现并阻止拓扑环路。消除桥接域,或者至少将它们隔离在一对 ToR(机架顶部交换机)中,将减少难以排查的桥接不稳定性。IPvlan L2 模式非常适合仅通过一对 ToR 中继的隔离 VLAN,这些 ToR 可以提供无环路、无阻塞的 fabric。进一步的步骤是通过 IPvlan L3 模式在边缘进行路由,这将故障域缩小到仅限本地主机。

  • L3 模式需要位于与默认命名空间不同的子网上,因为它需要在默认命名空间中有一个指向 IPvlan 父接口的 netlink 路由。
  • 本示例中使用的父接口是 eth0,它位于子网 192.168.1.0/24 上。注意 docker network 不在与 eth0 相同的子网上。
  • 与 IPvlan l2 模式不同,只要它们共享相同的父接口 -o parent=,不同的子网/网络就可以互相 ping 通。
$$ ip a show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:39:45:2e brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
  • 传统的网关对于 L3 模式的 IPvlan 接口来说意义不大,因为不允许广播流量。因此,容器的默认网关指向容器的 eth0 设备。有关详细信息,请参阅下文中从 L3 容器内部执行的 ip routeip -6 route 的 CLI 输出。

必须显式指定模式 -o ipvlan_mode=l3,因为默认的 IPvlan 模式是 l2

以下示例未指定父接口。网络驱动程序将为用户创建一个虚拟类型的链路,而不是拒绝网络创建并仅允许容器之间进行通信。

# Create the IPvlan L3 network
$ docker network create -d ipvlan \
    --subnet=192.168.214.0/24 \
    --subnet=10.1.214.0/24 \
    -o ipvlan_mode=l3 ipnet210

# Test 192.168.214.0/24 connectivity
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh

# Test L3 connectivity from 10.1.214.0/24 to 192.168.214.0/24
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10

# Test L3 connectivity from 192.168.214.0/24 to 10.1.214.0/24
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10

注意

请注意,在网络创建中不存在 --gateway= 选项。如果在 l3 模式下指定了该字段,则会被忽略。让我们从容器内部查看容器的路由表:

# Inside an L3 mode container
$$ ip route
 default dev eth0
  192.168.214.0/24 dev eth0  src 192.168.214.10

为了从远程 Docker 主机 ping 容器,或者容器能够 ping 远程主机,远程主机或中间的物理网络需要有一条指向容器 Docker 主机 eth 接口的主机 IP 地址的路由。

双栈 IPv4 IPv6 IPvlan L2 模式

  • Libnetwork 不仅为您提供对 IPv4 地址的完全控制,而且还为您提供对 IPv6 地址的完全控制,以及这两种地址系列之间的功能对等性。

  • 下一个示例将仅使用 IPv6 启动。在同一个 VLAN 139 上启动两个容器并互相 ping。由于未指定 IPv4 子网, 默认 IPAM 将配置一个默认的 IPv4 子网。除非上游网络在 VLAN 139 上 显式路由该子网,否则该子网是隔离的。

# Create a v6 network
$ docker network create -d ipvlan \
    --ipv6 --subnet=2001:db8:abc2::/64 --gateway=2001:db8:abc2::22 \
    -o parent=eth0.139 v6ipvlan139

# Start a container on the network
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh

查看容器 eth0 接口和 v6 路由表:

# Inside the IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc2::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc2::22 dev eth0  metric 1024

启动第二个容器并 ping 第一个容器的 v6 地址。

# Test L2 connectivity over IPv6
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh

# Inside the second IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link tentative dadfailed
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::2/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ping6 2001:db8:abc2::1
PING 2001:db8:abc2::1 (2001:db8:abc2::1): 56 data bytes
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=1 ttl=64 time=0.058 ms

2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.044/0.051/0.058/0.000 ms

下一个示例将设置一个双栈 IPv4/IPv6 网络,示例 VLAN ID 为 140

接下来创建一个网络,包含两个 IPv4 子网和一个 IPv6 子网,所有子网都 有明确的网关:

$ docker network create -d ipvlan \
    --subnet=192.168.140.0/24 --subnet=192.168.142.0/24 \
    --gateway=192.168.140.1 --gateway=192.168.142.1 \
    --subnet=2001:db8:abc9::/64 --gateway=2001:db8:abc9::22 \
    -o parent=eth0.140 \
    -o ipvlan_mode=l2 ipvlan140

启动容器并查看 eth0 以及 IPv4 和 IPv6 路由表:

$ docker run --net=ipvlan140 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh

$ ip a show eth0
78: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.140.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc9::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip route
default via 192.168.140.1 dev eth0
192.168.140.0/24 dev eth0  proto kernel  scope link  src 192.168.140.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc9::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc9::22 dev eth0  metric 1024

使用特定 --ip4 地址启动第二个容器,并使用 IPv4 数据包 ping 第一个主机:

$ docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh

注意

在 IPvlan L2 模式下,同一父接口上的不同子网无法互相 ping 通。这需要路由器通过辅助子网对请求进行代理 ARP。然而,只要它们共享相同的 -o parent 父链路,IPvlan L3 将在不同子网之间路由单播流量。

双栈 IPv4 IPv6 IPvlan L3 模式

示例:IPvlan L3 模式双栈 IPv4/IPv6,多子网带 802.1Q VLAN 标签:118

在所有示例中,并不一定要使用带标签的 VLAN 接口。子接口可以替换为 eth0eth1bond0 或主机上除 lo 回环接口之外的任何其他有效接口。

您将看到的主要区别是,L3 模式不会创建带有下一跳的默认路由,而是设置一个仅指向 dev eth 的默认路由,因为根据设计,Linux 会过滤 ARP/广播/多播。由于父接口实际上充当路由器,父接口的 IP 和子网需要与容器网络不同。这与桥接和 L2 模式相反,后者需要位于同一子网(广播域)中才能转发广播和多播数据包。

# Create an IPv6+IPv4 Dual Stack IPvlan L3 network
# Gateways for both v4 and v6 are set to a dev e.g. 'default dev eth0'
$ docker network create -d ipvlan \
    --subnet=192.168.110.0/24 \
    --subnet=192.168.112.0/24 \
    --subnet=2001:db8:abc6::/64 \
    -o parent=eth0 \
    -o ipvlan_mode=l3 ipnet110


# Start a few of containers on the network (ipnet110)
# in separate terminals and check connectivity
$ docker run --net=ipnet110 -it --rm alpine /bin/sh
# Start a second container specifying the v6 address
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
# Start a third specifying the IPv4 address
$ docker run --net=ipnet110 --ip=192.168.112.30 -it --rm alpine /bin/sh
# Start a 4th specifying both the IPv4 and IPv6 addresses
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh

接口和路由表的输出如下:

$$ ip a show eth0
63: eth0@if59: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.112.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc6::10/64 scope link nodad
       valid_lft forever preferred_lft forever

# Note the default route is the eth device because ARPs are filtered.
$$ ip route
  default dev eth0  scope link
  192.168.112.0/24 dev eth0  proto kernel  scope link  src 192.168.112.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc6::/64 dev eth0  proto kernel  metric 256
default dev eth0  metric 1024

注意

在删除一个具有指定 v6 地址的容器时,指定 --ip6= 地址可能会出现错误。然后,当你启动一个具有相同 v6 地址的新容器时,会抛出以下错误,就像地址没有正确释放到 v6 地址池一样。它将无法卸载该容器,并处于死锁状态。

docker: Error response from daemon: Address already in use.

VLAN ID 40

如果用户不希望驱动程序创建 VLAN 子接口,则需要在运行 docker network create 之前就存在。如果您的子接口命名不是 interface.vlan_id,只要该接口存在且处于活动状态,它将在 -o parent= 选项中再次被认可。

手动创建的链接,只要在网络创建时存在,可以任意命名。当使用 docker network rm 删除网络时,无论名称如何,手动创建的链接都不会被删除。

# create a new sub-interface tied to dot1q vlan 40
$ ip link add link eth0 name eth0.40 type vlan id 40

# enable the new sub-interface
$ ip link set eth0.40 up

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 \
    --gateway=192.168.40.1 \
    -o parent=eth0.40 ipvlan40

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh

示例:手动创建的 VLAN 子接口,可使用任意名称:

# create a new sub interface tied to dot1q vlan 40
$ ip link add link eth0 name foo type vlan id 40

# enable the new sub-interface
$ ip link set foo up

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 --gateway=192.168.40.1 \
    -o parent=foo ipvlan40

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh

手动创建的链接可以通过以下方式进行清理:

$ ip link del foo

与所有 Libnetwork 驱动程序一样,它们可以混合搭配,甚至可以并行运行第三方生态系统驱动程序,从而为 Docker 用户提供最大的灵活性。