IPvlan 网络驱动

IPvlan 驱动程序使用户能够完全控制 IPv4 和 IPv6 地址分配。 VLAN 驱动程序在此基础上构建,使操作员能够完全控制 第 2 层 VLAN 标记,甚至为对底层网络集成感兴趣的用户提供 IPvlan L3 路由。对于抽象掉物理限制的覆盖部署, 请参阅 多主机覆盖 驱动程序。

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

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

选项

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

OptionDefaultDescription
ipvlan_model2Sets the IPvlan operating mode. Can be one of: l2, l3, l3s
ipvlan_flagbridgeSets the IPvlan mode flag. Can be one of: bridge, private, vepa
parentSpecifies the parent interface to use.

示例

先决条件

  • 本页上的示例都是单主机的。
  • 所有示例都可以在运行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

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

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标志,则会为用户创建一个dummy类型的netlink父接口,并将其用作父接口,从而有效地完全隔离网络。

以下两个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服务器托管在同一虚拟网络上将是一个合规性问题,同时也会规避分层防御深度架构的长期最佳实践。在使用Overlay驱动程序时,VLAN或等效的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来表示一个带有VLAN ID为10eth0子接口。等效的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的父接口,使用-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

一个关键的要点是,操作员有能力将他们的物理网络映射到他们的虚拟网络中,以便将容器集成到他们的环境中,而无需进行运营上的大修。NetOps将一个802.1Q中继放入Docker主机。那个虚拟链接将是网络创建时传入的-o parent=。对于未标记的(非VLAN)链接,它就像-o parent=eth0一样简单,或者对于带有VLAN ID的802.1Q中继,每个网络都会从网络映射到相应的VLAN/子网。

一个例子是,NetOps 提供 VLAN ID 和与 VLAN 相关的子网,这些 VLAN 通过以太网链路传递到 Docker 主机服务器。这些值在配置 Docker 网络时被插入到 docker network create 命令中。这些是持久化的配置,每次 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(桥接端口数据单元)的级联性质,这些BPDU在整个广播域(VLAN)中泛滥以查找和阻止拓扑环路。消除桥接域,或者至少将它们隔离到一对ToR(机架顶部交换机)中,将减少难以排除的桥接不稳定性。IPvlan L2模式非常适合仅通过一对ToR中继的隔离VLAN,这些ToR可以提供无环路、非阻塞的结构。更进一步的是通过IPvlan L3模式在边缘进行路由,这将故障域减少到仅本地主机。

  • L3模式需要位于与默认命名空间不同的子网上,因为它需要在默认命名空间中有一个指向IPvlan父接口的网络链接路由。
  • 本示例中使用的父接口是 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模式,该字段将被忽略。从容器内部查看容器路由表:

# 在L3模式容器内部
$$ 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通。这需要一个路由器来代理带有次级子网的请求。然而,只要它们共享相同的-o parent父链接,IPvlan L3将在不同的子网之间路由单播流量。

双栈 IPv4 IPv6 IPvlan L3 模式

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

与所有示例一样,不需要使用标记的VLAN接口。子接口可以与eth0eth1bond0或主机上除lo回环接口之外的任何其他有效接口交换。

你将看到的主要区别是,L3模式不会创建一个带有下一跳的默认路由,而是设置一个仅指向dev eth的默认路由,因为根据设计,ARP/广播/多播都被Linux过滤了。由于父接口本质上充当路由器,父接口的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地址的容器后,再启动一个具有相同v6地址的新容器时,可能会出现一个bug,它抛出以下类似地址未正确释放到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用户提供灵活性。