Files
Knowledge/1 使用/docker/告别单机自嗨 从Docker容器跨主机通信需求到Overlay、Macvlan、IPvlan网络原理与实战.md
T

10 KiB
Raw Blame History

告别单机自嗨:从Docker容器跨主机通信需求到Overlay/Macvlan/IPvlan网络原理与实战

写 Docker 的朋友大概都经历过一个阶段:在单机上玩得飞起 docker run 用得滚瓜烂熟。但当业务扩展,需要两台服务器上的容器直接“对话”时,问题就来了。

默认的 bridge 网络只能管自家一亩三分地,跨主机通信怎么办?难道只能靠繁琐的端口映射和复杂的 iptables 转发?

当然不是。Docker 早已为我们准备了三把利剑:Overlay、Macvlan 和 IPvlan。

Docker官网的几种网络模式

今天这篇文章,我们就从原理到实战,彻底把这三者讲清楚,顺便带你避开那些文档里不常说的“坑”。

一、 为什么我们需要跨主机通信?

在默认的 bridge 模式下,Docker 容器通过 NAT(网络地址转换)访问外部。外部要访问容器,必须通过端口映射。

痛点很明显:

  1. 端口管理地狱:几十个微服务,端口号记不住,还容易冲突。
  2. 性能损耗:NAT 转换在大流量下是 CPU 杀手。
  3. IP 不可见:容器没有真实局域网 IP,传统的监控、服务发现工具无法直接通过 IP 管理容器。

我们想要的是:容器像虚拟机一样,拥有局域网内的独立 IP,不仅跨主机能通,还能和物理机直接互联。

二、 方案一:Overlay 网络 (Docker Swarm 的默认选择)

如果你用过 Docker Swarm 或 K8s (Flannel/Calico),对 Overlay 应该不陌生。

1. 原理核心:VXLAN 隧道

Overlay 网络是在现有的物理网络(Underlay)之上,构建了一个虚拟网络。

  • 封装:当主机 A 的容器发包给主机 B 的容器时,Docker 会把原始数据包封装在一个 VXLAN 包(UDP 4789端口)里。
  • 传输:这个 UDP 包像普通数据一样在物理网络传输。
  • 解封:到达主机 B 后,Docker 拆开 UDP 包,拿出原始数据,塞给目标容器。

通俗理解: 就像寄快递。原本的信件(容器数据)被装进了一个快递盒(VXLAN 封装),快递员(物理网络)只看快递单(物理 IP),不管盒子里装啥。到了目的地,拆盒取信。

2. 实战测试

Overlay 需要依赖键值存储(KV Store)来同步网络信息,最简单的办法是使用 Docker Swarm 模式(无需安装额外组件),早期的Docker版本(17.03前)配置中也可使用外部组件如consul、etcd等同步信息

环境准备:

  • Node 1 (Manager): 172.21.14.5
  • Node 2 (Worker): 172.21.14.6
  • Docker环境 (我的 Docker version 26.1.5+dfsg1, build a72d7cd , 带docker swarm)

核心端口要求(Swarm 集群必需)

  • 2377/tcp:Swarm 集群管理通信
  • 7946/tcp/udp:节点间通信(覆盖网络发现)
  • 4789/udp:Overlay 网络数据传输(VXLAN)

Step 1: 初始化 Swarm (node1) , 加入Swarm集群(node2)

# node1上  Manager
docker swarm init --advertise-addr 172.21.14.5
# 执行后会给出一个 token 命令,复制该命令到 Node 2 执行即可加入集群 ,也会打开了相应的端口

# node2上  Worker
docker swarm join --token SWMTKN-1-028glf3487mka3134oot1z2rxfmbisqj7jaqan9gayvmwjjcpl-e5hpu73a6fvegdm5xi10otl15 172.21.14.5:2377

# node1上  Manager
docker node ls

运行docker swarm init后

执行完后已查看到一个节点

加入docker

已经有两个节点了

**Step 2: 创建 Overlay 网络,**Swarm 会自动同步到node2 工作节点

docker network create -d overlay --attachable my-overlay

注意:加上 --attachable 才能让独立的容器(非 Swarm Service)也能使用这个网络。

Step 3: 跨主机验证 在 Node 1 运行容器:

docker run -itd --name app1 --network my-overlay alpine

在 Node 2 运行容器:

docker run -itd --name app2 --network my-overlay alpine

进入 Node 1 的容器 ping Node 2 的容器:

docker exec -it app1 ping app2

node1容器

node2容器测试

结果: 跨主机 Ping 通!且支持 DNS 解析(直接 Ping 容器名)。

Step 4: 查看验证通信原理(vxlan)

# 通过查看详情检查是vxlan
docker network inspect my-overlay 

# 主机tcpdump抓包通信过程,之前说到的4789端口
 tcpdump -i eth0 port 4789 -c 10 -nn

docker network inspect查看

tcpdump 抓取vxlan 4789端口数据包

Step 5: 使用service进行验证

# node1上创建service1 并进行验证,并调度到node1节点
docker service create --name service1 --network my-overlay --replicas  3  --constraint node.hostname==iZt4n4moivyl2vcl14obxcZ nginx:alpine

# 查看service
docker service ls

# 查看容器
docker ps

# node1上创建service2 并进行验证,并调度到node2节点
docker service create --name service2 --network my-overlay --replicas  3  --constraint node.hostname==iZt4n4moivyl2vcl14obxdZ nginx:alpine

# 查看service
docker service ls

# 在node2上查看容器,看调度情况
docker ps

创建两个service进行验证

在node1上验证service2的连通性和nginx服务

三、 方案二:Macvlan (性能之王)

在验证了overlay后,看到官方还有IPvlan 、Macvlan,也想着来验证下。(云服务器测试可能不通)

官方network

Overlay 虽然方便,但 VXLAN 封包解包有 CPU 损耗。如果你的应用对网络延迟极度敏感(如高频交易、VoIP),Macvlan 是更好的选择。

1. 原理核心:子接口与独立 MAC

Macvlan 允许你在物理网卡(如 eth0)上创建多个“子接口”,每个子接口都有独立的 MAC 地址和 IP 地址。

  • 从交换机来看,你的服务器仿佛变身成了接了 N 台设备的“交换机”。
  • 容器直接通过 Layer 2(数据链路层)通信,无需 NAT,性能几乎等同于物理机。

2. 实战测试

前提: 你的物理网卡需要支持(大部分都支持),且交换机开启混杂模式(Promiscuous Mode,如果在 VMware 虚拟机里测试,记得在 vSwitch 安全设置里开启“混杂模式”)。

Step 1: 创建 Macvlan 网络 (两台主机都要执行) 假设物理网段是 △192.168.1.0/24△,网关 △192.168.1.1△,我们划出一部分 IP 给容器用。

# 创建macvlan网络
docker network create -d macvlan \
 --subnet=172.18.200.0/24 \
 --gateway=172.18.200.254 \
 -o parent=enp3s0  macvlan-net 
9460256b68801cf46f5c21dff59c7a79d9a757010c5d6cc0414e5a1474d5433b

Step 2: 运行容器

# 创建一个172.18.200.222的容器
docker run -d --name app  \
  --network macvlan-net \
  --ip=172.18.200.222  \
  nginx:1.23-alpine

运行macvlan网络和容器

Step 3: 验证 容器互 Ping、容器 Ping 外部物理机均可通, 这个过程可能需要一点儿时间。

局域网访问macvlan ip

在物理机上进行验证

四、 方案三:IPvlan (云环境救星)

Macvlan 有个缺点:每个容器都要一个新的 MAC 地址。很多公有云厂商(AWS, 阿里云等)的虚拟交换机有限制,如果不认识这个 MAC 地址,直接丢弃数据包。这就导致 Macvlan 在云上往往跑不通。

IPvlan 应运而生。

1. 原理核心:共享 MAC

IPvlan 也有 L2 和 L3 两种模式,最常用的是 L2。

  • 所有容器共享宿主机物理网卡的 MAC 地址。
  • 虽然 MAC 一样,但 IP 不同,Linux 内核根据 IP 地址进行流量分发。

2. 实战测试 (L2 模式)

该命令需要 Linux 内核 >= 4.2。

Step 1: 创建 IPvlan 网络 语法几乎和 Macvlan 一模一样,只是驱动变了。我仍然在

# 创建一个ipvlan网络,创建之前要先删除之前的Macvlan(因为网络相同冲突了)
docker network create -d ipvlan \
  --subnet=172.18.200.0/24 \
  --gateway=172.18.200.254 \
  -o parent=enp3s0  \
  -o ipvlan_mode=l2 \
  ipvlan-net

Step 2: 运行与验证

# 运行一个ipvlan-net 容器
docker run -d --name app \
  --network ipvlan-net \
 --ip=172.18.200.222 nginx:1.23-alpine

本机验证ip及网络

五、 总结:我该选哪个?

为了方便大家决策,我做了一张对比表:

特性 Overlay Macvlan IPvlan (L2)
应用场景 容器编排 (Swarm/K8s) 传统应用迁移、高性能需求 公有云环境、MAC受限环境
配置难度 简单 (Swarm原生) 中等 (需规划网段) 中等
性能 有损耗 (VXLAN封装) 极高 (接近物理机) 极高
网络层级 纯虚拟网络 物理网络二层打通 物理网络二层打通
MAC地址 虚拟 MAC 每个容器独立 MAC 共享宿主机 MAC
最大缺点 只有 Docker 内部互通 容易耗尽交换机 MAC 表 旧内核不支持

极简决策树:

  1. 如果在云服务器上跑,且不能申请辅助网卡 -> 选 Overlay。
  2. 如果是自建机房,追求极致性能 -> 选 Macvlan。
  3. 如果是自建机房,但交换机限制了 MAC 地址数量 -> 选 IPvlan。

最后一步:

看完原理和实验,建议你找两台虚拟机(VirtualBox 或 VMWare),按照文章里的命令敲一遍。网络这东西,纸上得来终觉浅,绝知此事要 Ping 通!