尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Moby macvlan 网络驱动详解:容器直连物理网络、802.1Q VLAN Trunk 与双栈实战

Moby macvlan 网络驱动详解:容器直连物理网络、802.1Q VLAN Trunk 与双栈实战 Moby macvlan 网络驱动详解容器直连物理网络、802.1Q VLAN Trunk 与双栈实战【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby本文基于 Moby 仓库中 macvlan 驱动官方文档系统讲解 macvlan 内建网络驱动如何绕过 Linux 网桥与 NAT把容器接口直接挂接到宿主机物理网卡或其 VLAN 子接口上实现与数据中心现有 L2 网络无缝集成。读完后你将掌握docker network create -d macvlan的完整参数体系--subnet、--gateway、-o parent、-o macvlan_mode、--ip-range、--aux-address、bridge 模式、802.1Q Trunking、多子网与 IPv4/IPv6 双栈的实操方法并能对照 驱动源码 理解子接口自动创建/回收、网关注入与内核级过滤行为的底层机制。一、macvlan 驱动概述无 NAT、无网桥的直连架构macvlan 驱动让运维人员能够以简单、轻量级的方式把容器网络融入底层物理网络。macvlan 是 Linux 内核原生支持的成熟网络类型Moby 的内建 macvlan 驱动不需要任何端口映射并且支持 VLAN trunking虚拟局域网。VLAN 是传统的网络虚拟化与二层数据路径隔离手段在各类数据中心中普遍存在。与 bridge 驱动相比macvlan 的核心差异在于数据路径不经过宿主机网桥。传统 bridge 方案要把容器接口接到 Docker 宿主机的 Linux 网桥上再通过两种方式打通外部网络一是用 iptables 规则对网桥做 NAT 转换好处是网卡无需混杂模式二是把宿主机外部以太网口直接移入网桥——这种方式风险较高配置失误可能把宿主机自己踢出网络甚至造成桥接环路bridging loop在整个数据中心的 VLAN 范围内瘫痪流量。容器接口直接挂到宿主机以太网接口或其子接口上。每个网络network绑定一个唯一的父接口parent interface。同一网络内的容器共享同一个广播域网络内部互通是允许的两个不同网络各自绑定不同的父接口父接口就构成了两个网络之间的数据路径隔离。跨网络通信需要 Docker 宿主机之外的 IP 路由器在两个网络之间做路由流量hairpin绕回到物理网络后再回到宿主机。hairpin 流量效率虽不如留在宿主机本地的东西向流量但许多用户正是希望复用数据中心中现成的网络服务防火墙、负载均衡器等这种取舍在实践上是合理的。性能与可观测性收益。绕过 Linux 网桥带来正向的性能影响同时减少活动部件、简化架构。macvlan 容器很容易排障容器的真实 MAC 地址和 IP 地址直接桥接进了上游网络出问题的应用可以被网络侧工具直接从链路上追踪现有的底层网络管理和监控工具保持可用。该驱动要求对底层宿主机有完全访问权限因此适合拥有宿主机管理员权限的企业级数据中心场景。前置条件文档中所有示例均为单主机场景要求 Linux 上的 Docker v1.12 或更高版本当前 Moby 仓库实现远超过此要求。任何使用eth0.10这类子接口sub-interface的示例都可以替换为eth0或宿主机上任意有效的父接口。带.的子接口是动态创建的父接口参数-o parent也可以完全省略此时驱动会创建一个dummy类型的 Linux 接口仅支持宿主机本地容器之间的连通性用于完成示例练习。内核要求可用uname -r查看当前内核版本macvlan 要求 Linux 内核v3.9–3.19 及 4.0。源码层面macvlan 驱动仅编译于 Linux 平台入口文件 macvlan.go 首行即为//go:build linux驱动在 Register 函数 中注册声明DataScope: scope.Local、ConnectivityScope: scope.Global——即网络数据是节点本地的但连通性面向全局。二、Bridge 模式基础用法macvlan 驱动网络必须挂接到一个父接口上父接口可以是物理接口如eth0802.1q VLAN 打标签的子接口如eth0.10.10即 VLAN 10甚至绑定接口bond0——把两个以太网口捆绑成单一逻辑接口提供链路冗余。关键行为约定网关是宿主机外部的预期由网络基础设施提供。若未用--gateway指定Libnetwork 会推断子网的第一个可用地址作为网关--subnet 10.1.100.0/24对应网关10.1.100.1--subnet 10.1.100.128/25对应网关10.1.100.129。这个推断行为在源码中得到印证GetSkipGwAlloc 返回true, true注释明确说明网关必须位于 Docker macvlan 网络之外驱动不把它分配给任何东西。不同网络上的容器之间没有外部路由介入时无法互相到达。每个 macvlan bridge 模式网络彼此隔离一个父接口同一时刻只允许挂一个 macvlan 网络passthru 模式有更严格的独占检查见下文源码分析。每个宿主机网卡理论上最多可挂 4,094 个子接口VLAN ID 1–4094。驱动限制每个父接口一个网络但允许在同一个 Docker 网络里分配多个子网multi-subnet 需求由上游路由器在两个子网之间做 proxy-arping。同一子网内的容器可以直接通过 IP 通信无需网关。注意只要有容器挂到父接口上父接口就会进入混杂模式promiscuous mode因为每个容器拥有独立的 MAC 地址。作为对照目前仍处于实验阶段的 ipvlan 驱动复用父接口的 MAC 地址因此不需要父接口开启混杂模式。完整示例父接口 eth0网段 172.16.86.0/24在下面的示例中Docker 宿主机eth0位于172.16.86.0/24网络默认网关172.16.86.1一个外部路由器。bridge 模式下eth0上并不要求有 IP 地址它只需处于正确的上游网络能被交换机或路由器转发即可。注意Docker 网络指定的子网必须与宿主机父接口所在网络匹配对外通信时。请使用与-o parent指定的宿主机以太网接口相同的子网和网关。父接口本身不要求分配 IP 地址因为这只是 L2 泛洪flooding与学习learning。父接口eth0配置如下ip addr show eth0 3: eth0: BROADCAST,MULTICAST,UP,LOWER_UP mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 172.16.86.250/24 brd 172.16.86.255 scope global eth0创建 macvlan 网络并运行两个容器# Macvlan (-o macvlan_mode 未指定时默认为 bridge 模式) docker network create -d macvlan \ --subnet172.16.86.0/24 \ --gateway172.16.86.1 \ -o parenteth0 pub_net # 在新网络上运行容器并显式指定 --ip 地址 docker run --netpub_net --ip172.16.86.10 -itd alpine /bin/sh # 启动第二个容器并 ping 第一个容器 docker run --netpub_net -it --rm alpine /bin/sh ping -c 4 172.16.86.10查看容器内的 IP 与路由表ip a show eth0 eth0if3: BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN mtu 1500 qdisc noqueue state UNKNOWN link/ether 46:b2:6b:26:2f:69 brd ff:ff:ff:ff:ff:ff inet 172.16.86.2/24 scope global eth0 ip route default via 172.16.86.1 dev eth0 172.16.86.0/24 dev eth0 src 172.16.86.2 # 注意容器无法 ping 底层宿主机的接口地址 # 因为 Linux 内核有意过滤这类流量以实现额外隔离。 # 本例中容器无法 ping -o parent 的 172.16.86.250用户可以用-o macvlan_modebridge显式指定 bridge 模式也可以省略该选项——bridge 是驱动默认值也是最常见的模式。IPAM 相关参数--aux-address 与 --ip-range虽然eth0接口不必须有 IP 地址但实际环境中给父接口分配 IP 很常见。可以用--aux-addressx.x.x.x把指定地址从内建 IPAM 的分配中拉黑防止它被分给容器# 与上面相同的网络示例但把 -o parenteth0 的地址从可分配池中排除 docker network create -d macvlan \ --subnet172.16.86.0/24 \ --gateway172.16.86.1 \ --aux-addressexclude_host172.16.86.250 \ -o parenteth0 pub_net另一种控制可用地址子池/区间的方式是--ip-range指示驱动从该特定区间分配容器地址而不是从--subnet指定的更大范围分配。下面示例中地址从192.168.32.128开始按 n1 递增分配docker network create -d macvlan \ --subnet192.168.32.0/24 \ --ip-range192.168.32.128/25 \ --gateway192.168.32.254 \ -o parenteth0 macnet32 # 启动容器并验证地址为 192.168.32.128 docker run --netmacnet32 -it --rm alpine /bin/sh网络删除docker network rm network_name or id常见坑gotchaLinux macvlan 接口类型无法 ping 或访问默认命名空间中的 IP 地址。例如创建容器后去 ping Docker 宿主机的eth0是不会成功的——该流量被内核显式过滤用于提供额外的提供方隔离与安全。这是用户初次接触这类 Linux 接口时最常见的困惑因为测试时自然会先 ping 本地地址。源码视角驱动如何解析选项与处理父接口结合 macvlan_network.go 的实现文档中的行为都有明确的代码依据选项解析驱动只识别两个通用选项常量定义在 macvlan.go#L14-L25parent-o parent与macvlan_mode。parseNetworkOptions 中macvlan_mode为空时默认置为bridge合法取值为bridge、private、passthru、vepa四种否则报错。此外lo回环接口被显式拒绝为父接口若-o parent为空网络会被标记为internal无外部连通性。父接口不存在时的自动创建createNetwork 中若父接口不存在父接口是dm-前缀的 dummy 名时调用 createDummyLink 创建 dummy 接口否则调用 createVlanLink 按iface.vlan_id格式解析并创建 802.1Q 子接口——VLAN ID 校验为1–409412 位字段创建后自动LinkSetUp置起接口。驱动创建的从属链路会记录CreatedSlaveLink true为后续回收做准备。删除网络时的链路回收DeleteNetwork 只在驱动自己创建的从属接口 该网络是唯一使用者parentHasSingleUser检查时才删除 VLAN 子接口或 dummy 接口否则保留对 macvlan 和 ipvlan 同挂一个父接口的情形注释说明了同一父接口上只能有一个从属接口处于激活状态的限制。passthru 模式独占性createNetwork 中若已有网络占用同一父接口且新旧网络任一方是passthru模式直接报错拒绝——这就是每个父接口一个网络限制在 passthru 下的严格执行。三、容器接入流程Join 阶段的 macvlan 接口创建与网关注入文档中容器获得真实 MAC/IP 直通上游网络的现象发生在端点 Join 阶段。Join 方法macvlan_joinleave.go的完整流程是用veth前缀生成一个宿主机侧临时接口名如vethxxxxxxxx调用 createMacVlan通过 netlink 的LinkAdd在父接口上创建 macvlan 从属接口模式由 setMacVlanMode 映射到netlink.MACVLAN_MODE_BRIDGE/PRIVATE/VEPA/PASSTHRU将端点的 IPv4/IPv6 地址与网络子网做匹配getSubnetForIP要求掩码长度一致且 IP 被包含子网配置了GwIP就调用jinfo.SetGateway / SetGatewayIPv6写入默认路由——这就是容器内ip route中default via gateway dev eth0的来源未配置网关时走ForceGw4/ForceGw6保留旧行为调用jinfo.DisableGatewayService()关闭网桥类驱动才需要的网关服务把宿主机侧的 macvlan 接口重命名映射为容器内的eth0前缀eth与文档示例中eth0if3的命名一致。MAC 地址方面CreateEndpointmacvlan_endpoint.go在接口信息未带 MAC 时调用netutils.GenerateRandomMAC()生成随机 MAC——这正是每个容器拥有唯一 MAC 地址、父接口进入混杂模式的实现根源。同一文件还显式拒绝端口映射-p与端口暴露--expose检测到相关选项时仅记录警告macvlan driver does not support port mappings——与文档概述内建 macvlan 驱动不需要任何端口映射相呼应说明容器流量本身就是以真实地址出现在物理网络上无需转换。四、802.1Q Trunk Bridge 模式一个网卡跑多个虚拟网络VLAN 长期以来一直是虚拟化数据中心网络的主要手段在几乎所有现有网络中仍在使用。VLAN 通过在二层隔离域上打一个 **12 位标识符1–4094**的标签工作。VLAN 标签插入报文头部实现单个子网或多个 IPv4/IPv6 子网的逻辑分组。网络运维常见做法是按子网功能或安全画像如web、db等隔离需求用 VLAN 分隔流量。计算宿主机上同时运行多个虚拟网络是常见需求。Linux 网络长期支持 VLAN 打标签标准 802.1Q用于维护网络之间的数据路径隔离。连接 Docker 宿主机的以太网链路可以通过创建 Linux 子接口来支持 802.1q VLAN ID每个子接口分配一个唯一的 VLAN ID。把 802.1q Trunk 接到 Linux 宿主机对运维来说 notoriously 痛苦需要修改配置文件才能重启后持久化若涉及网桥物理网卡需要移入网桥、网桥再获取 IP 地址。由于切断访问或配置失误的风险较高导致许多服务器搁浅stranded。和其他 Docker 网络驱动一样总目标是减轻网络资源管理的运维之痛。为此当网络收到一个尚不存在的子接口作为父接口时驱动会在创建网络的同时创建 VLAN 打标签的接口子接口若已存在则直接使用。宿主机重启时无需修改往往复杂的网络配置文件驱动会在 Docker 守护进程重启时重建所有网络链路。驱动会跟踪该 VLAN 子接口最初是否由网络创建时由驱动生成并且只有在驱动最初创建过该链路时才会在重启后重建。docker network rm删除网络时同理若子接口是驱动用docker network create创建的会替运维删除该子接口链路。若用户不希望 Docker 创建/删除-o parent子接口只需传入一个已存在的接口作为父链路。eth0这类父接口不会被删除只有从属slave链路才会。驱动增删 VLAN 子接口要求-o parent interface_name.vlan_tag的格式。例如-o parent eth0.50表示父接口eth0、从属接口eth0.50、VLAN ID50。等价的ip link命令是ip link add link eth0 name eth0.50 type vlan id 50。将-d驱动参数中的macvlan替换为ipvlan即可创建 ipvlan 的 802.1q trunk。该行为与源码完全对应createVlanLink中按strings.Contains(parentName, .)判定子接口parseVlan 强制名字.vlan_id两段格式、校验 VLAN ID 范围并确认主接口存在而delVlanLink对不能解析成iface.vlan_id的命名即用户自定义名称一律保留不删——即文档所说手工创建的链路无论如何命名都不会被删除。示例一VLAN ID 50网络在 Docker 宿主机上打标签并隔离eth0.50作为父接口把以太网流量打上vlan id 50标签由-o parenteth0.50的父接口命名约定指定。其他命名格式也可以使用但那样的链路需要手工用ip link或 Linux 配置文件增删。只要-o parent存在且符合 Linux netlink 规范用什么名字都行。# 像往常一样添加网络和主机挂到已打标签的 master (sub)interface 上 docker network create -d macvlan \ --subnet192.168.50.0/24 \ --gateway192.168.50.1 \ -o parenteth0.50 macvlan50 # 在两个终端中各启动一个容器容器之间现在可以互 ping docker run --netmacvlan50 -it --name macvlan_test5 --rm alpine /bin/sh docker run --netmacvlan50 -it --name macvlan_test6 --rm alpine /bin/sh示例二VLAN ID 60显式指定 macvlan_mode第二个网络同样在宿主机上打标签隔离eth0.60是打 vlan id60标签的父接口-o parenteth0.60。macvlan_mode默认是macvlan_modebridge显式设置结果相同如下例所示# 像往常一样添加网络和主机挂到已打标签的 master (sub)interface 上 docker network create -d macvlan \ --subnet192.168.60.0/24 \ --gateway192.168.60.1 \ -o parenteth0.60 \ -o macvlan_modebridge macvlan60 # 在两个终端中各启动一个容器容器之间现在可以互 ping docker run --netmacvlan60 -it --name macvlan_test7 --rm alpine /bin/sh docker run --netmacvlan60 -it --name macvlan_test8 --rm alpine /bin/sh示例三多子网 macvlan 802.1Q Trunking与前一示例相同但网络绑定了额外的子网用户可以选择在上面供给容器。macvlan/bridge 模式下容器只有在同一子网/广播域内才能互 ping除非有外部路由器在两个子网之间做路由回应 ARP 等。为网络分配多个子网需要一个宿主机外部、落在子网范围内的网关把流量 hairpin 回宿主机。docker network create -d macvlan \ --subnet10.1.20.0/24 --subnet10.1.10.0/24 \ --gateway10.1.20.1 --gateway10.1.10.1 \ -o parenteth0.101 mcv101 # 网络创建后查看链路 ip link $ ip link # 测试 10.1.20.0/24 的连通性 docker run --netmcv101 --ip10.1.20.9 -itd alpine /bin/sh docker run --netmcv101 --ip10.1.20.10 -it --rm alpine ping -c 4 10.1.20.9 # 测试 10.1.10.0/24 的连通性 docker run --netmcv101 --ip10.1.10.10 -itd alpine /bin/sh docker run --netmcv101 --ip10.1.10.9 -it --rm alpine ping -c 4 10.1.10.10 # 删除所有容器 docker rm -f docker ps -qa # 删除所有网络 docker network rm $(docker network ls -q) # 再次运行 ip link验证链路已清理干净 ip link同一 VLAN 上的主机通常位于同一子网且几乎总是按安全策略分组。多数场景下多层应用的不同层位于不同子网因为每个进程的安全画像要求某种形式的隔离。例如把信用卡处理与前端的 web 服务器放在同一个虚拟网络上会成为合规问题也违背纵深防御的分层架构最佳实践。VLAN或使用内建 Overlay 驱动时等价的 VNIVirtual Network Identifier是隔离租户流量的第一步。NetOps 交付值 → docker network create 的映射范式关键收获运维人员可以把物理网络映射到虚拟网络把容器集成进现有环境而无需运营层面的大改造。NetOps 只需把一根 802.1q trunk 接入 Docker 宿主机这条虚拟链路就是网络创建时传入的-o parent。对于无标签非 VLAN链路简单到-o parenteth0对于带 VLAN ID 的 802.1q trunk每个网络映射到对应的 VLAN/子网即可。例如NetOps 提供接入 Docker 宿主机以太网链路的 VLAN ID 及对应子网。这些值直接填入docker network create命令即可。这些是持久化配置每次 Docker 引擎启动都会重新应用从而免去管理往往复杂的配置文件。网络接口也可以预先手工创建来管理——Docker 网络永远不修改它们只是把它们当父接口使用。从 NetOps 到 Docker 网络命令的映射示例如下VLAN: 10子网: 172.16.80.0/24网关: 172.16.80.1--subnet172.16.80.0/24 --gateway172.16.80.1 -o parenteth0.10VLAN: 20子网: 172.16.50.0/22网关: 172.16.50.1--subnet172.16.50.0/22 --gateway172.16.50.1 -o parenteth0.20VLAN: 30子网: 10.1.100.0/16网关: 10.1.100.1--subnet10.1.100.0/16 --gateway10.1.100.1 -o parenteth0.30五、手工创建 802.1Q 链路如果用户不希望驱动创建 VLAN 子接口只需在docker network create之前让该接口存在即可。若子接口命名不是interface.vlan_id形式-o parent同样会尊重它——前提是接口存在且已 up。手工创建的链路可以随便命名只要网络创建时它们存在就足够了。网络用docker network rm删除时手工创建的链路无论叫什么名字都不会被删除。# 创建一个绑定 dot1q vlan 40 的新子接口 ip link add link eth0 name eth0.40 type vlan id 40 # 启用新子接口 ip link set eth0.40 up # 像往常一样添加网络和主机挂到已打标签的 master (sub)interface 上 docker network create -d macvlan \ --subnet192.168.40.0/24 \ --gateway192.168.40.1 \ -o parenteth0.40 macvlan40 # 在两个终端中各启动一个容器容器之间现在可以互 ping docker run --netmacvlan40 -it --name mcv_test5 --rm alpine /bin/sh docker run --netmacvlan40 -it --name mcv_test6 --rm alpine /bin/sh示例以任意名称手工创建 VLAN 子接口# 创建一个绑定 dot1q vlan 40 的新子接口 ip link add link eth0 name foo type vlan id 40 # 启用新子接口 ip link set foo up # 像往常一样添加网络和主机挂到已打标签的 master (sub)interface 上 docker network create -d macvlan \ --subnet192.168.40.0/24 --gateway192.168.40.1 \ -o parentfoo macvlan40 # 在两个终端中各启动一个容器容器之间现在可以互 ping docker run --netmacvlan40 -it --name mcv_test5 --rm alpine /bin/sh docker run --netmacvlan40 -it --name mcv_test6 --rm alpine /bin/sh手工创建的链路清理ip link del foo与其他 Libnetwork 驱动一样不同类型的网络可以混用混搭。这也适用于第三方生态驱动——它们可以与内建驱动并行运行为用户提供最大灵活性。六、Dual StackIPv4 IPv6 macvlan bridge 模式下面创建同时指定 v4 和 v6 地址的网络每个容器会从两个地址族各分配一个地址。你可以显式指定某个地址族也可以让 Libnetwork IPAM 从子网池中自动分配。关于 IPv6 的说明docker network create声明 v6 子网时必须带--ipv6标志以及子网下例为--subnet2001:db8:abc8::/64。与 IPv4 功能类似若未指定 IPv6--gateway则推断 v6 子网中第一个可用地址作为该广播域的网关。以下示例创建一个含多个 IPv4 与 IPv6 子网的网络网络挂到eth0.218子接口上。指定eth0.218作为父接口后驱动会创建该子接口若尚不存在并为网络内所有容器的流量打上 VLAN ID 218 的标签。ToRtop of rack交换机端口必须启用 802.1Q Trunking宿主机进出通信才能工作。# 创建双栈多子网网络: docker network create -d macvlan \ --subnet192.168.216.0/24 --subnet192.168.218.0/24 \ --gateway192.168.216.1 --gateway192.168.218.1 \ --ipv6 --subnet2001:db8:abc8::/64 --gateway2001:db8:abc8::10 \ -o parenteth0.218 \ -o macvlan_modebridge macvlan216 # 在第一个子网 192.168.216.0/24 上启动容器 docker run --netmacvlan216 --namemacnet216_test --ip192.168.216.10 -itd alpine /bin/sh # 在第二个子网 192.168.218.0/24 上启动容器 docker run --netmacvlan216 --namemacnet218_test --ip192.168.218.10 -itd alpine /bin/sh # ping 第一个子网 192.168.216.0/24 上先启动的容器 docker run --netmacvlan216 --ip192.168.216.11 -it --rm alpine /bin/sh # 在容器 shell 里 ping 同子网的另一台主机然后退出 $ ping -c4 192.168.216.10 $ exit # ping 第二个子网 192.168.218.0/24 上先启动的容器 docker run --netmacvlan216 --ip192.168.218.11 -it --rm alpine /bin/sh # 在容器 shell 里 ping 同子网的另一台主机然后退出 $ ping -c4 192.168.218.10 $ exit # 显式声明 v6 地址启动后台容器 docker run --netmacvlan216 --ip62001:db8:abc8::20 -itd alpine /bin/sh # 再启动一个容器ping 前一个容器的 v6 地址 docker run --netmacvlan216 -it --rm alpine /bin/sh $ ping6 -c4 2001:db8:abc8::20 $ exit # 或者把 ping 作为显式进程运行 docker run --netmacvlan216 -it --rm alpine ping6 -c4 2001:db8:abc8::20查看其中一个容器的详情docker run --netmacvlan216 --ip192.168.216.11 -it --rm alpine /bin/sh root526f3060d759:/# ip a show eth0 25: eth0if19: BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN mtu 1500 qdisc noqueue state UNKNOWN link/ether 02:42:c0:a8:d8:0b brd ff:ff:ff:ff:ff:ff inet 192.168.216.11/24 scope global eth0 valid_lft forever preferred_lft forever inet6 2001:db8:abc8::1/64 scope link valid_lft forever preferred_lft forever # 默认网关是宿主机外部的网络网关 $ ip route default via 192.168.216.1 dev eth0 192.168.216.0/24 dev eth0 src 192.168.216.11 # 指定的 v6 网关 2001:db8:abc8::10 $ ip -6 route 2001:db8:abc4::/64 dev eth0 proto kernel metric 256 2001:db8:abc8::/64 dev eth0 proto kernel metric 256 default via 2001:db8:abc8::10 dev eth0 metric 1024 # 容器接口可以同时分配 v4 和 v6 地址 docker run --netmacvlan216 --ip192.168.216.50 --ip62001:db8:abc8::50 -it --rm alpine /bin/sh # 在容器内查看双栈 eth0 接口详情 $ ip a show eth0 95: eth0if91: BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN mtu 1500 qdisc noqueue state UNKNOWN link/ether 02:42:c0:a8:d8:32 brd ff:ff:ff:ff:ff:ff inet 192.168.216.50/24 scope global eth0 valid_lft forever preferred_lft forever inet6 2001:db8:abc8::50/64 scope global flags 02 valid_lft forever preferred_lft forever源码层面双栈网关行为由 Join 阶段的双段逻辑实现macvlan_joinleave.go#L51-L111 分别处理 IPv4 与 IPv6——ep.addr/ep.addrv6各自匹配子网配置了网关则SetGateway/SetGatewayIPv6未配置则ForceGw4/ForceGw6两条路由表各自独立写入与上面ip route与ip -6 route的输出一致。网关推断 子池保留综合示例下面示例演示当docker network create中某个子网未指定--gateway时默认网关如何被推断——选取子网中第一个可用地址。同时演示--ip-range与--aux-address联用用于排除网络内的地址分配、在网络子网内保留可用地址子池。由于使用eth0而非子接口所有流量均无 VLAN 标签。docker network create -d macvlan \ --subnet192.168.136.0/24 \ --subnet192.168.138.0/24 \ --ipv6 --subnetfd11::/64 \ --ip-range192.168.136.0/25 \ --ip-range192.168.138.0/25 \ --aux-addressreserved1fd11::2 \ --aux-addressreserved2192.168.136.2 \ --aux-addressreserved3192.168.138.2 \ -o parenteth0 mcv0 docker run --netmcv0 -it --rm alpine /bin/sh在该示例网络mcv0上供给的容器输出如下v4 网关推断为192.168.136.1、192.168.138.1v6 网关推断为fd11::1# 容器 eth0 输出fe80::42:c0ff:fea8:8803/64 是本地链路地址 ip address show eth0 100: eth0if2: BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN mtu 1500 qdisc noqueue state UNKNOWN link/ether 02:42:c0:a8:88:03 brd ff:ff:ff:ff:ff:ff inet 192.168.136.3/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fd11::3/64 scope global flags 02 valid_lft forever preferred_lft forever inet6 fe80::42:c0ff:fea8:8803/64 scope link valid_lft forever preferred_lft forever # 容器内 IPv4 路由表 $ ip route default via 192.168.136.1 dev eth0 192.168.136.0/24 dev eth0 src 192.168.136.3 # 容器内 IPv6 路由表第二个 v6 地址是本地链路地址 $ ip -6 route fd11::/64 dev eth0 metric 256 fe80::/64 dev eth0 metric 256 default via fd11::1 dev eth0 metric 1024示例完成后的清理docker rm -fdocker ps -qa 可移除宿主机上所有容器运行中和停止的。七、小结macvlan 驱动的设计哲学可以概括为让 NetOps 把物理网络原样映射进虚拟网络。一根 802.1q trunk 接入宿主机-o parenteth0.x即完成一个网络与一个 VLAN/子网的映射无标签链路则-o parenteth0即可。这些是持久化配置每次 Docker 引擎启动自动生效替代了往往复杂易错的接口配置文件。同时驱动对谁创建、谁回收的边界处理得非常明确驱动创建的从属链路才自动重建/删除父接口与手工链路永不触碰配合内核级对宿主机本地地址的过滤使容器网络在获得物理网络级可观测性的同时保持租户隔离。延伸阅读仓库内文档bridge 驱动、overlay/IPAM 文档、网络设计文档驱动实现位于 macvlan 驱动目录含 单元测试与 setup 逻辑测试。【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表