Docker 的 overlay
网络是一种基于 VXLAN(Virtual Extensible LAN)的多主机网络模式,专为 Docker Swarm 集群设计,用于实现跨节点的容器通信。它通过虚拟二层网络,允许容器在不同主机上像在同一局域网内一样通信。Docker 在实现 overlay
网络时,协调用户态(Docker 守护进程、libnetwork)和内核态(Linux 网络栈、VXLAN 模块),完成从网络创建到数据包转发的复杂工作。以下是以 Markdown 格式输出的详细讲解,以两个跨节点容器(例如节点 1 的 gindemo1
和节点 2 的 gindemo2
)通信为例,深入分析 Docker 的核心工作,并具体展示路由表和数据包转发流程。
我们假设以下场景:
192.168.1.9
,主机名 node01
,运行容器 gindemo1
(IP: 10.0.1.2
)。192.168.1.10
,主机名 node02
,运行容器 gindemo2
(IP: 10.0.1.6
)。my-overlay-network
,VNI(VXLAN Network Identifier)为 4097
,子网 10.0.1.0/24
,网关 10.0.1.1
。gindemo2
(节点 2)访问 gindemo1
(节点 1),例如 curl http://gindemo1
。Docker 在实现这一通信的过程中,完成了以下核心工作,并涉及具体的路由表配置。
Docker 通过 libnetwork
和 Swarm 控制平面创建和管理 overlay
网络。
创建网络:
docker network create -d overlay --attachable my-overlay-network
overlay
驱动分配网络 ID 和子网(10.0.1.0/24
)。4097
),存储在配置中(com.docker.network.driver.overlay.vxlanid_list
)。attachable: true
,允许手动附加容器(避免 not manually attachable
错误)。Swarm 同步:
my-overlay-network
,直接使用集群配置。IPAM(IP 地址管理):
10.0.1.0/24
,网关 10.0.1.1
。gindemo1
(10.0.1.2
)、gindemo2
(10.0.1.6
)。Docker 在每个节点上创建 VXLAN 接口和桥接网络,支持跨节点二层通信。
VXLAN 接口:
my-overlay-network
创建 VXLAN 接口(例如 vxlan0
)。4097
。enp0s3
(你的节点 2 网卡)。ip -d link show vxlan0
输出:10: vxlan0: mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether 02:42:ac:11:00:06 brd ff:ff:ff:ff:ff:ff
vxlan id 4097 srcport 0 0 dstport 4789 ...
桥接网络:
br-xxxx
),连接 VXLAN 接口和容器虚拟接口。brctl
已安装):brctl show
输出:bridge name bridge id STP enabled interfaces
br-xxxx 8000.0242ac110006 no vxlan0
veth30344ea
docker_gwbridge 8000.0242bf32025b no vetha7fbe75
vxlan0
:VXLAN 接口,处理跨节点通信。veth30344ea
:gindemo2
的虚拟接口。docker_gwbridge
:用于外部网络连接。你的情况:
ip -d link show type vxlan
无输出),但抓包确认 VNI 4097 和通信正常,说明 VXLAN 功能通过内核或其他机制运行。Docker 为每个容器创建独立的网络命名空间,配置 IP、MAC 和路由。
命名空间创建:
gindemo1
和 gindemo2
创建网络命名空间,隔离网络栈。gindemo2
):docker inspect gindemo2 | grep -A 5 Network
输出: "Networks": {
"my-overlay-network": {
"IPAddress": "10.0.1.6",
"Gateway": "10.0.1.1",
"EndpointID": "xxxx",
"MacAddress": "02:42:ac:11:00:06"
}
}
虚拟接口:
veth
接口对:
eth0
(IP: 10.0.1.6
,MAC: 02:42:ac:11:00:06
)。veth30344ea
,连接到桥接接口(br-xxxx
或 docker_gwbridge
)。docker exec -it gindemo2 ip addr
输出:1: lo: mtu 65536
inet 127.0.0.1/8 scope host lo
30: eth0@if31: mtu 1450
inet 10.0.1.6/24 brd 10.0.1.255 scope global eth0
路由表配置:
gindemo2
容器内):docker exec -it gindemo2 ip route
输出:default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.6
10.0.1.1
(虚拟网关,由 Docker 实现)。10.0.1.0/24
直接通过 eth0
访问,覆盖 gindemo1
(10.0.1.2
)。主机路由表:
my-overlay-network
配置路由,确保数据包进入 VXLAN 隧道。ip route
输出:default via 192.168.1.1 dev enp0s3
10.0.1.0/24 dev br-xxxx proto kernel scope link src 10.0.1.1
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.10
10.0.1.0/24
:通过桥接接口(br-xxxx
)访问,网关 10.0.1.1
。enp0s3
和默认网关 192.168.1.1
。Docker 提供内置 DNS 服务,简化容器间通信。
DNS 配置:
gindemo1
解析为 10.0.1.2
,gindemo2
解析为 10.0.1.6
。通信过程:
gindemo2
执行 curl http://gindemo1
:
gindemo1
,解析到 10.0.1.2
。eth0
。你的抓包:
10.0.1.6
(gindemo2
)访问 10.0.1.2
(gindemo1
)的 websm
端口(80 或 443),DNS 解析正常。Docker 协调内核 VXLAN 模块,完成数据包的封装和跨节点转发。
数据包生成:
gindemo2
(10.0.1.6
)发送 HTTP 请求到 gindemo1
(10.0.1.2
)。10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.6
eth0
发送,目标 IP 10.0.1.2
,MAC 未解析(需 ARP)。ARP 解析:
10.0.1.2
的 MAC(例如 02:42:ac:11:00:02
)。bridge fdb show dev vxlan0
输出(节点 2):02:42:ac:11:00:02 dst 192.168.1.9 self
gindemo1
的 MAC 映射到节点 1(192.168.1.9
)。VXLAN 封装:
br-xxxx
),转发到 VXLAN 接口(vxlan0
)。10.0.1.6
(MAC: 02:42:ac:11:00:06
),目标 10.0.1.2
(MAC: 02:42:ac:11:00:02
)。4097
。192.168.1.10
(动态端口,例如 50730),目标 192.168.1.9:4789
。192.168.1.10
,目标 192.168.1.9
。07:22:12.656724 IP 192.168.1.10.50730 > 192.168.1.9.vxlan: VXLAN, flags [I] (0x08), vni 4097
IP 10.0.1.6.35126 > 10.0.1.2.websm: Flags [S], seq 2498547307, win 28200, ...
转发:
enp0s3
)发送到节点 1。192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.10
192.168.1.9
通过 enp0s3
直接发送。节点 1 解封装:
vxlan0
)解封装。gindemo1
(10.0.1.2
)的 eth0
。default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.2
Docker 配置 iptables,支持容器与外部网络的通信。
NAT 配置:
-p 8081:80
)配置 iptables
的 nat
表(DOCKER
链)。sudo iptables -t nat -L DOCKER
输出:Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- anywhere 0.0.0.0/0 tcp dpt:8081 to:10.0.1.6:80
docker_gwbridge:
192.168.1.10:8081
访问 gindemo2
)。10: docker_gwbridge: mtu 1500 ...
link/ether 02:42:bf:32:02:5b ...
24: vetha7fbe75@if23: ... master docker_gwbridge ...
31: veth30344ea@if30: ... master docker_gwbridge ...
防火墙:
sudo ufw allow 4789/udp
Docker Swarm 提供分布式管理,确保 overlay
网络跨节点一致。
网络同步:
my-overlay-network
,Swarm 自动分发。服务发现:
gindemo2
查询 gindemo1
,返回 10.0.1.2
。故障处理:
docker node ls
),重新同步配置。Docker 优化 overlay
网络的性能。
内核 VXLAN:
多播/单播:
02:42:ac:11:00:02 dst 192.168.1.9 self
MTU:
mss 1410
,确认 MTU 正确。Docker 提供工具支持 overlay
网络调试。
网络检查:
docker network inspect my-overlay-network
:显示 VNI(4097
)、子网、容器 IP。docker inspect gindemo2
:确认 IP 和 MAC。抓包:
IP 192.168.1.10.50730 > 192.168.1.9.vxlan: VXLAN, flags [I] (0x08), vni 4097
日志:
journalctl -u docker
:记录网络错误。Docker 处理 overlay
网络的异常情况。
你的问题(节点 2 无 VXLAN 接口):
modprobe vxlan
)、iproute2
过旧、Docker 网络栈异常。解决方案:
sudo modprobe vxlan
iproute2
:sudo yum update iproute
systemctl restart docker
以下是 gindemo2
(节点 2,10.0.1.6
)访问 gindemo1
(节点 1,10.0.1.2
)的详细流程,包含路由表。
docker exec -it gindemo2 ip route
default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.6
curl http://gindemo1
解析为 10.0.1.2
(Swarm DNS)。10.0.1.6:35126
,目标 10.0.1.2:80
(HTTP)。10.0.1.0/24
,通过 eth0
发送。10.0.1.2
的 MAC,解析为 02:42:ac:11:00:02
。ip route
default via 192.168.1.1 dev enp0s3
10.0.1.0/24 dev br-xxxx proto kernel scope link src 10.0.1.1
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.10
bridge fdb show dev vxlan0
02:42:ac:11:00:02 dst 192.168.1.9 self
veth30344ea
进入桥接接口(br-xxxx
)。vxlan0
,若存在)封装数据包:
10.0.1.6
(MAC: 02:42:ac:11:00:06
),目标 10.0.1.2
(MAC: 02:42:ac:11:00:02
)。192.168.1.10:50730
,目标 192.168.1.9:4789
,VNI 4097
。192.168.1.0/24
,通过 enp0s3
发送。ip route
default via 192.168.1.1 dev enp0s3
10.0.1.0/24 dev br-yyyy proto kernel scope link src 10.0.1.1
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.9
br-yyyy
),匹配 10.0.1.2
。veth
接口送达 gindemo1
的 eth0
。docker exec -it gindemo1 ip route
default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.2
Docker 在 overlay
网络中完成以下核心工作:
4097
)、子网(10.0.1.0/24
),通过 Swarm 同步。vxlan0
)、桥接接口(br-xxxx
)。10.0.1.2
, 10.0.1.6
)、MAC,配置路由表和 veth
接口。gindemo1
到 10.0.1.2
。192.168.1.10
到 192.168.1.9
,VNI 4097
),维护 FDB。docker_gwbridge
。