Docker桥接网络(bridge network)的原理和用法详解

在网络术语中,桥接网络(bridge network)是在网络段之间转发流量的链路层设备。网桥(bridge)是可以硬件设备或在主机内核中运行的软件设备。

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

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

启动Docker时,会自动创建默认桥接网络(也称为bridge),并且除非另行指定,否则新启动的容器将连接到该网络。您还可以创建用户定义的自定义网桥。用户定义的桥接网络优于默认桥接网络。

用户定义的桥接网络和默认桥接网络的区别

  • 用户定义的桥接网络可在容器化应用程序之间提供更好的隔离和互操作性。

连接到同一用户定义的桥接网络的容器会自动将所有端口相互暴露,并且不会向外界暴露任何端口。这使得容器化应用程序可以轻松地相互通信,而不会意外地打开对外界的访问。

想象一下具有Web前端和数据库后端的应用程序。外部世界需要访问Web前端(可能在端口80上),但只有后端本身需要访问数据库主机和端口。使用用户定义的网桥,只需要打开Web端口,并且数据库应用程序不需要打开任何端口,因为Web前端可以通过用户定义的桥接网络访问它。

如果在默认桥接网络上运行相同的应用程序堆栈,则需要打开Web端口和数据库端口,并为每个端口使用-p--publish标记。这意味着Docker主机需要通过其他方式阻止对数据库端口的访问。

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

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

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

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

  • 容器可以在运行中与用户定义的网络连接和分离。

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

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

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

使用docker network create创建和配置用户定义的网桥。如果不同的应用程序组具有不同的网络要求,则可以在创建时单独配置每个用户定义的网桥。

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

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

  • 多个容器可以使用Docker卷加载包含共享信息的文件或目录。

  • 可以使用docker-compose一起启动多个容器,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使用特定于操作系统的工具来管理底层网络基础结构(例如添加或删除网桥设备或配置Linux的iptables规则)。 这些细节应视为实施细节。 让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,则需要在创建任何IPv6网络或分配容器IPv6地址之前,启用Docker后台程序上的IPv6选项并重新加载配置。

创建网络时,可以指定--ipv6标记以启用IPv6。 您无法在默认桥接网络上有选择地禁用IPv6支持。

启用从Docker容器转发到外部世界

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

  1. 配置Linux内核允许转发。
$ sysctl net.ipv4.conf.all.forwarding=1
  1. 修改iptables FORWARD策略从DROPACCEPT

这些设置在重新启动时会消失,因此您可能需要将它们添加到启动脚本中。

使用默认桥接网络

默认桥接网络被认为是Docker的遗留细节,不建议用于生产用途。 配置它要手动操作,它还有一些技术缺点。

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

如果未使用--network标记指定网络,并且指定网络驱动程序,则默认情况下容器将连接到默认桥接网络。 连接到默认网桥的容器只能通过IP地址进行通信,除非它们使用遗留的 --link标记进行链接。

配置默认网桥

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

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

重启Docker使更改生效。

将IPv6与默认网桥一起使用

如果将Docker配置为支持IPv6,则还会自动默认网桥网络配置为IPv6。 与用户定义的网桥不同,您无法在默认网桥网络上有选择地禁用IPv6。

下一步: