在Docker网络中,网络命名空间(Network Namespace) 是实现容器网络隔离的核心Linux内核技术。它为每个Docker容器提供了一个完全独立的网络堆栈环境,这意味着每个容器拥有自己的网络接口(如eth0)、IP地址、路由表、ARP表和端口空间。

这种隔离机制确保了不同容器之间以及容器与宿主机之间IP地址和端口不会冲突,使得每个容器都能独立地监听端口或配置网络规则。Docker通过创建虚拟网卡对(veth pair),一端连接到容器的Network Namespace,另一端连接到宿主机的Linux Bridge(如docker0),从而实现容器间的通信以及容器与外部网络的连接。它是Docker提供强大、灵活和安全网络环境的基础。

下面在Ubuntu环境下,命令行配置网络命名空间。包含两个部分,虚拟网线和网桥

  • 虚拟网线(Virtual Cable)

在Linux中,"virtual cable"(虚拟网线)通常指的是 Virtual Ethernet Device (veth pair)。它是一种特殊的网络设备,设计用来在两个网络实体之间创建一个点对点的连接。

你可以把它想象成一根虚拟的网线。与物理网线连接两个物理网卡不同,veth pair 在软件层面连接了两个虚拟的网卡接口。当你创建一个 veth pair 时,实际上会生成两个互相连接的虚拟网络接口:

  1. 成对出现: veth pair 总是成对创建的,例如 veth0 和 veth1。
  2. 点对点连接: 从 veth pair 的一端发出的数据包会立即在另一端接收到,反之亦然,它们之间是双向全工的。
  3. 跨越网络命名空间: 这是 veth pair 最强大的功能之一。它的两端可以分别放置在不同的网络命名空间 (Network Namespace) 中。

参照上图,在宿主机Ubuntu操作系统中,创建两个网络namespace:boy和girl,为其中的网络接口配置IP地址,使用Virtual Cable,使这两个命名空间可以ping通。

# 创建命名空间boy
ip netns add boy

# 创建命名空间girl
ip netns add girl

这两个命名空间和宿主机的命名空间是隔离的。三个命名空间此时相当于处在三个平行宇宙,谁也感知不到谁。

执行完后,在宿主机上执行“ip netns”,可以看到网络命名空间“boy”和“girl”已成功创建,

在命名空间boy中,可以看到内核已经创建了一个环回接口,

在宿主机中创建Virtual Cable,并将两端分别“attach”到boy和girl两个命名空间

# 创建virtual cable
ip link add veth-boy type veth peer name veth-girl

# 将两头分别‘attach’到boy和girl网络命名空间
ip link set veth-boy netns boy
ip link set veth-girl netns girl

当将“Virtual Cable”附加到boy命名空间后,可以看到生成的网络接口“veth-boy@if12”,

文章开头已经说过,“Virtual Cable”实现了点对点的连接,从一端进入的数据包,另一端可以收到,就跟现实中的RJ 45网线一样。为了能够ping通,我们还需要给两个命名空间中的接口配置上IP地址。

# 配置boy命名空间接口ip
ip -n boy addr add 192.168.2.1/24 dev veth-boy

# 配置girl命名空间接口ip
ip -n girl addr add 192.168.2.2/24 dev veth-girl

创建的虚拟接口默认是“down”的状态, 启动它,

ip -n boy link set veth-boy up

ip -n girl link set veth-girl up

然后在任意的命名空间就可以ping通对方了,

如果创建的“Virtual Cable”一端在宿主机,就可以实现宿主机和自建网络命名空间的通信。

  • 网桥(Bridge)

Bridge(网桥)是一个工作在二层(数据链路层)的虚拟网络设备,其核心功能是连接多个网络接口,使其行为如同一个物理以太网交换机。Bridge通过学习和维护一张MAC地址表来智能转发数据帧:当数据帧到达时,它会根据目的MAC地址,将其精确地发送到对应的端口。

我们还是使用上节创建的网络命名空间。开始前,先删除创建的“Virtual Cable”,删除一端即可,另一端会自动删除。

试验拓扑图如下,

宿主机中创建桥接设备“v-net-0”并启动,

想象一下,现在有一个桥接设备,它相当于一台交换机。两个网络命名空间,相当于两台服务器,为了将这两台服务器接入交换机,需要两条网线,也就是两个“Virtual Cable”,

# 第一个‘Virtual Cable’
ip link add veth-boy type veth peer name veth-boy-br

# 第二个‘Virtual Cable’
ip link add veth-girl type veth peer name veth-girl-br

两条“网线”分别接入“服务器”和“交换机”,

# 网线1一头接boy
ip link set veth-boy netns boy
# 网线1另一头接v-net-0,在宿主机网络命名空间
ip link set veth-boy-br master v-net-0

# 网线2一头接girl
ip link set veth-girl netns girl
# 网线2另一头接v-net-0,在宿主机网络命名空间
ip link set veth-girl-br master v-net-0

为它们配置上IP地址并启动,这里有一点特殊,我们需要给“v-net-0”也配置上IP地址。现实中二层交换机设备不需要配置IP地址就可以实现服务器的互通。

# 分配IP地址
ip -n boy addr add 192.168.2.1/24 dev veth-boy
ip -n girl addr add 192.168.2.2/24 dev veth-girl
ip addr add 192.168.2.3/24 dev v-net-0

# 启动自建网络命名空间中的网口
ip -n boy link set veth-boy up
ip -n girl link set veth-girl up

# 启动宿主机中创建的虚拟网口
ip link set dev veth-boy-br up
ip link set dev veth-girl-br up

此时,两台“服务器”就和“交换机”互通了。

这就是docker使用的桥接网络技术。只不过你在使用docker时,它帮你做了这些底层的工作。

如果还要实现在命名空间中访问外面的网站,比如“cn.bing.com”,那如何实现呢?很简单,加条默认路由,然后再配置SNAT就可以了。

# 网络命名空间boy中加入一条默认路由,让宿主机中的v-net-0来转发数据包
ip netns exec boy ip route add default via 192.168.2.3

# 因为包要出去,配置SNAT,在宿主机中操作
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j MASQUERADE

看到已经可以在网络命名空间boy中ping通必应了,

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐