Docker 容器网络
Docker 从容器中提取了基础的主机连接网络。 这样做为应用程序提供了一定程度的运行时环境不可知性,并允许基础结构管理器调整实现以适合操作环境。 连接到 Docker 网络的容器将获得一个唯一的 IP 地址,该 IP 地址可以为连接到同一 Docker 网络的其他容器进行路由。
但这种方法的主要问题是,在容器内运行的任何软件都没有简洁的方法来确定依赖的宿主机的 IP 地址,这阻止了容器将其服务端点通告给容器网络外部的其他服务。
Docker 还将网络视为第一类实体。 这意味着它们具有自己的生命周期,并且不受任何其他对象的约束。 您可以使用 docker network 子命令直接定义和管理它们。
运行 docker network ls 会将打印所有网络表格信息到终端。 结果应如下所示:
NETWORK ID NAME DRIVER SCOPE
63d93214524b bridge bridge local
6eeb489baff0 host host local
3254d02034ed none null local
默认情况下,Docker 包括三个网络,每个网络由不同的驱动程序提供。 名为 bridge 的网络是默认网络,由网桥驱动程序提供。 桥驱动程序为同一机器上运行的所有容器提供容器间连接。host 网络由 host 驱动程序提供,该驱动程序指示 Docker 不要为连接的容器创建任何特殊的网络命名空间或资源。 主机网络上的容器与主机的网络堆栈交互,就像非容器进程一样。最后,none 网络使用 null 驱动程序。 连接到无网络的容器自身外部将没有任何网络连接。
网络的范围可以采用三个值:local
,global
或 swarm
。这表明是将网络限制在网络所在的计算机上(local),还是在集群的每个节点上创建网络,而不是在它们之间路由(global),还是无缝地跨接参与 Docker 群的所有主机(多主机) 或整个群集)。 如您所见,所有默认网络都具有 local
范围,并且将无法直接与路由在不同计算机上运行的容器之间通信。
默认 bridge
网络保持与旧 Docker 的兼容性,并且无法利用现代 Docker 功能(包括服务发现或负载平衡),处于同一网络环境下的 docker 容器,可以通过 hostname 互相发现,默认容器的 hostname 和容器名相同,可以只用 --hostname 指定容器主机名。
超越 bridge 网络
默认情况下,桥接网络已经可以满足你的需求。桥接网络非常适合单服务部署,例如运行内容管理系统或博客的 LAMP 或大多数本地开发任务。但如果你正在运行旨在容忍机器故障的多服务器环境,则需要能够在不同机器上的容器之间无缝路由流量,桥接网络做不到。
Docker 提供了一些开箱即用的选项来处理这种用例。 最佳选择取决于构建网络的环境,如果在 Linux 主机上使用Docker 并且可以控制主机网络,则可以使用 macvlan
或 ipvlan
网络驱动程序提供的底层网络。 底层网络为每个容器创建第一类的网络地址。 这些身份可从连接主机的同一网络中发现和路由。 机器上运行的每个容器看起来就像网络上的一个独立节点。
如果您正在运行 Mac 的 Docker 或 Windows 的 Docker 或在托管云环境中运行,那么这些选项将不起作用。 此外,底层网络配置取决于主机网络,因此定义很少可移植。 最受欢迎的多主机容器网络选项是 overlay
网络。
overlay 网络驱动程序在启用了 swarm
模式的 Docker 引擎上可用。 overlay 网络的结构与桥接网络相似,但是逻辑网桥组件可感知多主机,并且可以在集群中每个节点路由容器间连接。
就像在桥接网络上一样,overlay 网络上的容器也不能从集群外部直接路由。 但是容器间的通信很简单,并且网络定义基本上独立于主机网络环境。
在某些情况下,您会有一些特殊的网络要求,但底层网络或 overlay 网络无法满足这些要求。 也许您需要能够调整主机网络配置,或者确保容器在完全网络隔离的情况下运行。 在这种情况下,您应该使用一种特殊的容器网络。
特殊容器网络:host 和 none
host 和 none。 这些并不是真正的网络。 相反,它们是具有特殊含义的网络附件类型。
在 docker run 命令上指定 --network host 选项时,您正在告诉 Docker 创建一个没有任何特殊网络适配器或网络名称空间的新容器。 无论结果容器中运行的是哪种软件,对主机网络的访问程度都将与容器外部运行的软件相同。 由于没有网络名称空间,因此所有用于调整网络堆栈的内核工具都可用于修改(只要修改过程可以这样做)。
在 host 网络上运行对于系统服务或其他基础结构组件很有用。 但这在多租户环境中不合适,因此不应将其用于第三方容器。 因此,您通常不希望将容器连接到网络。 本着构建最低特权系统的精神,应尽可能使用 none 网络。
在 none 网络上创建容器会指示 Docker 不要为新容器设置任何已连接的虚拟以太网适配器。 它将具有自己的网络名称空间,因此将被隔离,但是如果没有跨越名称空间边界连接的适配器,它将无法使用网络在容器外部进行通信。 以这种方式配置的容器仍将具有自己的回环接口,因此多进程容器仍可以使用与本地主机的连接进行进程间通信。
桥接网络使用网络地址转换(NAT)来使所有出站容器通信以及桥接网络外部的目的地看起来像是来自主机本身。 这意味着您在容器中运行的服务软件与世界其他地区以及大多数客户和客户所在的网络部分是隔离的。
使用 NodePort 发布处理入站流量
Docker 容器网络都是关于容器之间的简单连接和路由的。 将那些容器中运行的服务与外部网络客户端连接起来需要额外的步骤。 由于容器网络通过网络地址转换连接到更广泛的网络,因此您必须专门告诉 Docker 如何从外部网络接口转发流量。 您需要在主机接口上指定 TCP 或 UDP 端口以及目标容器和容器端口,类似于通过家庭网络上的 NAT 屏障转发流量。
NodePort 发布
是我们在这里用来匹配 Docker 和其他生态系统项目的术语。 节点部分是对主机的推断,通常是较大机器集群中的节点。
端口发布配置是在容器创建时提供的,以后不能更改。 docker run 和 docker create 命令提供 -p 或 --publish list 选项。 与其他选项一样,-p 选项采用以冒号分隔的字符串参数。 该参数指定主机接口,要转发的主机上的端口,目标端口和端口协议。 以下所有参数均等效:
- 0.0.0.0:8080:8080/tcp
- 8080:8080/tcp
- 8080:8080
直接使用 port 时未指定主机端口号,会随机从主机端口中分配一个端口号,可以使用 docker port 容器名
来查看具体分配端口号,或 docker ps
也可以看到端口映射情况,不过 docker port 可以使用容器端口号缩小查找范围:docker port 容器名 容器端口号
。
总结
网络是一个广泛的主题,需要几本书才能正确覆盖。 这里主要解释了 Docker 提供的的单主机的网络实施:
- Docker 网络是第一类实体,可以像容器,卷和镜像一样被创建,索引和删除。
- 桥接网络是一种特殊的网络,它允许使用内置的容器名称解析来直接进行容器间网络通信。
- Docker 默认提供另外两个特殊网络:host 和 none。
- 使用 none 驱动程序创建的网络会将容器与网络隔离。
- host 网络上的容器将具有对主机上网络设施和接口的完全访问权限。
- 使用 NodePort 发布将网络流量转发到主机端口与目标容器端口。
- Docker 网桥网络不提供任何网络防火墙或访问控制功能。
- 可以为每个容器自定义网络名称解析堆栈。 可以自定义 DNS 服务器,搜索域和静态主机。
- 网络管理可以使用第三方工具和 Docker none 网络进行外部化。