智能
助手
最大化  清空记录 停止  历史记录
翻译选中文本
选中一段文本后进行翻译
名词解释
选中一段文本后进行名词解释
知识图谱生成
通过图谱展示知识信息
登录用户在知识浏览页面可用
答案生成
AI自动回答一个问答功能中的问题
登录用户在问答浏览页面,且问题开放回答中可用
知识摘要
自动为当前知识生成摘要
知识浏览页面可用
知识问答
针对当前知识进行智能问答
知识浏览面可用
2025-12-20 00:57:24 版本 : 7 跨主机网络解决方案
作者: 文艺范儿 于 2025年12月20日 发布在分类 / Docker & K8S / docker基础 下,并于 2025年12月20日 编辑
 历史版本

备注 修改日期 修改人
创建版本 2025-12-20 00:57:24[当前版本] 文艺范儿

7. 跨主机网络解决方案

7.1 Docker原生方案(内置支持)

方案 驱动 核心原理 适用场景 配置复杂度

Overlay网络

overlay

VXLAN隧道+加密

Docker Swarm集群

中等

Macvlan网络

macvlan

容器直连物理网卡

需要独立公网IP的容器

IPvlan网络

ipvlan

容器共享物理网卡MAC

网络设备限制MAC数量的环境

7.2 第三方CNI插件方案(推荐生产使用)

方案 网络模式 核心特性 性能 安全性

Calico

BGP路由/IPIP隧道

网络策略、IPAM、支持K8s

企业级

Flannel

VXLAN/host-gw/云厂商集成

简单易用、社区活跃

基础

Weave Net

VXLAN+自有路由

内置加密、服务发现

良好

Cilium

eBPF

L3/L7策略、可观测性

极高

企业级

7.3 macvlan实现跨主机互联(生产不推荐 )

7.3.1 什么是 Macvlan?

  • Macvlan 允许在单个物理网卡上创建多个虚拟 MAC 地址的虚拟接口
  • 每个容器获得独立的 MAC 地址和 IP 地址,在物理网络中表现为独立的设备
  • 容器流量不经过 Docker 网桥/NAT,直接通过物理网卡进出

7.3.2 架构示意图

graph TB
    subgraph 物理网络
        Switch[物理交换机]
    end

    subgraph 主机A
        NIC_A[物理网卡 eth0]
        MACVLAN_A[Macvlan接口<br/>macvlan0]
        Container_A[容器A IP: 172.29.0.10]
    end

    subgraph 主机B
        NIC_B[物理网卡 eth0]
        MACVLAN_B[Macvlan接口<br/>macvlan0]
        Container_B[容器B IP: 172.29.0.11]
    end

    Container_A -->|直接通过| MACVLAN_A
    MACVLAN_A -->|虚拟接口| NIC_A
    NIC_A -->|物理网络| Switch

    Container_B -->|直接通过| MACVLAN_B
    MACVLAN_B -->|虚拟接口| NIC_B
    NIC_B -->|物理网络| Switch

    Container_A <-->|二层直接通信| Container_B

7.3.3 实战案例:双节点macvlan互联

1. 环境准备

# 节点信息
节点A: 
  IP: 192.168.1.71/24
  网关: 192.168.1.1
  物理网卡: ens34
  Docker版本: 20.10+

节点B:
  IP: 192.168.1.72/24
  网关: 192.168.1.1
  物理网卡: ens34
  Docker版本: 20.10+

2. 网络拓扑规划

注意: Macvlan bridge模式 + 独立子网

网络规划:
  物理网络: 192.168.1.0/24
  容器IP段: 172.29.0.0/16
  网关: 172.29.0.254

3.具体操作步骤

a.检查网络环境

注意:我这里是ESXI8 开的虚拟机,需要在ESXI8控制台,网络-端口组-安全-接受混杂模式

# 在节点A和B上都执行
# 需要开启混杂模式,这里不做描述
# 确认物理网络配置
ip addr show ens34
# 输出示例: inet 192.168.1.71/24 brd 192.168.1.255 scope global ens34

# 检查macvlan模块是否已加载
lsmod | grep macvlan

# 检查模块是否存在系统中
modinfo macvlan

# 尝试手动加载模块
modprobe macvlan

## 永久启用
# 添加到模块加载列表
echo "macvlan" | sudo tee -a /etc/modules
# 或者创建模块配置文件
echo "options macvlan" | sudo tee /etc/modprobe.d/macvlan.conf
# 更新initramfs(某些系统需要)
update-initramfs -u

# 再次检查是否加载成功
lsmod | grep macvlan

# 检查网络命名空间支持(Macvlan依赖此功能)
ip netns add test_ns && echo "✅ 支持网络命名空间" && ip netns delete test_ns

b.创建macvlan网络

# 在节点A上创建
docker network create -d macvlan --subnet 172.29.0.0/16 --gateway 172.29.0.254 -o parent=ens34 macvlan-test

# 在节点B上创建(使用相同的配置)
docker network create -d macvlan --subnet 172.29.0.0/16 --gateway 172.29.0.254 -o parent=ens34 macvlan-test

参数详解:

  • --subnet: 物理网络的子网
  • --gateway: 物理网络的网关
  • --ip-range: 为该 Macvlan 网络分配的 IP 范围
  • --aux-address: 排除宿主机的 IP,避免冲突
  • -o parent: 指定父接口(物理网卡)
  • -o macvlan_mode: Macvlan 模式(bridge 最常用)

c.运行容器并测试

# 在节点A上运行容器
docker container run -d -it --name box1 --network macvlan-test --ip 172.29.0.71 busybox

# 在节点B上运行容器
docker container run -d -it --name box2 --network macvlan-test --ip 172.29.0.72 busybox

d.测试夸主机通信

# 在节点A的容器中测试连接节点B的连通性
[root@docker-71 ~]# docker exec -it  box1 sh 
/ # ping -c 3 172.29.0.72
PING 172.29.0.72 (172.29.0.72): 56 data bytes
64 bytes from 172.29.0.72: seq=0 ttl=64 time=0.421 ms
64 bytes from 172.29.0.72: seq=1 ttl=64 time=0.573 ms
64 bytes from 172.29.0.72: seq=2 ttl=64 time=0.486 ms

--- 172.29.0.72 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.421/0.493/0.573 ms
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 26:ED:AB:B4:65:16  
          inet addr:172.29.0.71  Bcast:172.29.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1200 errors:0 dropped:205 overruns:0 frame:0
          TX packets:1409 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:92250 (90.0 KiB)  TX bytes:87346 (85.2 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:917 errors:0 dropped:0 overruns:0 frame:0
          TX packets:917 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:102704 (100.2 KiB)  TX bytes:102704 (100.2 KiB)
/ # 

# 在节点B的容器中测试,测试到节点A容器的连通性
[root@docker-72 ~]# docker exec box2 sh -c "ping -c 3 172.29.0.71"
PING 172.29.0.71 (172.29.0.71): 56 data bytes
64 bytes from 172.29.0.71: seq=0 ttl=64 time=0.448 ms
64 bytes from 172.29.0.71: seq=1 ttl=64 time=0.581 ms
64 bytes from 172.29.0.71: seq=2 ttl=64 time=0.588 ms

--- 172.29.0.71 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.448/0.539/0.588 ms

e.解决macvlan无法访问外网的情况

#添加一个能够访问外网的网络类型
[root@docker-72 ~]# docker network connect bridge box2 
[root@docker-72 ~]# docker exec box2 sh -c "ping -c 3 223.5.5.5"

7.4 Consul+Overlay 跨主机容器网络部署

Overlay 网络 是一种在现有网络之上构建的虚拟网络,它允许多个主机上的容器或虚拟机像在同一个局域网中一样通信,而无需修改底层物理网络结构。

目标:构建基于 Consul 服务发现的容器跨主机网络解决方案

架构:Consul 集群 + Docker 自定义网络 + 容器间服务发现


7.4.1 环境规划

主机信息
主机名 IP 地址 角色 功能

consul-server-1

192.168.1.71

Consul Server + Docker 主机

Consul 主服务器,运行服务

consul-server-2

192.168.1.72

Consul Server + Docker 主机

Consul 备份服务器,运行服务

consul-client-1

192.168.1.73

Consul Client + Docker 主机

Consul 客户端,运行服务

网络规划
  • 物理网络:192.168.1.0/24

  • Overlay 网络:10.20.0.0/16

  • 服务端口

    • Consul HTTP: 8500

    • Consul DNS: 8600

    • Consul RPC: 8300

    • Consul Serf LAN: 8301

    • Consul Serf WAN: 8302


7.4.2 准备环境

步骤 1.1:所有节点系统准备

在 consul-server-1, consul-server-2, consul-client-1 上都执行

# 1. 设置主机名
hostnamectl set-hostname consul-server-1  # 在 server-1 上执行
hostnamectl set-hostname consul-server-2  # 在 server-2 上执行
hostnamectl set-hostname consul-client-1  # 在 client-1 上执行

# 2. 编辑 hosts 文件
tee -a /etc/hosts << EOF
192.168.1.71 consul-server-1
192.168.1.72 consul-server-2
192.168.1.73 consul-client-1
EOF

# 3. 安装 Docker
此处省略...

7.4.3 部署 Consul 集群

1:在 consul-server-1 上启动第一个 Consul Server
# 1. 创建 Consul 数据目录
mkdir -p /opt/consul/data
mkdir -p /etc/consul

# 2. 创建 Consul 配置文件
tee /etc/consul/server1.json << EOF
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "log_level": "INFO",
  "node_name": "consul-server-1",
  "server": true,
  "bootstrap_expect": 2,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "advertise_addr": "192.168.1.71",
  "ui": true,
  "enable_syslog": false,
  "ports": {
    "dns": 8600,
    "http": 8500,
    "serf_lan": 8301,
    "serf_wan": 8302,
    "server": 8300
  }
}
EOF

# 3. 启动 Consul Server
docker run -d \
  --name=consul-server-1 \
  --restart=always \
  --net=host \
  -v /opt/consul/data:/consul/data \
  -v /etc/consul:/consul/config \
  consul:1.15 agent \
  -config-dir=/consul/config \
  -node=consul-server-1 \
  -bind=192.168.1.71 \
  -advertise=192.168.1.71 \
  -client=0.0.0.0 \
  -datacenter=dc1 \
  -server \
  -bootstrap-expect=2 \
  -ui
2:在 consul-server-2 上启动第二个 Consul Server
# 1. 创建目录
mkdir -p /opt/consul/data
mkdir -p /etc/consul

# 2. 创建配置
tee /etc/consul/server2.json << EOF
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "log_level": "INFO",
  "node_name": "consul-server-2",
  "server": true,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "advertise_addr": "192.168.1.72",
  "ui": true,
  "retry_join": ["192.168.1.71"],
  "ports": {
    "dns": 8600,
    "http": 8500,
    "serf_lan": 8301,
    "serf_wan": 8302,
    "server": 8300
  }
}
EOF

# 3. 启动 Consul Server
docker run -d \
  --name=consul-server-2 \
  --restart=always \
  --net=host \
  -v /opt/consul/data:/consul/data \
  -v /etc/consul:/consul/config \
  consul:1.15 agent \
  -config-dir=/consul/config \
  -node=consul-server-2 \
  -bind=192.168.1.72 \
  -advertise=192.168.1.72 \
  -client=0.0.0.0 \
  -datacenter=dc1 \
  -server \
  -retry-join=192.168.1.71
3:在 consul-client-1 上启动 Consul Client
# 1. 创建目录
mkdir -p /opt/consul/data
mkdir -p /etc/consul

# 2. 创建配置
tee /etc/consul/client1.json << EOF
{
  "datacenter": "dc1",
  "data_dir": "/opt/consul/data",
  "log_level": "INFO",
  "node_name": "consul-client-1",
  "server": false,
  "bind_addr": "0.0.0.0",
  "client_addr": "0.0.0.0",
  "advertise_addr": "192.168.1.73",
  "ui": false,
  "retry_join": ["192.168.1.71", "192.168.1.72"],
  "ports": {
    "dns": 8600,
    "http": 8500,
    "serf_lan": 8301,
    "server": 8300
  }
}
EOF

# 3. 启动 Consul Client
docker run -d \
  --name=consul-client-1 \
  --restart=always \
  --net=host \
  -v /opt/consul/data:/consul/data \
  -v /etc/consul:/consul/config \
  consul:1.15 agent \
  -config-dir=/consul/config \
  -node=consul-client-1 \
  -bind=192.168.1.73 \
  -advertise=192.168.1.73 \
  -client=0.0.0.0 \
  -datacenter=dc1 \
  -retry-join=192.168.1.71
4:验证 Consul 集群
# 在任意节点执行
curl -s http://192.168.1.71:8500/v1/agent/members | jq .
curl -s http://192.168.1.71:8500/v1/catalog/nodes | jq .

# 访问 Web UI
Consul Web UI: http://192.168.1.71:8500

7.4.4 创建 Docker Overlay 网络

1:Swarm操作

在 Docker 中,Overlay 网络依赖于 Swarm 控制平面来分发网络配置到各节点,因此必须先初始化 Swarm。

# 1️⃣ 在当前节点(consul-server-1)初始化 Swarm. --advertise-addr指定该节点对外通告的 IP(必须是其他节点能访问的地址)。
docker swarm init --advertise-addr 192.168.1.71


# 2️⃣ 在其他节点加入 Swarm,
# 测试只有加入manager时其它两个节点才会同步网络(worker不会),我也不知道为什么。
# 在 consul-server-2和 consul-client-1分别执行上一步输出的 docker swarm join manager...命令。
# 如果忘记了token,可以在manager节点查看:

# 查看加入命令(worker)
docker swarm join-token worker

# 查看加入命令(manager)
docker swarm join-token manager

# 在 consul-server-2 执行
docker swarm join --token SWMTKN-1-xxxxxx 192.168.1.71:2377
# 在 consul-client-1 执行
docker swarm join --token SWMTKN-1-xxxxxx 192.168.1.71:2377

# 3️⃣ 验证 Swarm 状态
# 在 manager 节点(consul-server-1):
[root@consul-server-1 ~]# docker node ls
ID                            HOSTNAME          STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
qxcnxi779r3wvp43hvkhusipo     consul-client-1   Ready     Active         Reachable        29.1.3
jn39c7awwa5l50tqccbdxjy6a *   consul-server-1   Ready     Active         Leader           29.1.3
orc7648vp80ttrg1xzdk28obg     consul-server-2   Ready     Active         Reachable        29.1.3
2:在 consul-server-1 上创建 Overlay 网络
# 创建 Overlay 网络
docker network create \
  --driver overlay \
  --attachable \
  --subnet 10.20.0.0/16 \
  consul-overlay-net

# 查看网络
docker network ls
docker network inspect consul-overlay-net
3:在所有节点上验证网络

任何客户端节点创建网络,其他客户端会通过consul来实时同步配置

# 在 consul-server-2 和 consul-client-1 上执行
docker network ls | grep overlay
# 应该能看到 consul-overlay-net

# 如果还是看不到,尝试刷新 Docker 网络
systemctl restart docker
# 或者
docker swarm update --task-history-limit 5

7.4.5 部署服务到 Overlay 网络

1:在 consul-server-1 上部署 Web 服务
# 1. 运行 Web 服务
docker run -d \
  --name web-service-1 \
  --network consul-overlay-net \
  --label "consul=true" \
  --label "service=web" \
  --label "version=1.0" \
  -p 8080:80 \
  nginx:alpine

# 2. 注册服务到 Consul
docker exec consul-server-1 sh -c '
  cat > /tmp/web-service.json << EOF
  {
    "ID": "web-service-1",
    "Name": "web",
    "Tags": ["nginx", "production"],
    "Address": "$(hostname -i)",
    "Port": 80,
    "Check": {
      "HTTP": "http://$(hostname -i):80",
      "Interval": "10s",
      "Timeout": "5s"
    }
  }
  EOF
  curl -X PUT http://127.0.0.1:8500/v1/agent/service/register -d @/tmp/web-service.json
'
2:在 consul-server-2 上部署另一个 Web 服务实例
# 1. 运行 Web 服务
docker run -d \
  --name web-service-2 \
  --network consul-overlay-net \
  --label "consul=true" \
  --label "service=web" \
  --label "version=1.0" \
  nginx:alpine

# 2. 注册服务到 Consul
WEB2_IP=$(docker inspect web-service-2 --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')

cat > /tmp/web-service-2.json << EOF
{
  "ID": "web-service-2",
  "Name": "web",
  "Tags": ["nginx", "production"],
  "Address": "$WEB2_IP",
  "Port": 80,
  "Check": {
    "HTTP": "http://$WEB2_IP:80",
    "Interval": "10s",
    "Timeout": "5s"
  }
}
EOF

curl -X PUT http://192.168.1.72:8500/v1/agent/service/register -d @/tmp/web-service-2.json
3:在 consul-client-1 上部署 API 服务
# 1. 运行 API 服务(用 nginx 模拟)
docker run -d \
  --name api-service-1 \
  --network consul-overlay-net \
  --label "consul=true" \
  --label "service=api" \
  --label "version=1.0" \
  nginx:alpine

# 2. 注册 API 服务
API_IP=$(docker inspect api-service-1 --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')

cat > /tmp/api-service.json << EOF
{
  "ID": "api-service-1",
  "Name": "api",
  "Tags": ["rest", "backend"],
  "Address": "$API_IP",
  "Port": 80,
  "Check": {
    "HTTP": "http://$API_IP:80",
    "Interval": "10s",
    "Timeout": "5s"
  }
}
EOF

curl -X PUT http://192.168.1.73:8500/v1/agent/service/register -d @/tmp/api-service.json

7.4.6 测试服务发现和跨主机通信

1:测试跨主机容器通信
# 在 consul-server-1 上测试
docker exec web-service-1 ping -c 3 api-service-1
# 应该成功

# 在 consul-client-1 上测试
docker exec api-service-1 ping -c 3 web-service-1
# 应该成功
2:验证服务注册
# 查看所有服务
curl -s http://192.168.1.71:8500/v1/catalog/services | jq .

# 查看 web 服务详情
curl -s http://192.168.1.71:8500/v1/catalog/service/web | jq .

# 查看健康的服务实例
curl -s "http://192.168.1.71:8500/v1/health/service/web?passing=true" | jq .

# 查看集群状态
curl -s http://192.168.1.71:8500/v1/status/leader
curl -s http://192.168.1.71:8500/v1/status/peers

# 查看健康检查
curl -s http://192.168.1.71:8500/v1/health/state/critical

7.5 Calico 跨主机互联手动部署案例(可用于k8s集群)

目标:实现 Docker 容器跨主机直接路由通信,无需 Overlay 网络

优点:高性能、无 NAT、支持网络策略、生产验证

后面到k8s再讲。

历史版本-目录  [回到顶端]
    文艺知识分享平台 -V 5.2.5 -wcp