概述

在应用程序和网络之间是 Docker 网络,被亲切地称为容器网络模型 或 CNM(Container Network Model)。是 CNM 为您的 Docker 容器代理连接性,并且还抽象出网络中常见的多样性和复杂性。结果是可移植性,它来自 CNM 强大的网络驱动程序。这些是 Docker 引擎、Swarm 和 UCP 的可插拔接口,提供了多主机网络、网络层加密和服务发现等特殊功能。

每个驱动程序都提供权衡,并根据用例具有不同的优势。Docker Engine 附带了内置的网络驱动程序,也有网络供应商和社区提供的插件 网络驱动程序。最常用的内置网络驱动程序是bridge、overlay和macvlan、host、container、none

Docker 网桥驱动程序会自动在宿主机中安装规则,使不同网桥网络上的容器无法直接相互通信。

docker创建的默认网络

当你安装Docker后,它会自动创建三个network,你可以使用命令:docker network ls

Docker容器网络 - Java技术债务

从历史上看,这三个network是Docker实现的一部分。当你运行一个container时,你可以用--net 标志去指定这个container运行在哪一种network上。这三种network你都可以使用。

这个bridgenetwork 代表所有安装了Docker的主机的docker0 network。除非使用docker run --set=<NETWORK>选项指定一个其它的network,否则Docker daemon会默认使用这个network连接contrainer。你可以使用系统的ifconfig命令查看主机的network stack中的docker0:

Docker容器网络 - Java技术债务

查看当前运行容器的网络

可以使用命令docker network inspect nginx 查看nginx的网络以及容器信息

找到NetworkSettings→Network

"Networks": {
                "testnet": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "nginx",
                        "f15d7fb1dc5d"
                    ],
                    "NetworkID": "71e578417fe3185720271d46fa7a5d97bf0c8acaf36f71f05d225c7fbe45158d",
                    "EndpointID": "f9114e7e10ecefeea6a148814dad3c3e195e972d5a2874666f4f4461acb160ae",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.4",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:04",
                    "DriverOpts": null
                }
}

我使用的是自定义的网络testnet。

上面是 docker network inspect命令根据给定的network回显的这个network已连接的容器和它的一些网络资源。在这个默认的network中的container可以利用IP地址相互通信。在默认的bridgenetwork中Docker不支持自动的服务发现。如果你的container想要通过其他container的name在这个默认的bridgenetwork中通行,你必须通过docker run --linke选项来实现。

常用的网络驱动程序

自定义的network

你可以创建属于你的自定义network来更好的隔离container。为了创建这些network,Docker提供了一些默认的network drivers。你可以创建一个新的bridge network或者overlay network。你也可以创建一个network plugin或是一个remote network

你可以创建多个网络。可以添加一个container到多个网络。container只能在这个网络中通行不能跨越这个网络。一个container可以附着到两个network中,并分别与这两个network中的container成员通信。

运行容器是可以通过 —network testnet指定你的容器使用testnet网络,更好的和其他容器隔离

bridge(桥接网络驱动程序)

默认网络驱动程序。如果您未指定驱动程序,则这是您正在创建的网络类型。当您的应用程序在需要通信的独立容器中运行时,通常会使用桥接网络。

bridge驱动程序提供了基于 Linux Bridge 的特定于 Linux 的桥接实现。

bridge 网络驱动程序是我们列表中的第一个驱动程序。它易于理解、易于使用且易于排除故障,这使其成为开发人员和 Docker 新手的良好网络选择。bridge驱动程序在主机内部创建一个专用网络,以便该网络上的容器可以通信。通过将端口暴露给容器来授予外部访问权限。Docker 通过管理阻止不同 Docker 网络之间连接的规则来保护网络。

Docker 引擎创建了必要的 Linux 网桥、内部接口、iptables 规则和主机路由,以使这种连接成为可能。在下面突出显示的示例中,创建了一个 Docker 桥接网络并附加了两个容器。在没有额外配置的情况下,Docker 引擎进行必要的接线,为容器提供服务发现,并配置安全规则以防止与其他网络通信。内置 IPAM 驱动程序为容器接口提供来自桥接网络子网的私有 IP 地址。

在以下示例中,我们使用了一个pets由 awebdb容器组成的虚构应用程序。随意在您自己的 UCP 或 Swarm 集群上试用它。您的应用程序将可在 ``:8000.

docker network create -d bridge mybridge docker run -d --net mybridge --name db redis docker run -d --net mybridge -e DB=db -p 8000:5000 --name web chrch/web

Docker容器网络 - Java技术债务

我们的应用程序现在在我们的主机上的 8000 端口上提供服务。Docker 桥允许通过其容器名称web进行通信。db网桥驱动程序会自动为我们进行服务发现,因为它们位于同一网络上。Linux 网桥之间的所有端口映射、安全规则和管道工作都由网络驱动程序为我们处理,因为容器在集群中被调度和重新调度。

网桥驱动程序是本地范围驱动程序,这意味着它仅在单个主机上提供服务发现、IPAM 和连接。多主机服务发现需要一个可以将容器映射到其主机位置的外部解决方案。

overlay(覆盖网络驱动程序)

Overlay 网络将多个 Docker 守护进程连接在一起,使 swarm 服务能够相互通信。您还可以使用覆盖网络来促进 swarm 服务和独立容器之间的通信,或者不同 Docker 守护程序上的两个独立容器之间的通信。这种策略消除了在这些容器之间进行操作系统级路由的需要。

内置的 Dockeroverlay网络驱动程序从根本上简化了多主机网络中的许多复杂性。它是一个swarm 范围驱动程序,这意味着它跨整个 Swarm 或 UCP 集群而不是单个主机运行。使用该overlay驱动程序,多主机网络是 Docker 内部的一等公民,无需外部配置或组件。内置 IPAM、服务发现、多主机连接、加密和负载平衡。为了进行控制,overlay驱动程序使用加密的 Swarm 控制平面以低收敛时间管理大规模集群。

overlay驱动程序使用行业标准的 VXLAN 数据平面,将容器网络与底层物理网络(底层)分离。这具有跨各种云和本地网络提供最大可移植性的优势。网络策略、可见性和安全性通过 Docker 通用控制平面 (UCP) 进行集中控制。

macvlan

Macvlan 网络允许您将 MAC 地址分配给容器,使其在您的网络上显示为物理设备。Docker 守护进程通过它们的 MAC 地址将流量路由到容器。macvlan 在处理期望直接连接到物理网络而不是通过 Docker 主机的网络堆栈路由的遗留应用程序时,使用驱动程序有时是最佳选择。

macvlan驱动程序是最新的内置网络驱动程序,并提供了几个独特的特性。它是一个非常轻量级的驱动程序,因为它不使用任何 Linux 桥接或端口映射,而是将容器接口直接连接到主机接口。容器使用外部网络子网上的可路由 IP 地址进行寻址。

由于 IP 地址可路由,容器直接与 Swarm 集群外部的资源通信,无需使用 NAT 和端口映射。这有助于网络可见性和故障排除。此外,容器和主机接口之间的直接流量路径有助于减少延迟。macvlan是按主机配置的本地范围网络驱动程序。这样一来,MACVLAN 与外部网络之间的依赖关系就更加严格,这既是约束,也是不同于overlayor的优势bridge

macvlan驱动程序使用父接口的概念。该接口可以是主机接口,例如eth0子接口,甚至可以是绑定的主机适配器,它将以太网接口捆绑到单个逻辑接口中。在 MACVLAN 网络配置期间需要来自外部网络的网关地址,因为 MACVLAN 网络是从容器到网络网关的 L2 段。像所有 Docker 网络一样,MACVLAN 网络是相互分割的——提供网络内的访问,而不是网络之间的访问。

驱动程序可以通过macvlan不同的方式进行配置,以达到不同的效果。在下面的示例中,我们创建了两个连接到不同子接口的 MACVLAN 网络。这种类型的配置可用于通过主机接口将多个 L2 VLAN 直接扩展到容器。VLAN 默认网关存在于外部网络中。

Docker容器网络 - Java技术债务

dbweb容器连接到不同的 MACVLAN 网络。每个容器都驻留在其各自的外部网络上,并具有从该网络提供的外部 IP。使用这种设计,操作员可以在 L2 的主机和分段容器之外控制网络策略。通过在同一个 MACVLAN 网络上配置容器,也可以将它们放置在同一个 VLAN 中。这只是显示了每个网络驱动程序提供的灵活性。

host

容器和宿主机共享 Network namespace

如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再用了,网络的隔离性不好。

Docker容器网络 - Java技术债务

container

容器和另外一个容器共享 Network namespace

命令:-network container:NAME_OR_ID

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

none

对于这个容器,禁用所有网络。通常与自定义网络驱动程序一起使用

使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

这种网络模式下容器只有 lo 回环网络,没有其他网卡。none 模式可以在容器创建时通过–network none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

域名系统

在 Docker Desktop 内部有多个 DNS 服务器:

Docker容器网络 - Java技术债务

来自容器的 DNS 请求首先由内部的服务器处理,该服务器dockerd识别同一内部网络上其他容器的名称。这允许容器在不知道其内部 IP 地址的情况下轻松地相互通信。例如,图中有 3 个容器:“nginx”、“golang”和“postgres”,取自 docker /awesome-compose 示例。每次启动应用程序时,内部 IP 地址可能会有所不同,但由于内部的 DNS 服务器,容器仍然可以通过人类可读的名称轻松地相互连接。dockerd

所有其他名称查找都发送到CoreDNS(来自CNCF)。然后根据域名将请求转发到主机上的两个不同 DNS 服务器之一。域是特殊的,包括解析为当前主机的有效 IP 地址docker.internal的 DNS 名称。host.docker.internal尽管我们更喜欢一切都完全容器化,但有时将应用程序的一部分作为普通的旧主机服务运行是有意义的。特殊名称host.docker.internal允许容器以可移植的方式联系这些主机服务,而无需担心 IP 地址的硬编码。

主机上的第二个 DNS 服务器通过标准 OS 系统库来处理所有其他请求。这样可以确保,如果名称在开发人员的 Web 浏览器中正确解析,它也将在开发人员的容器中正确解析。这在复杂的设置中尤为重要,例如图中所示,其中一些请求通过公司 VPN 发送(例如internal.registry.mycompany),而其他请求则发送到常规 Internet(例如docker.com)。

总结

  • 当您需要多个容器在同一个 Docker 主机上进行通信时,用户定义的bridge桥接网络是最佳选择。

  • 当网络堆栈不应该与 Docker 主机隔离时,主机网络是最好的,但您希望容器的其他方面被隔离。

  • 当您需要在不同 Docker 主机上运行的容器进行通信时,或者当多个应用程序使用 swarm 服务一起工作时,overlay覆盖网络是最佳选择。

  • 当您从 VM 设置迁移或需要容器看起来像网络上的物理主机时,Macvlan 网络是最佳选择,每个主机都有唯一的 MAC 地址。

  • 第三方网络插件

    允许您将 Docker 与专门的网络堆栈集成。


更多好文章也可关注以下网站

本文作者:Java技术债务
原文链接:https://cuizb.top/myblog/article/1666607410
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。


当然也可以点击下面公众号进行扫描关注公众号,及时收到文章推荐

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐