1. Docker网络基础:Docker网络模型概述、网络命名空间、veth pair设备、网桥工作原理

好,咱们直接进入正题。Docker的网络,说白了就是Linux网络的一种封装。很多初学者觉得它玄乎,其实拆开来看,核心就四个东西:网络命名空间、veth pair、网桥,以及Docker自己搞的那套网络模型。我当年刚接触容器时,也被这些概念绕得头晕,后来亲手搭了一遍,才真正搞明白。

1.1 Docker网络模型概述

Docker的网络模型,官方叫CNM(Container Network Model)。别被这个高大上的名字吓到,它其实就是一套标准,规定了容器该怎么连网。

CNM里有三个核心概念:

  • Sandbox(沙箱):容器的网络环境,其实就是网络命名空间。每个容器有自己的沙箱,互相隔离。
  • Endpoint(端点):容器接入网络的接口,通常就是veth pair的一端。
  • Network(网络):一组可以互相通信的端点集合,比如一个网桥就是一个网络。

我个人习惯把这三个东西类比成现实世界:Sandbox是你的房子,Endpoint是你家的门,Network就是你们小区。每个房子有独立的门,门连到小区里,大家就能串门了。

核心要点:Docker默认创建三种网络——bridge(桥接)、host(主机)、none(无网络)。我们最常用的是bridge,后面会重点讲。

1.2 网络命名空间

网络命名空间,这是Linux内核提供的一个隔离机制。它让每个容器拥有独立的网络栈——独立的网卡、路由表、iptables规则等等。

你想想看,如果没有命名空间,所有容器共享主机的网络栈,那端口冲突、路由混乱这些问题就全来了。有了命名空间,每个容器就像一台独立的小机器。

我可以用一条命令来演示命名空间的创建:

# 创建一个名为test_ns的网络命名空间
ip netns add test_ns

# 查看所有命名空间
ip netns list

# 在命名空间里执行命令
ip netns exec test_ns ip addr

嗯,这里要注意:你在主机上看到的网卡,在命名空间里是看不到的。反过来也一样。这就是隔离。

小技巧:排查容器网络问题时,可以用 nsenter 命令进入容器的命名空间,直接查看它的网络配置。我曾经用这招定位过一个DNS解析超时的问题,省了不少时间。

1.3 veth pair设备

好,现在每个容器有自己的网络命名空间了,但它是孤立的。怎么让它和外界通信?这就需要veth pair。

veth pair,说白了就是一根虚拟的网线,两端各连一个网络命名空间。一端在容器里,另一端在主机上(或者网桥上)。数据从一端进去,从另一端出来。

创建veth pair的命令很简单:

# 创建一对veth设备
ip link add veth0 type veth peer name veth1

# 把一端放到命名空间里
ip link set veth1 netns test_ns

# 给两端配置IP并启用
ip addr add 10.0.0.1/24 dev veth0
ip link set veth0 up
ip netns exec test_ns ip addr add 10.0.0.2/24 dev veth1
ip netns exec test_ns ip link set veth1 up

配置完以后,主机和容器就能互相ping通了。我在项目中遇到过一种情况:容器能ping通主机,但主机ping不通容器。排查了半天,发现是主机的iptables规则把流量给DROP了。所以啊,网络不通时,先查防火墙。

避坑指南:我曾经在生产环境遇到过veth pair的MTU不匹配问题。容器里设置了1500,但底层网络是9000的巨型帧,结果导致大量丢包。后来统一改成1450才解决。记住,veth pair两端的MTU必须一致。

1.4 网桥工作原理

现在,一个容器能跟主机通信了。但多个容器之间怎么通信?总不能每两个容器之间都拉一根veth pair吧?那太乱了。

这时候网桥就登场了。网桥,你可以理解成一个虚拟的交换机。所有容器的veth pair都插到这个交换机上,容器之间就能互相通信了。

Docker默认会创建一个叫docker0的网桥:

# 查看docker0网桥
ip addr show docker0

# 查看网桥上的设备
brctl show docker0

网桥的工作原理其实很简单:

  1. 容器A发送数据包,目标IP是容器B
  2. 数据包通过veth pair到达docker0网桥
  3. 网桥检查MAC地址表,找到容器B对应的端口
  4. 数据包从那个端口转发出去,到达容器B

说白了,就是二层交换。跟物理交换机一模一样。

关键点:Docker的bridge网络默认使用NAT(网络地址转换)让容器访问外网。容器发出的数据包,源IP会被替换成主机的IP。但容器之间通信不走NAT,直接通过网桥转发,效率很高。

我建议你亲手做个小实验:启动两个容器,用 docker inspect 查看它们的网络配置,然后用 brctl 观察docker0网桥上的设备变化。你会看到,每启动一个容器,网桥上就多一个接口。这就是Docker网络最朴素的原理。

最后,用一张表格总结一下今天的内容:

组件 作用 类比
网络命名空间 隔离容器的网络栈 独立的房子
veth pair 连接两个命名空间 网线
网桥 转发容器间的数据包 交换机
NAT 让容器访问外网 小区门卫

嗯,这一章就到这里。下一章我们会深入Docker的bridge网络驱动,看看它是怎么自动创建veth pair、配置IP、设置iptables规则的。到时候你会觉得,Docker其实帮我们干了不少脏活累活。