1.5 网络互通

1.5 网络互通 #

1.5.1 容器网络 #

在 Docker 网络中,有三个比较核心的概念,分别是:沙盒(Sandbox)、网络(Network)、端点(Endpoint)。

  • 沙盒提供了容器的虚拟网络栈,也就是端口套接字、IP 路由表、防火墙等内容。实现隔离容器网络与宿主机网络,形成了完全独立的容器网络环境。

  • 网络可以理解为 Docker 内部的虚拟子网,网络内的参与者相互可见并能够进行通讯。Docker 的这种虚拟网络也是与宿主机网络存在隔离关系的,其目的主要是形成容器间的安全通讯环境。

  • 端点是位于容器或网络隔离墙之上的 “洞”,其主要目的是形成一个可以控制的突破封闭的网络环境的出入口。当容器的端点与网络的端点形成配对后,就如同在这两者之间搭建了桥梁,便能够进行数据传输了。

这三者形成了 Docker 网络的核心模型,也就是容器网络模型(Container Network Model)。

1.5.2 网络驱动 #

Docker 官方提供了五种基础的 Docker 网络驱动:Bridge DriverHost DriverOverlay DriverMacLan DriverNone Driver,并基于这些网络驱动又衍生了一些其他的网络驱动,如 IPvlan。

Bridge #

Bridge(桥接)网络是默认的网络驱动程序,它提供了容器之间的基本网络通信功能。Docker 桥接网络通过在主机上创建一个虚拟网桥并将容器连接到该网桥来实现容器之间的通信。

当创建一个桥接网络时,Docker 会在主机上创建一个虚拟网桥(默认为 docker0),并为该网桥分配一个 IP 地址172.17.0.1。每个容器连接到这个桥接网络时,都会分配一个唯一的 B 类私 IP 地址,如172.17.0.2,并通过网络地址转换(NAT)实现与主机和其他容器之间的通信。

端口号映射需要使用 bridge 模式,并且在 docker run 启动容器时使用 -p 参数,用:分隔本机端口和容器端口。

使用 Docker 桥接网络有以下特点:

  1. 默认网络驱动程序:桥接网络是 Docker 的默认网络驱动程序,因此当创建容器时,如果没有显式指定网络驱动程序,则会自动使用桥接网络。

  2. 内部网络隔离:每个桥接网络都有自己的 IP 地址范围(默认为172.17.0.0/16),容器之间在网络上是相互隔离的,它们可以使用相同的 IP 地址范围而不会发生冲突。

  3. 网络地址转换(NAT):通过桥接网络,容器可以与主机和其他容器进行通信。桥接网络使用网络地址转换(NAT)将容器的私有 IP 地址转换为主机的公共 IP 地址。

  4. 主机网络连接:桥接网络允许容器与主机网络连接,容器可以访问主机上的网络服务。

创建和管理桥接网络的命令包括:

  1. 创建一个桥接网络:
docker network create --driver bridge <network_name>
  1. 运行容器并连接到桥接网络:
docker run --network=<network_name> --name <container_name> -d <image_name>

桥接网络在单主机上提供了容器之间的基本网络通信功能。如果需要在多个主机之间建立容器网络通信,可以考虑使用 Overlay 网络驱动程序或其他支持跨主机通信的网络驱动程序。

Host #

host 是一种特殊的网络模式,它使用宿主机的网络命名空间,将容器直接连接到宿主机的网络上。在使用 host 网络模式时,容器与宿主机共享相同的网络接口,可以直接访问宿主机上的网络服务。

如果在本机和容器里分别执行 ip addr 命令:

ip addr                    # 本机查看网卡
docker exec xxx ip addr    # 容器查看网卡

可以看到这两个 ip addr 命令的输出信息是完全一样的,这就证明容器确实与本机共享了网络栈。

使用 host 网络模式有以下特点:

  1. 容器与宿主机网络共享:容器不会创建自己的网络命名空间,而是与宿主机共享相同的网络命名空间,因此容器可以直接使用宿主机的网络接口和 IP 地址。

  2. 无网络隔离:容器与宿主机共享网络命名空间,它们之间的网络隔离较低。容器可以直接访问宿主机上的网络服务,并且容器之间也可以直接进行网络通信,不需要通过端口映射或网络转发。

  3. 更高的网络性能:由于容器直接连接到宿主机网络,无需进行网络地址转换(NAT)或端口映射,因此在 host 网络模式下,容器与网络之间的通信性能更高。

host 网络模式适用于以下情况:

  • 需要容器与宿主机共享相同的网络命名空间,以便容器可以直接访问宿主机上的网络服务。

  • 需要容器之间进行高性能的网络通信,而不需要经过网络地址转换或端口映射。

  • 要将容器设置为使用 host 网络模式,可以在Docker命令中指定--network=host,例如:

docker run --network=host <image_name>

由于 host 网络模式没有网络隔离,容器中运行的应用程序可以直接访问宿主机上的所有网络服务,这可能会带来一些安全风险。因此,在使用 host 网络模式时,需要特别注意网络安全和权限管理。

Overlay #

Overlay 网络是一种用于构建跨主机容器网络的网络驱动程序。它使用了 VXLAN(Virtual Extensible LAN)技术,通过在宿主机之间创建覆盖网络来实现容器之间的通信。

Overlay 网络驱动程序在多个 Docker 守护进程之间创建一个逻辑网络,使得容器可以在不同的宿主机上运行,并且它们之间可以透明地进行通信,就好像它们在同一个本地主机上运行一样。这为构建分布式应用程序和服务提供了便利。

在 Overlay 网络中,每个 Docker 主机上的容器都分配了一个唯一的 IP 地址。这些 IP 地址是从一个预定义的网络地址范围中动态分配的,称为 Overlay 网络的子网。每个容器的 IP 地址来自 Overlay 网络子网的地址空间。

以使用以下命令查看每个容器的IP地址:

docker network inspect my-overlay-network

上述命令将返回 Overlay 网络的详细信息,包括每个容器的IP地址。在输出中,你会看到类似以下的内容:

[
  {
    "Name": "my-overlay-network",
    "Id": "abcde1234567890",
    "Scope": "swarm",
    "Driver": "overlay",
    "Containers": {
      "container1": {
        "Name": "container1",
        "IPv4Address": "10.0.0.2/24",
        ...
      },
      "container2": {
        "Name": "container2",
        "IPv4Address": "10.0.0.3/24",
        ...
      }
    },
    ...
  }
]

使用 Overlay 网络时,可以按照以下步骤进行配置:

  1. 创建 Overlay 网络:
docker network create --driver overlay --subnet=<subnet> --gateway=<gateway> <network_name>
  • <subnet>:指定网络的子网,如192.168.0.0/24
  • <gateway>:指定网络的网关地址,如192.168.0.1
  • <network_name>:指定要创建的 Overlay 网络的名称。

在不同的主机上运行容器并连接到 Overlay 网络:

docker run --network=<network_name> --name <container_name> -d <image_name>
  • <network_name>:指定要连接的 Overlay 网络。
  • <container_name>:指定容器的名称。
  • <image_name>:指定容器所使用的镜像。

在这个配置下,Docker 会自动管理 Overlay 网络的路由和连接,使得跨主机的容器可以直接进行通信。Overlay 网络使用 VXLAN 技术将数据包封装在 UDP 包中,并通过宿主机之间的隧道进行传输。

使用 Overlay 网络驱动程序需要满足一些要求,包括宿主机的内核版本支持 VXLAN 和网络互联的设置。此外,Overlay 网络驱动程序还支持使用 Swarm 模式来创建容器集群,并提供内置的负载均衡和服务发现功能,使得分布式应用程序的部署和管理更加简便。

Macvlan #

Macvlan 网络驱动程序允许将容器连接到宿主机网络上的物理网络接口,使得容器可以直接与宿主机网络上的其他设备进行通信,而不需要通过 NAT 或端口映射。它提供了更高级别的网络功能和更好的性能。

使用 Macvlan 网络驱动程序时,每个容器都有一个唯一的 MAC 地址和 IP 地址。容器的 IP 地址是通过动态主机配置协议(DHCP)或手动配置(静态分配)来获取的,并可以直接与宿主机网络上的其他设备通信,就像它是一个独立的物理设备一样。

[
  {
    "Name": "my-macvlan-network",
    "Id": "abcde1234567890",
    "Scope": "local",
    "Driver": "macvlan",
    "IPAM": {
      "Config": [
        {
          "Subnet": "192.168.1.0/24",
          "Gateway": "192.168.1.1"
        }
      ]
    },
    "Containers": {
      "container1": {
        "Name": "container1",
        "IPv4Address": "192.168.1.2/24",
        ...
      },
      "container2": {
        "Name": "container2",
        "IPv4Address": "192.168.1.3/24",
        ...
      }
    },
    ...
  }
]

以下是使用 Macvlan 网络驱动程序的一般步骤:

  1. 创建Macvlan网络:
docker network create -d macvlan --subnet=<subnet> --gateway=<gateway> -o parent=<parent_interface> <network_name>
  • <subnet>:指定网络的子网,如192.168.0.0/24
  • <gateway>:指定网络的网关地址,如192.168.0.1
  • <parent_interface>:指定宿主机上的父接口,即物理网络接口。
  1. 运行容器并连接到 Macvlan 网络:
docker run --network=<network_name> --name <container_name> -d <image_name>
  • <network_name>:指定要连接的 Macvlan 网络。
  • <container_name>:指定容器的名称。
  • <image_name>:指定容器所使用的镜像。

通过这样的配置,容器将具有独立的 MAC 地址,并且可以直接与宿主机网络上的其他设备进行通信。使用 Macvlan 网络驱动程序需要宿主机的网络设备支持将虚拟 MAC 地址传递到物理网络上。

IPvlan #

基于 MacVLAN 的网络驱动程序还有一种新的驱动程序 IPvlan,它提供了更高级别的功能和灵活性。IPvlan 驱动程序允许创建具有独立 MAC 地址的虚拟网络接口,容器可以拥有自己的唯一 IP 地址,并直接与物理网络进行通信,而无需进行NAT转换。

[
  {
    "Name": "my-ipvlan-network",
    "Id": "abcde1234567890",
    "Scope": "local",
    "Driver": "ipvlan",
    "IPAM": {
      "Config": [
        {
          "Subnet": "192.168.1.0/24"
        }
      ]
    },
    "Containers": {
      "container1": {
        "Name": "container1",
        "IPv4Address": "192.168.1.2/24",
        ...
      },
      "container2": {
        "Name": "container2",
        "IPv4Address": "192.168.1.3/24",
        ...
      }
    },
    ...
  }
]

IPvlan 提供了三种模式:L2(二层)模式、L3(三层)模式和 L3s(二层和三层混合)模式,可以根据需要选择合适的模式。

  • L2 模式下,容器可以直接与主机网络上的其他设备进行通信,但容器之间无法直接通信。

  • L3 模式下,容器可以在容器网络内直接通信,容器之间和主机之间的通信需要通过路由器进行。

  • L3s 模式结合了 L2 和 L3 模式的特点,容器既可以直接与主机网络上的其他设备通信,也可以在容器网络内直接通信。

使用 ipvlan 网络驱动程序,可以按照以下步骤配置容器网络:

  1. 创建 ipvlan 网络:
docker network create -d ipvlan --subnet=<subnet> --gateway=<gateway> --ip-range=<ip-range> -o ipvlan_mode=<mode> -o parent=<parent_interface> <network_name>
  • <subnet>:指定网络的子网,如192.168.0.0/24
  • <gateway>:指定网络的网关地址,如192.168.0.1
  • <ip-range>:指定网络的IP地址范围,如192.168.0.2/28
  • <mode>:指定 ipvlan 模式,可以是 l2、l3 或 l3s。
  • <parent_interface>:指定宿主机上的父接口,即物理网络接口。
  1. 运行容器并连接到 ipvlan 网络:
docker run --network=<network_name> --name <container_name> -d <image_name>
  • <network_name>:指定要连接的 ipvlan 网络。
  • <container_name>:指定容器的名称。
  • <image_name>:指定容器所使用的镜像。

通过这样的配置,容器将具有独立的 MAC 地址,并可以直接与物理网络上的其他设备进行通信。

ipvlan 网络驱动程序需要宿主机的内核版本支持,并且一些网络功能可能受到宿主机网络设备的限制。此外,ipvlan 网络驱动程序在多宿主机的分布式环境下也可以使用,以构建具有高度可扩展性和灵活性的容器网络。

None #

None 驱动程序禁用容器的网络功能,使其完全与外部网络隔离。使用 None 驱动程序时,容器将无法进行网络通信,包括与宿主主机或其他容器的通信。 这种网络模式适用于某些安全要求较高的容器,或者仅用于计算任务而不需要网络访问的容器。

1.5.3 NAT 网络地址转换 #

网络地址转换(Network Address Translation,NAT)是一种网络技术,用于在不同网络之间转换 IP 地址。NAT 常用于连接私有网络(如家庭网络或企业内部网络)与公共网络(如 Internet)之间,以实现多个设备共享单个公共 IP 地址的功能。

NAT 的主要目的是解决 IPv4 地址短缺的问题。由于 IPv4 地址资源有限,当一个网络中有多个设备需要连接到 Internet 时,不可能为每个设备都分配一个唯一的公共 IP 地址。这就引入了 NAT 作为一种解决方案。

NAT 通过在网络边界的设备(通常是路由器或防火墙)上执行地址转换,将内部私有 IP 地址转换为外部公共 IP 地址。这样,内部网络中的多个设备可以共享一个或一组公共 IP 地址来访问 Internet。

NAT有几种常见的模式:

  • 静态 NAT(Static NAT):一对一映射,将内部私有 IP 地址与外部公共 IP 地址进行静态映射,一般用于将特定的内部服务(如 Web 服务器)暴露给外部网络。

  • 动态 NAT(Dynamic NAT):多对多映射,内部私有 IP 地址动态地映射到一组可用的公共 IP 地址。

  • PAT(Port Address Translation)或 NAT Overload:将多个内部私有 IP 地址映射到单个公共 IP 地址,通过使用不同的端口号来区分不同的内部连接。

NAT 提供了以下几个好处:

  • 节约公共 IP 地址:通过 NAT,多个设备可以使用相同的公共 IP 地址访问 Internet,节约了 IPv4 地址资源。

  • 增加网络安全性:由于 NAT 会隐藏内部网络的细节,对外部网络而言,只能看到公共 IP 地址,内部网络结构对外部网络来说是不可见的,提高了网络安全性。

  • 简化网络配置:NAT 可以简化内部网络的配置,因为内部设备不需要直接与外部网络进行通信,只需要使用内部私有 IP 地址即可。

虽然 IPv6 地址的广泛采用可以缓解 IPv4 地址短缺问题,因为 IPv6 地址空间更大。但在过渡期间,NAT 仍然是一个常用的网络技术。