vault backup: 2026-11-07 16:33:44
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||

|
||||
|
||||
写 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)**
|
||||
|
||||
```bash
|
||||
# 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 工作节点
|
||||
|
||||
```bash
|
||||
docker network create -d overlay --attachable my-overlay
|
||||
```
|
||||
|
||||
_注意:加上 **--attachable** 才能让独立的容器(非 Swarm Service)也能使用这个网络。_
|
||||
|
||||
|
||||
|
||||
**Step 3: 跨主机验证** 在 Node 1 运行容器:
|
||||
|
||||
```bash
|
||||
docker run -itd --name app1 --network my-overlay alpine
|
||||
```
|
||||
|
||||
在 Node 2 运行容器:
|
||||
|
||||
```bash
|
||||
docker run -itd --name app2 --network my-overlay alpine
|
||||
```
|
||||
|
||||
进入 Node 1 的容器 ping Node 2 的容器:
|
||||
|
||||
```bash
|
||||
docker exec -it app1 ping app2
|
||||
```
|
||||
|
||||

|
||||
|
||||
node1容器
|
||||
|
||||

|
||||
|
||||
node2容器测试
|
||||
|
||||
**结果:** 跨主机 Ping 通!且支持 DNS 解析(直接 Ping 容器名)。
|
||||
|
||||
**Step 4: 查看验证通信原理(vxlan)**
|
||||
|
||||
```bash
|
||||
# 通过查看详情检查是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进行验证**
|
||||
|
||||
```bash
|
||||
# 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 给容器用。
|
||||
|
||||
```bash
|
||||
# 创建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: 运行容器**
|
||||
|
||||
```bash
|
||||
# 创建一个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 一模一样,只是驱动变了。我仍然在
|
||||
|
||||
```bash
|
||||
# 创建一个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: 运行与验证**
|
||||
|
||||
```bash
|
||||
# 运行一个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 通!**
|
||||
Reference in New Issue
Block a user