欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

【译文】docker网络概述
(last modified Jun 26, 2023, 12:31 PM )
by
侧边栏壁纸
  • 累计撰写 192 篇文章
  • 累计创建 66 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

【译文】docker网络概述

橙序员
2023-02-12 / 0 评论 / 0 点赞 / 600 阅读 / 13,907 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

网络概述Docker 容器和服务如此强大的原因之一是您可以将它们连接在一起,或将它们连接到非 Docker 工作负载。Docker 容器和服务甚至不需要知道它们部署在 Docker 上,或者它们的对等体是否也是 Docker 工作负载。无论您的 Docker 主机运行 Linux、Windows 还

网络概述

Docker 容器和服务如此强大的原因之一是您可以将它们连接在一起,或将它们连接到非 Docker 工作负载。Docker 容器和服务甚至不需要知道它们部署在 Docker 上,或者它们的对等体是否也是 Docker 工作负载。无论您的 Docker 主机运行 Linux、Windows 还是两者的混合体,您都可以使用 Docker 以与平台无关的方式管理它们。

本主题定义了一些基本的 Docker 网络概念,并帮助您设计和部署应用程序以充分利用这些功能。

本主题的范围

本主题不涉及有关 Docker 网络如何工作的特定于操作系统的详细信息,因此您不会找到有关 Docker 如何iptables 在 Linux 上操作规则或如何在 Windows 服务器上操作路由规则的信息,也不会找到有关 Docker 如何形成的详细信息并封装数据包或处理加密。请参阅Docker 和 iptables

此外,本主题不提供任何有关如何创建、管理和使用 Docker 网络的教程。每个部分都包含指向相关教程和命令参考的链接。

网络驱动

Docker 的网络子系统是可插入的,使用驱动程序。默认存在多个驱动程序,并提供核心网络功能:

  • bridge:默认网络驱动程序。如果您不指定驱动程序,这就是您正在创建的网络类型。**当您的应用程序在需要通信的独立容器中运行时,通常会使用桥接网络。**请参阅 桥接网络
  • host:对于独立容器,去掉容器和Docker宿主机之间的网络隔离,直接使用宿主机的网络。请参阅 使用主机网络
  • overlay:覆盖网络将多个 Docker 守护进程连接在一起,并使 swarm 服务能够相互通信。您还可以使用覆盖网络来促进 swarm 服务和独立容器之间,或不同 Docker 守护进程上的两个独立容器之间的通信。这种策略消除了在这些容器之间进行操作系统级路由的需要。请参阅覆盖网络
  • ipvlan:IPvlan 网络使用户可以完全控制 IPv4 和 IPv6 寻址。VLAN 驱动程序建立在其之上,使运营商能够完全控制第 2 层 VLAN 标记,甚至为对底层网络集成感兴趣的用户提供 IPvlan L3 路由。请参阅IPvlan 网络
  • macvlan:Macvlan 网络允许您为容器分配 MAC 地址,使其在您的网络上显示为物理设备。Docker 守护进程通过 MAC 地址将流量路由到容器。macvlan 在处理希望直接连接到物理网络而不是通过 Docker 主机的网络堆栈路由的遗留应用程序时,使用驱动程序有时是最佳选择。请参阅 Macvlan 网络
  • none:对于这个容器,禁用所有网络。通常与自定义网络驱动程序结合使用。none不适用于群服务。请参阅 禁用容器网络
  • 网络插件:您可以通过 Docker 安装和使用第三方网络插件。这些插件可从 Docker Hub 或第三方供应商处获得。请参阅供应商的文档以安装和使用给定的网络插件。

网络驱动总结

  • 当您需要多个容器在同一台 Docker 主机上进行通信时,用户定义的桥接网络是最佳选择。
  • 当网络堆栈不应该与 Docker 主机隔离,但您希望容器的其他方面被隔离时,主机网络是最好的。
  • 当您需要在不同 Docker 主机上运行的容器进行通信时,或者当多个应用程序使用 swarm 服务协同工作时,覆盖网络是最佳选择。
  • 当您从 VM 设置迁移或需要您的容器看起来像网络上的物理主机时,Macvlan 网络是最好的,每个主机都有一个唯一的 MAC 地址。
  • 第三方网络插件允许您将 Docker 与专用网络堆栈集成。

使用桥接网络

从组网的角度来说,桥接网络是在网段之间转发流量的链路层设备。网桥可以是硬件设备,也可以是在主机内核中运行的软件设备。

就 Docker 而言,桥接网络使用软件桥接,允许连接到同一桥接网络的容器进行通信,同时提供与未连接到该桥接网络的容器的隔离。Docker 桥接驱动程序会自动在宿主机中安装规则,使不同桥接网络上的容器无法直接相互通信。

桥接网络适用于在同一Docker 守护进程主机上运行的容器。对于运行在不同 Docker 守护进程主机上的容器之间的通信,您可以在操作系统级别管理路由,也可以使用 覆盖网络

当您启动 Docker 时,会自动创建一个默认的桥接网络(也称为bridge),除非另有说明,否则新启动的容器将连接到它。您还可以创建用户定义的自定义桥接网络。用户定义的桥接网络优于默认bridge 网络。

用户定义的网桥和默认网桥之间的

  • 用户定义的网桥提供容器之间的自动 DNS 解析

    默认桥接网络上的容器只能通过 IP 地址相互访问,除非您使用该--link选项,这被认为是遗留的。在用户定义的桥接网络上,容器可以通过名称或别名相互解析。

    想象一个具有 Web 前端和数据库后端的应用程序。如果您调用您的容器webdb,Web 容器可以连接到 db 容器db,无论应用程序堆栈运行在哪个 Docker 主机上。

    如果您在默认桥接网络上运行相同的应用程序堆栈,则需要手动创建容器之间的链接(使用 legacy--link 标志)。这些链接需要在两个方向上创建,因此您可以看到,如果有两个以上的容器需要通信,这会变得很复杂。或者,您可以操作/etc/hosts容器内的文件,但这会产生难以调试的问题。

  • 用户定义的桥提供更好的隔离

    所有没有指定--network的容器,都附加到默认的桥接网络。这可能是一种风险,因为不相关的堆栈/服务/容器随后能够进行通信。

    使用用户定义的网络提供了一个范围内的网络,其中只有连接到该网络的容器才能进行通信。

  • 容器可以动态地附加到用户定义的网络或从中分离

    在容器的生命周期内,您可以动态地将其连接到用户定义的网络或断开连接。要从默认桥接网络中删除容器,您需要停止容器并使用不同的网络选项重新创建它。

  • 每个用户定义的网络都会创建一个可配置的网桥

    如果您的容器使用默认桥接网络,您可以配置它,但所有容器都使用相同的设置,例如 MTU 和iptables规则。此外,配置默认桥接网络发生在 Docker 本身之外,需要重新启动 Docker。

    用户定义的桥接网络是使用 docker network create创建和配置的。如果不同的应用程序组有不同的网络要求,您可以在创建每个用户定义的网桥时分别对其进行配置。

  • 默认 bridge 网络上的链接容器共享环境变量

    最初,在两个容器之间共享环境变量的唯一方法是使用--link标志链接它们。这种类型的变量共享对于用户定义的网络是不可能的。但是,有更好的方法来共享环境变量。一些想法:

    • 多个容器可以使用 Docker 卷挂载包含共享信息的文件或目录。
    • 多个容器可以使用docker-compose一起启动,组合文件可以定义共享变量。
    • 您可以使用 swarm 服务而不是独立容器,并利用共享的秘密配置

连接到同一个用户定义的桥接网络的容器有效地相互暴露所有端口。对于不同网络上的容器或非 Docker 主机可以访问的端口,必须使用-p--publish标志发布该端口。

管理用户定义的桥梁

使用docker network create`命令创建用户自定义桥接网络。

$ docker network create my-net

您可以指定子网、IP 地址范围、网关和其他选项。有关详细信息,请参阅 docker network create 参考或输出docker network create --help

使用docker network rm命令删除用户自定义的桥接网络。如果容器当前连接到网络, 请先断开它们

$ docker network rm my-net

到底发生了什么?

当您创建或删除用户定义的网桥或将容器与用户定义的网桥连接或断开连接时,Docker 使用特定于操作系统的工具来管理底层网络基础设施(例如添加或删除网桥设备或iptables在 Linux 上配置规则). 这些细节应被视为实现细节。让 Docker 为您管理用户定义的网络。

将容器连接到用户定义的桥

当您创建一个新容器时,您可以指定一个或多个--network标志。此示例将 Nginx 容器连接到my-net网络。它还将容器中的 80 端口发布到 Docker 主机上的 8080 端口,以便外部客户端可以访问该端口。连接到my-net 网络的任何其他容器都可以访问my-nginx容器上的所有端口,反之亦然。

$ docker create --name my-nginx \
  --network my-net \
  --publish 8080:80 \
  nginx:latest

要将正在运行的容器连接到现有的用户定义桥,请使用该 docker network connect命令。以下命令将一个已经运行的 my-nginx容器连接到一个已经存在的my-net网络:

$ docker network connect my-net my-nginx

从用户定义的桥断开容器

要将正在运行的容器与用户定义的桥断开连接,请使用该docker network disconnect命令。以下命令断开my-nginx 容器与my-net网络的连接。

$ docker network disconnect my-net my-nginx

使用 IPv6

如果您需要 Docker 容器的 IPv6 支持,您需要 在 Docker 守护进程上启用该选项并重新加载其配置,然后再创建任何 IPv6 网络或分配容器 IPv6 地址。

创建网络时,您可以指定--ipv6标志以启用 IPv6。您不能在默认bridge网络上有选择地禁用 IPv6 支持。

启用从 Docker 容器到外部世界的

默认情况下,来自连接到默认桥接网络的容器的流量 不会转发到外界。要启用转发,您需要更改两个设置。这些不是 Docker 命令,它们会影响 Docker 主机的内核。

  1. 配置 Linux 内核以允许 IP 转发。

    $ sysctl net.ipv4.conf.all.forwarding=1
    
  2. 将策略的iptables FORWARD策略从更改DROPACCEPT

    $ sudo iptables -P FORWARD ACCEPT
    

这些设置不会在重启后保留,因此您可能需要将它们添加到启动脚本中。

使用默认桥接网络

默认bridge网络被认为是 Docker 的遗留细节,不建议用于生产。配置它是一个手动操作,它有 技术上的缺点

将容器连接到默认桥接网络

如果您没有使用该--network标志指定网络,并且指定了网络驱动程序,则默认情况下您的容器将连接到默认bridge网络。连接到默认bridge网络的容器可以通信,但只能通过 IP 地址进行通信,除非它们使用 legacy--link标志链接。

配置默认桥接网络

要配置默认bridge网络,您可以在 中指定选项daemon.json。这是一个daemon.json指定了几个选项的示例。仅指定您需要自定义的设置。

{
  "bip": "192.168.1.1/24",
  "fixed-cidr": "192.168.1.0/25",
  "fixed-cidr-v6": "2001:db8::/64",
  "mtu": 1500,
  "default-gateway": "192.168.1.254",
  "default-gateway-v6": "2001:db8:abcd::89",
  "dns": ["10.20.1.2","10.20.1.3"]
}

重新启动 Docker 以使更改生效。

将 IPv6 与默认桥接网络一起使用

如果您为 IPv6 支持配置 Docker(请参阅使用 IPv6),默认桥接网络也会自动为 IPv6 配置。与用户定义的网桥不同,您不能在默认网桥上有选择地禁用 IPv6。

使用覆盖网络

网络驱动程序在overlay多个 Docker 守护进程主机之间创建分布式网络。该网络位于(覆盖)特定于主机的网络之上,允许连接到它的容器(包括 swarm 服务容器)在启用加密时安全地通信。Docker 透明地处理每个数据包往返于正确的 Docker 守护程序主机和正确的目标容器的路由。

当您初始化群或将 Docker 主机加入现有群时,会在该 Docker 主机上创建两个新网络:

  • 覆盖网络称为ingress,它处理与群服务相关的控制和数据流量。当您创建一个 swarm 服务并且不将其连接到用户定义的覆盖网络时,它ingress 默认连接到该网络。
  • 一个名为docker_gwbridge 的桥接网络,它将单个 Docker 守护进程连接到参与 swarm 的其他守护进程。

您可以使用docker network create , 创建用户定义的overlay网络,方法与创建用户定义的bridge网络相同。服务或容器一次可以连接到多个网络。服务或容器只能通过它们各自连接的网络进行通信。

尽管您可以将 swarm 服务和独立容器连接到覆盖网络,但默认行为和配置问题是不同的。因此,本主题的其余部分分为适用于所有覆盖网络的操作、适用于群服务网络的操作以及适用于独立容器使用的覆盖网络的操作。

所有覆盖网络的操作

创建覆盖网络

先决条件

  • 使用覆盖网络的 Docker 守护进程的防火墙规则

    您需要为参与覆盖网络的每个 Docker 主机打开和接收以下端口:

    • 用于集群管理通信的 TCP 端口 2377
    • 用于节点间通信的 TCP 和 UDP 端口 7946
    • 覆盖网络流量的 UDP 端口 4789
  • 在创建覆盖网络之前,您需要将 Docker 守护程序初始化为群管理器,docker swarm init或者使用docker swarm join. 这些中的任何一个都会创建默认 ingress覆盖网络,默认情况下由 swarm 服务使用。即使您从未打算使用 swarm 服务,您也需要这样做。之后,您可以创建其他用户定义的覆盖网络。

要创建用于 swarm 服务的覆盖网络,请使用如下命令:

$ docker network create -d overlay my-overlay

要创建可由 swarm 服务 独立容器使用以与在其他 Docker 守护进程上运行的其他独立容器通信的覆盖网络,请添加--attachable标志:

$ docker network create -d overlay --attachable my-attachable-overlay

您可以指定 IP 地址范围、子网、网关和其他选项。详情请见 docker network create --help

加密覆盖网络上的流量

所有 swarm 服务管理流量默认加密, 在 GCM 模式下使用AES 算法。群中的管理器节点每 12 小时轮换一次用于加密八卦数据的密钥。

要同时加密应用程序数据,--opt encrypted请在创建覆盖网络时添加。这会在 vxlan 级别启用 IPSEC 加密。这种加密会造成不可忽略的性能损失,因此您应该在将其用于生产之前测试该选项。

当您启用覆盖加密时,Docker 在所有节点之间创建 IPSEC 隧道,在这些节点上为连接到覆盖网络的服务安排任务。这些隧道还在 GCM 模式下使用 AES 算法,管理器节点每 12 小时自动轮换一次密钥。

不要将 Windows 节点附加到加密覆盖网络。

Windows 不支持覆盖网络加密。如果 Windows 节点尝试连接到加密覆盖网络,则不会检测到任何错误,但节点无法通信。

Swarm 模式覆盖网络和独立容器

您可以将覆盖网络功能与两者一起使用--opt encrypted --attachable ,并将非托管容器附加到该网络:

$ docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network

自定义默认入口网络

大多数用户永远不需要配置ingress网络,但 Docker 允许您这样做。如果自动选择的子网与网络上已有的子网冲突,或者您需要自定义其他低级网络设置(例如 MTU),这将很有用。

自定义ingress网络涉及删除和重新创建它。这通常在您在 swarm 中创建任何服务之前完成。如果您有发布端口的现有服务,则需要先删除这些服务,然后才能删除ingress网络。

在没有ingress网络存在的时间内,不发布端口的现有服务继续运行但没有负载平衡。这会影响发布端口的服务,例如发布端口 80 的 WordPress 服务。

  1. 使用docker network inspect ingress检查ingress网络,并删除其容器连接到它的所有服务。这些是发布端口的服务,例如发布80端口的WordPress服务。如果这些服务都没有停止,则下一步失败。

  2. 删除现有ingress网络:

    $ docker network rm ingress
    
    WARNING! Before removing the routing-mesh network, make sure all the nodes
    in your swarm run the same docker engine version. Otherwise, removal may not
    be effective and functionality of newly created ingress networks will be
    impaired.
    Are you sure you want to continue? [y/N]
    
  3. --ingress使用标志以及您要设置的自定义选项创建一个新的覆盖网络。此示例将 MTU 设置为 1200,将子网设置为10.11.0.0/16,将网关设置为10.11.0.2

    $ docker network create \
      --driver overlay \
      --ingress \
      --subnet=10.11.0.0/16 \
      --gateway=10.11.0.2 \
      --opt com.docker.network.driver.mtu=1200 \
      my-ingress
    

    注意:您可以将您的ingress网络命名为 以外 的名称ingress,但您只能有一个。尝试创建第二个失败。

  4. 重新启动您在第一步中停止的服务。

自定义 docker_gwbridge 接口

docker_gwbridge是一个将覆盖网络(包括ingress网络)连接到单个 Docker 守护进程的物理网络的虚拟网桥。当您初始化群或将 Docker 主机加入群时,Docker 会自动创建它,但它不是 Docker 设备。它存在于 Docker 主机的内核中。如果您需要自定义其设置,则必须在将 Docker 主机加入 swarm 之前或在将主机暂时从 swarm 中移除之后执行此操作。

  1. 停止docker。

  2. 删除现有docker_gwbridge接口。

    $ sudo ip link set docker_gwbridge down
    
    $ sudo ip link del dev docker_gwbridge
    
  3. 启动docker。不要加入或初始化群。

  4. 使用命令docker_gwbridge使用您的自定义设置手动创建或重新创建网桥。docker network create此示例使用子网10.11.0.0/16。有关可自定义选项的完整列表,请参阅桥接驱动程序选项

    $ docker network create \
    --subnet 10.11.0.0/16 \
    --opt com.docker.network.bridge.name=docker_gwbridge \
    --opt com.docker.network.bridge.enable_icc=false \
    --opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
    
  5. 初始化或加入群。由于桥已经存在,Docker 不会使用自动设置创建它。

集群服务的操作

在覆盖网络上发布端口

连接到同一覆盖网络的 Swarm 服务有效地将所有端口相互公开。对于可在服务外部访问的端口,必须使用 或 上的或标志发布端口。支持旧的冒号分隔语法和较新的逗号分隔值语法。较长的语法是首选,因为它在某种程度上是自我记录的。-p``--publish``docker service create``docker service update

标志值 描述
-p 8080:80-p published=8080,target=80 将服务上的 TCP 端口 80 映射到路由网格上的端口 8080。
-p 8080:80/udp-p published=8080,target=80,protocol=udp 将服务上的 UDP 端口 80 映射到路由网格上的端口 8080。
-p 8080:80/tcp -p 8080:80/udp-p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp 将服务上的TCP 80端口映射到路由网格上的TCP 8080端口,将服务上的UDP 80端口映射到路由网格上的UDP 8080端口。

绕过集群服务的路由网格

默认情况下,发布端口的群服务使用路由网格来实现。当您连接到任何 swarm 节点上的已发布端口时(无论它是否正在运行给定服务),您将被透明地重定向到正在运行该服务的工作程序。实际上,Docker 充当了集群服务的负载均衡器。使用路由网格的服务以虚拟 IP (VIP) 模式运行。即使是在每个节点上运行的服务(通过--mode global 标志)也使用路由网格。使用路由网格时,无法保证哪个 Docker 节点为客户端请求提供服务。

要绕过路由网格,您可以使用DNS 循环 (DNSRR) 模式启动服务,方法是将--endpoint-mode标志设置为dnsrr。您必须在服务前面运行您自己的负载均衡器。对 Docker 主机上服务名称的 DNS 查询返回运行该服务的节点的 IP 地址列表。配置您的负载均衡器以使用此列表并平衡节点之间的流量。

分离控制和数据流量

默认情况下,与群管理相关的控制流量和进出您的应用程序的流量在同一网络上运行,尽管群控制流量是加密的。您可以将 Docker 配置为使用单独的网络接口来处理两种不同类型的流量。在初始化或加入 swarm 时,分别指定--advertise-addr--datapath-addr。您必须为每个加入群的节点执行此操作。

覆盖网络上独立容器的操作

将独立容器附加到覆盖网络

ingress网络是在没有标志的情况下创建的--attachable,这意味着只有 swarm 服务可以使用它,而不是独立的容器。--attachable您可以将独立容器连接到使用标志创建的用户定义的覆盖网络。这使运行在不同 Docker 守护进程上的独立容器能够进行通信,而无需在各个 Docker 守护进程主机上设置路由。

发布端口

标志值 描述
-p 8080:80 将容器中的 TCP 端口 80 映射到覆盖网络上的端口 8080。
-p 8080:80/udp 将容器中的 UDP 端口 80 映射到覆盖网络上的端口 8080。
-p 8080:80/sctp 将容器中的 SCTP 端口 80 映射到覆盖网络上的端口 8080。
-p 8080:80/tcp -p 8080:80/udp 将容器中的TCP 80端口映射到overlay网络的TCP 8080端口,将容器中的UDP 80端口映射到overlay网络的UDP 8080端口。

容器发现

在大多数情况下,您应该连接到服务名称,该服务名称是负载平衡的并由支持该服务的所有容器(“任务”)处理。要获取支持该服务的所有任务的列表,请执行 DNS 查找tasks.<service-name>.

使用主机网络

如果您host对容器使用网络模式,则该容器的网络堆栈不会与 Docker 主机隔离(容器共享主机的网络命名空间),并且容器不会分配自己的 IP 地址。例如,如果您运行绑定到端口 80 的容器并使用host 网络,则容器的应用程序可在主机 IP 地址的端口 80 上使用。

笔记

host鉴于容器在使用模式网络时没有自己的 IP 地址 ,端口映射不会生效,并且忽略-p, --publish,-P--publish-all选项,而是产生警告:

WARNING: Published ports are discarded when using host network mode

主机模式网络可用于优化性能,并且在容器需要处理大量端口的情况下,因为它不需要网络地址转换 (NAT),并且没有为每个端口创建“userland-proxy”。

主机网络驱动程序仅适用于 Linux 主机,在适用于 Mac 的 Docker Desktop、适用于 Windows 的 Docker Desktop 或适用于 Windows Server 的 Docker EE 上不受支持。

您还可以通过传递 给命令host,将网络用于 swarm 服务。在这种情况下,控制流量(与管理 swarm 和服务相关的流量)仍然通过覆盖网络发送,但各个 swarm 服务容器使用 Docker 守护进程的主机网络和端口发送数据。这会产生一些额外的限制。例如,如果服务容器绑定到端口 80,则只有一个服务容器可以在给定的 swarm 节点上运行。--network host``docker service create

使用 IPvlan 网络

IPvlan 驱动程序使用户可以完全控制 IPv4 和 IPv6 寻址。VLAN 驱动程序建立在其之上,使运营商能够完全控制第 2 层 VLAN 标记,甚至为对底层网络集成感兴趣的用户提供 IPvlan L3 路由。对于抽象物理约束的覆盖部署,请参阅多主机覆盖驱动程序。

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

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

先决条件

  • 此页面上的示例都是单主机。
  • 所有示例都可以在运行 Docker 的单个主机上执行。任何使用eth0.10子接口的示例都可以替换为 Docker 主机上的eth0或任何其他有效父接口。带有.的子接口 是即时创建的。-o parent接口也可以被排除在 docker network create之外,驱动程序将创建一个dummy 接口,使本地主机连接能够执行示例。
  • 内核要求:
    • 要检查您当前的内核版本,请使用uname -r
    • IPvlan Linux 内核 v4.2+(存在对早期内核的支持,但有缺陷)

IPvlan L2 模式使用示例

下图显示了 IPvlanL2模式拓扑的示例。驱动程序是用-d driver_name选项指定的。在这种情况下-d ipvlan

简单 IPvlan L2 模式示例

下例中的父接口-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

使用来自主机接口的网络--subnet作为 docker 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 层网段。

多个 IPvlan 主机

下面将创建与之前创建的网络完全相同的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 上的主机通常位于同一子网上,并且几乎总是根据其安全策略分组在一起。在大多数情况下,多层应用程序被分层到不同的子网中,因为每个进程的安全配置文件都需要某种形式的隔离。例如,将您的信用卡处理托管在与前端网络服务器相同的虚拟网络上将是一个合规性问题,同时还要规避长期存在的分层深度防御架构的最佳实践。使用覆盖驱动程序时,VLAN 或模棱两可的 VNI(虚拟网络标识符)是隔离租户流量的第一步。

Docker VLAN 深入

标记有 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中,指定-o parent=eth0.20表示父接口标记有 VLAN id20ip 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 主机标记和隔离,是用-o parent=eth0.30指定eth0.30的VLAN id 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 为在以太网链路上传递到 Docker 主机服务器的 VLAN 提供 VLAN ID 和相关子网。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 模式

IPvlan L3 模式丢弃所有广播和多播流量。仅此一个原因就使 IPvlan L3 模式成为那些寻求大规模和可预测网络集成的人的首选。这是可预测的,并且反过来会导致更长的正常运行时间,因为不涉及桥接。桥接环路是导致高调中断的原因,根据故障域的大小,这些中断可能很难查明。这是由于 BPDU(桥接端口数据单元)的级联特性,它们在整个广播域 (VLAN) 中泛滥以查找和阻止拓扑环路。消除桥接域,或至少将它们与一对 ToR(架顶式交换机)隔离,将减少桥接不稳定性故障排除的难度。IPvlan L2 模式非常适合仅中继到一对 ToR 中的隔离 VLAN,可以提供无环路非阻塞结构。下一步是通过 IPvlan L3 模式在边缘进行路由,从而将故障域仅减少到本地主机。

  • L3 模式需要在单独的子网上作为默认命名空间,因为它需要默认命名空间中的 netlink 路由指向 IPvlan 父接口。
  • 本例中使用的父接口是eth0并且它在子网上 192.168.1.0/24。请注意 与docker network不在同一子网上eth0
  • 与 IPvlan l2 模式不同,不同的子网/网络只要共享相同的父接口就可以相互 ping 通-o parent=
$$ 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设备。ip route有关详细信息,请参阅下面的 L3 容器或ip -6 route来自 L3 容器内部的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.212.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.212.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 和 v4 & v6 路由表:

$ 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

笔记

IPvlanL2模式下同一父接口上的不同子网无法相互Ping 通。这需要路由器使用辅助子网代理 arp 请求。但是,IPvlanL3将在不同的子网之间路由单播流量,只要它们共享相同的-o parent父链接。

双栈 IPv4 IPv6 IPvlan L3 模式

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

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

您将看到的主要区别是,L3 模式不会创建带有下一跳的默认路由,而是设置默认路由指向dev ethonly,因为 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

注意

--ip6=当您删除具有指定 v6 地址的容器,然后启动具有相同 v6 地址的新容器时,指定地址时可能会出现错误,它会抛出以下内容,如地址未正确释放到 v6 池。它将无法卸载容器并保持死状态。

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

手动创建 802.1q 链接

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 驱动程序一样,它们可以混合和匹配,甚至可以并行运行 3rd 方生态系统驱动程序,从而为 Docker 用户提供最大的灵活性。

使用 macvlan 网络

一些应用程序,尤其是遗留应用程序或监控网络流量的应用程序,期望直接连接到物理网络。在这种情况下,您可以使用macvlan网络驱动程序为每个容器的虚拟网络接口分配一个 MAC 地址,使其看起来像是一个直接连接到物理网络的物理网络接口。在这种情况下,您需要在您的 Docker 主机上指定一个物理接口用于macvlan. 以及 . 的子网和网关macvlan。您甚至可以macvlan使用不同的物理网络接口隔离您的网络。请记住以下几点:

  • 由于 IP 地址耗尽或“VLAN 传播”,很容易无意中损坏您的网络,在这种情况下,您的网络中有大量不适当的唯一 MAC 地址。
  • 您的网络设备需要能够处理“混杂模式”,在这种模式下,一个物理接口可以分配多个 MAC 地址。
  • 如果您的应用程序可以使用网桥(在单个 Docker 主机上)或覆盖(在多个 Docker 主机之间进行通信)工作,从长远来看,这些解决方案可能会更好。

创建一个macvlan网络

创建macvlan网络时,它可以处于桥接模式或 802.1q 中继桥接模式。

  • 在桥接模式下,macvlan流量通过主机上的物理设备。
  • 在 802.1q 中继桥接模式下,流量通过 Docker 动态创建的 802.1q 子接口。这使您可以更精细地控制路由和过滤。

桥接模式

要创建macvlan与给定物理网络接口桥接的网络,请使用--driver macvlan命令docker network create。您还需要指定parent,这是流量在 Docker 主机上实际经过的接口。

$ docker network create -d macvlan \
  --subnet=172.16.86.0/24 \
  --gateway=172.16.86.1 \
  -o parent=eth0 pub_net

如果您需要排除 IP 地址在macvlan网络中使用,例如当给定的 IP 地址已被使用时,请使用--aux-addresses

$ docker network create -d macvlan \
  --subnet=192.168.32.0/24 \
  --ip-range=192.168.32.128/25 \
  --gateway=192.168.32.254 \
  --aux-address="my-router=192.168.32.129" \
  -o parent=eth0 macnet32

802.1q 中继桥接模式

如果您指定一个parent包含点的接口名称,例如eth0.50,Docker 会将其解释为子接口eth0并自动创建子接口。

$ docker network create -d macvlan \
    --subnet=192.168.50.0/24 \
    --gateway=192.168.50.1 \
    -o parent=eth0.50 macvlan50

使用 ipvlan 而不是 macvlan

在上面的示例中,您仍在使用 L3 网桥。您可以ipvlan 改用,并获得一个 L2 网桥。指定-o ipvlan_mode=l2

$ docker network create -d ipvlan \
    --subnet=192.168.210.0/24 \
    --subnet=192.168.212.0/24 \
    --gateway=192.168.210.254 \
    --gateway=192.168.212.254 \
     -o ipvlan_mode=l2 -o parent=eth0 ipvlan210

使用 IPv6

如果您已将Docker 守护程序配置为允许 IPv6,则可以使用双栈 IPv4/IPv6macvlan网络。

$ docker network create -d macvlan \
    --subnet=192.168.216.0/24 --subnet=192.168.218.0/24 \
    --gateway=192.168.216.1 --gateway=192.168.218.1 \
    --subnet=2001:db8:abc8::/64 --gateway=2001:db8:abc8::10 \
     -o parent=eth0.218 \
     -o macvlan_mode=bridge macvlan216

禁用容器的网络

如果要完全禁用容器上的网络堆栈,可以--network none在启动容器时使用该标志。在容器内,只创建环回设备。下面的例子说明了这一点。

  1. 创建容器。

    $ docker run --rm -dit \
      --network none \
      --name no-net-alpine \
      alpine:latest \
      ash
    
  2. 通过在容器内执行一些常见的网络命令来检查容器的网络堆栈。请注意,没有eth0创建。

    $ docker exec no-net-alpine ip link show
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1
        link/ipip 0.0.0.0 brd 0.0.0.0
    3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1
        link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
    
    $ docker exec no-net-alpine ip route
    

    第二条命令返回空,因为没有路由表。

  3. 停止容器。它会自动删除,因为它是使用--rm标志创建的。

    $ docker stop no-net-alpine
    
0

评论区