8、docker容器跨主机连接
docker容器跨主机连接
本章要点:dockek跨主机连接的几种模式以及简单使用配置
Docker 可通过网桥(如自定义网桥、Open vSwitch、Weave)实现跨主机容器连接,但原生网桥方式因缺点较多不推荐,生产环境更常用 Open vSwitch 或 Weave 等方案。
参考来源: 部分理论AI,Docker的跨主机网络,跨主机2,docker swarm,跨主机网络访问-不同宿主机上的容器之间的通信,跨虚拟机实现容器互联(网桥+ovs+weave)
主流网桥方案对比
- 自定义网桥
- 核心技术 : 调整docker0网段,Linux 网桥工具(bridge-utils)
- 优势: 配置简单,无需额外软件
- 适用场景:小规模集群,同网段环境,测试或临时环境
- 配置复杂度: 低
- 缺点: IP 划分复杂,生产环境难管理,兼容性差
- Open vSwitch(OVS)
- 核心技术 : 虚拟交换机 + GRE 隧道
- 优势: 支持大规模网络自动化,支持复杂网络拓扑,兼容性强
- 适用场景:企业级SDN环境,中大型网络,需灵活管理
- 配置复杂度: 中
- 缺点:需双网卡,步骤繁琐(建网桥、加 GRE 连接等)
- Weave
- 核心技术 : 虚拟网络 + 加密通信 +DNS解析
- 优势: 动态IP管理,即插即用,穿透防火墙,支持加密
- 适用场景:跨主机容器频繁通信场景,跨主机容器直接通信,安全性要求高
- 配置复杂度: 低
- 缺点:需安装 Weave 工具,依赖特定端口(6783)
网桥几种配置
来源:B站极客学院跟AI整合,个人学习记录用
自定义网桥
核心:将物理网卡和docker服务绑定到同一网桥。
-
实现原理
-
在同一个docker的主机中,docker的容器通过默认的docker0网桥来进行网络的通信;
-
将连接容器的网桥也桥接到docker主机提供的网卡上,并且将网桥分配的ip地址与docker主机的ip地址设置为同一ip段, 那我们就相当于将docker机中的容器与docker主机连接到了一起;
-
通过这样的方式来实现docker跨主机容器之间的通信, 在不同的docker机中分别创建网桥,并且使用这个网桥来连接docker主机的物理网卡来连接docker容器。
-
-
操作步骤
- 新建一个网桥br0
- 将物理绑卡绑定到br0
- docker服务启动时 也指定网桥为 br0
- 为docker服务器 进行地址划分(防止ip冲突)
-
示例
# 两台服务器 ip:10.4.50.136 网卡:ens192 操作系统:centos7 ip:10.4.50.102 网卡:ens192 操作系统:centos7
-
前期准备, 我们可以看到未操作前 容器默认桥是docker0
]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02428a698f5e no vethb6d0a03]# ip a 1: lo:.... 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000inet 10.4.50.102/24 brd 10.4.50.255 scope global noprefixroute dynamic ens192 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
-
开始配置
-
1、新建网桥br2 并将 物理网卡ens192 转发到br2网桥中
# 1、新建网桥br2 并将 物理网卡ens192 转发到br2网桥中 ~]# cd /etc/sysconfig/network-scripts/# 这里只加了一台 另一台也一样改下ip就成 ]# cat ifcfg-br2 TYPE=Bridge BOOTPROTO=static NAME=br2 DEVICE=br2 ONBOOT=yesIPADDR=10.4.50.102 NETMASK=255.255.255.0 GATEWAY=10.4.50.1]# cat ifcfg-ens192 TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes DEVICE=ens192 ONBOOT=yesBRIDGE=br2
-
2、docker将指定网桥为 br0、并对齐做子网划分
10.4.50.102 上的docker服务使用网桥配置: -dr0IP: 10.4.50.128/27 地址范围2: 即10.4.50.129~15910.4.50.136 上的docker服务使用网桥配置:IP: 10.4.50.224/27 地址范围2: 即10.4.50.225~254]# cat /etc/docker/daemon.json {"insecure-registries": ["docker.gh-proxy.com"],"exec-opts": ["native.cgroupdriver=systemd"],"bridge":"br2","fixed-cidr":"10.4.50.129/27" }
-
重启服务器 reboot
-
这有个常见的异常
-
问题
# 如果 docker启动不起来 ~]# journalctl -xe 会看到这里的异常 initializing network controller: error creating default "bridge" network: Failed to program NAT chain: ZONE_CONFLICT: 'br2' already bound to a zone
-
原因分析并处理
这是由于 Docker 尝试创建默认的 bridge 网络时,与系统防火墙(如 firewalld)的现有区域配置冲突所致。以下是具体原因和解决方案:错误原因分析 1、您自定义的网桥 br2 已被绑定到 firewalld 的某个区域(如 trusted 或 docker),而Docker 在初始化时尝试重新配置该网桥,导致冲突 2、 Docker 与 firewalld 的兼容性问题 Docker 依赖 iptables 管理网络规则,而 firewalld 在后台也会操作 iptables,两者可能互相覆盖规则 3、处理# 停止并禁用 firewalld systemctl stop firewalld systemctl disable firewalld # 重启 Docker systemctl restart docker 或者直接 reboot服务器
-
-
-
4、检验
]# docker run -d -P --name tomcats1 edf ]# docker inspect tomcats1 截取了一部分,可以看到这里就是直接用的本地局域网的网络了"NetworkSettings": {"Bridge": "br2","SandboxKey": "/var/run/docker/netns/10032d53e870","Gateway": "10.4.50.102","IPAddress": "10.4.50.64","IPPrefixLen": 24,"MacAddress": "02:42:0a:04:32:40","Networks": {"bridge": {"Gateway": "10.4.50.102","IPAddress": "10.4.50.129","IPPrefixLen": 24,}}
-
Open vSwitch
官网, github-ovs,OVS打包, 部署及其它参考文档: centos安装kvm虚拟机遇到的问题,docker实战–跨虚拟机实现容器互联(网桥+ovs+weave),Docker网络基础—Docker跨主机容器访问通信
-
简介
-
OVS是什么?
Open vSwitch是一个高质量的、多层虚拟交换机,其目的是让大规模网络自动化可以通过编程扩展,同时仍然支持标准的管理接口和协议(例如NetFlow, SFlOW, SPAN, RSPAN, CLI, LACP, 802.1ag)
-
Docker与Open vSwitch的协同价值
Open vSwitch 是开源虚拟多层交换机,实现容器网络隔离、跨主机通信及灵活网络策略,支持 OpenFlow 协议与 SDN 控制器通信,适用于物理服务器、虚拟机及容器平台, 与Docker集成后,可提供比默认Linux网桥更精细的网络控制(如VLAN隔离、跨主机通信),满足复杂场景需求
-
-
名词解释
- Bridge: Bridge 代表一个以太网交换机(Switch),一个主机中可以创建一个或者多个 Bridge 设备。
-
Port :Port 与物理交换机的端口概念类似, 每个 Port 都属于一个特定的 Bridge 。端口类型:Normal、Internal、Patch、Tunnel。
- Interface:接口,对应网卡,即可以是 ovs 生成的虚拟网卡,也可能是挂载在 ovs 的物理网卡。在通常情况下,Port 和 Interface 是一对一的关系, 只有在配置 Port 为 bond 模式后, Port 和 Interface 是一对多的关系。
-
Controller: OpenFlow 控制器。OVS 可以同时接受一个或者多个 OpenFlow 控制器的管理。
- Datapath: 在 OVS 中,datapath 负责执行数据交换,也就是把从接收端口收到的数据包在流表中进行匹配,并执行匹配到的动作。
-
Flow table: 每个 datapath 都和一个“flow table”关联,当 datapath 接收到数据之后,OVS 会在 flow table 中查找可以匹配的 flow,执行对应的操作, 例如转发数据到另外的端口。
-
实现原理
-
拓扑
-
网络架构组成
- Docker 容器网络:容器通过
veth
设备连接到docker0
网桥,默认处于隔离的网络命名空间- 补充veth: Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方
- OVS 网桥集成:创建 OVS 网桥(如
br0
),将docker0
网桥加入 OVS 网桥,实现容器流量捕获 - 隧道封装:通过 GRE/VXLAN 等隧道协议封装跨主机流量,经物理网卡转发
- Docker 容器网络:容器通过
-
跨主机通信流程(以 GRE 隧道为例)
-
GRE(General Routing Encapsulation- 通用路由协议封装 )是对网络层协议(如IP、IPX)的数据报文进行封装的技术,使被封装报文能在另一网络层协议(如IP)中传输,也可作为VPN的第三层隧道协议连接不同网络,提供透明数据传输通道, 其本质是通过“隧道”隐藏原始报文细节,实现跨网络类型的通信,例如让非IP协议(如IPX)通过IP网络传输。
-
报文通信流程,可对照拓扑看
步骤 节点1(发送端) 节点2(接收端) 1 容器 eth0
发送数据包至docker0
- 2 OVS 网桥 br0
捕获docker0
流量- 3 数据包经 GRE 协议封装为隧道包 - 4 物理网卡 eth0
转发隧道包物理网卡 eth0
接收隧道包5 - OVS 解封装,获取目标地址 6 - 转发至 docker0
,最终送达目标容器eth0
-
补充OSI七层模型
层级(从下到上) 核心功能 典型协议/技术 数据单位 物理层 传输比特流(0/1电信号) 网线、光纤、RJ45接口、IEEE 802.3 比特(Bit) 数据链路层 链路控制、差错校验 MAC地址、ARP、PPP、以太网协议 帧(Frame) 网络层 GRE在这层 路由选择、IP地址编址 IP、ICMP、IGMP、BGP、RIP 数据包(Packet) 传输层 端到端可靠传输、流量控制 TCP、UDP、RTP 段(Segment) 会话层 建立/管理/终止会话连接 RPC、NetBIOS、SCP 会话数据 表示层 数据格式转换、加密压缩 JPEG、MPEG、SSL/TLS、ASCII 表示数据 应用层 为应用程序提供网络服务 HTTP、FTP、SMTP、Telnet、DNS 数据(Data)
-
-
操作步骤
- 虚拟机中建立ovs网桥
- 添加gre连接
- 配置docker容器虚拟网桥
- 为虚拟网桥添加ovs接口
- 添加不同Docker容器网段路由
-
示例
-
服务器准备
# 两台服务器 ip:10.4.50.130 网卡:ens192,ens224 操作系统:centos7 虚拟网段: 192.168.1.0/24 ip:10.4.50.133 网卡:ens192,ens224 操作系统:centos7 虚拟网段: 192.168.2.0/24
-
所要具备的条件
- 1、双网卡
- 2、安装 openvswitch - 参考扩展-OVS打包
-
1、docker将指定网桥为 br0,主要是设置其它ip地址段
# 两台机器都是一样的操作 ~]# yum -y install bridge-utils # 端口转发要打开 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf ~]# brctl addbr br1 ~]# cat /etc/docker/daemon.json {"insecure-registries": ["docker.gh-proxy.com"],"exec-opts": ["native.cgroupdriver=systemd"],"bridge": "br1","fixed-cidr":"192.168.2.0/24" <--注意修改地址 } # 启动虚拟网桥br1, 设置混杂模式, 重启docker ~]# ip link set br1 up ~]# ip link set br1 promisc on ~]# systemctl restart docker~]# ip a ip:10.4.50.130 br1: 192.168.1.1 ip:10.4.50.133 br1: 192.168.2.1如果想容器间通信还需要加条路由 # 133 上面添加, 添加 192.168.1.0 下一跳是130 经过ens192网卡 ]# ip route add 192.168.1.0/24 via 10.4.50.130 dev ens192# 130 添加, 添加192.168.2.0 下一跳是 133 经过ens192网卡 ]# ip route add 192.168.2.0/24 via 10.4.50.133 dev ens192
-
2、创建虚拟机查看ip地址是否正常
-
下载镜像
~]# docker pull docker.gh-proxy.com/centos7.9.2009 ID: eeb6ee3f44bd ~]# docker pull docker.gh-proxy.com/tomcat-8.5.100-jre8 ID: edf8233555ae
-
运行容器
# 用来Ping ~]# docker run -it --name c1 eeb6ee ctrl+p+q退出 # 还没看到dockerfile将就用吧# 用来测试tomcat ~]# docker run -d -P --name t1 -v share:/usr/local/tomcat/webapps edf~]# docker inspect c1 ip:10.4.50.130 c1: 192.168.1.2 ip:10.4.50.130 t1: 192.168.1.3ip:10.4.50.133 c1: 192.168.2.2 ip:10.4.50.133 t1: 192.168.2.3
-
测试
# 分别测试Ping都ok docker exec -it c1 ping 192.168.2.2 docker exec -it c1 ping 192.168.1.2# 如果碰到 A ping B通, B ping A 怎么调都不通,换个机器试试, 我这搞了一天人麻掉换台虚拟机就都通 # 上述步骤已经可以实现容器间互联了,仿佛不需要ovs了, 搞不懂
-
-
3、配置gre隧道
-
查看ovs状态
]# ovs-vsctl showovs_version: "2.17.12"
-
添加ovs网桥 名:brsw1
]# ovs-vsctl add-br brsw1
-
添加ovs 虚拟机接口
ovs网桥绑定虚拟机接口,将物理接口与虚拟机接口添加进同一个网桥下,即可实现流量链路互通。一个物理口可对应多个虚拟机的接口,即多个虚拟机的其中一个接口可以共用一个物理口,但只能一一对应,不能将同一个虚拟机的多个接口放入同一个ovs网桥内
~]# ovs-vsctl add-port brsw1 我这里直接写的网卡ens224 -- set interface 我这里直接写的网卡ens224 type=gre options:remote_ip=[对端的服务器ip,A写B,B写A]# 133 ~]# ovs-vsctl add-port brsw1 ens224 -- set interface ens224 type=gre options:remote_ip=10.4.50.130# 130 ~]# ovs-vsctl add-port brsw1 ens224 -- set interface ens224 type=gre options:remote_ip=10.4.50.133
-
查看ovs状态
~]# ovs-vsctl show 7168db03-1d5b-4a89-8d59-ba172d5b68d5Bridge brsw1Port ens224Interface ens224type: greoptions: {remote_ip="10.4.50.130"}Port brsw1Interface brsw1type: internalovs_version: "2.17.12"
-
为虚拟网桥添加ovs接口
6. 为虚拟网桥添加ovs接口 ]# brctl addif br1 brsw1 ]# brctl show bridge name bridge id STP enabled interfaces br1 8000.0e03e827334b no brsw1
-
验证一下
# 构建个docker ~]# vi Dockerfile # 使用官方Ubuntu镜像作为基础镜像 FROM ubuntu# 安装net-tools包 RUN apt-get update && apt-get install -y net-tools tcpdump curl inetutils-ping# 启动容器时执行的命令(可选) CMD ["/bin/bash"]~]# docker build -t ubuntu1 .~]# docker run -it --name u1 ubuntu1 19485a44e6db:/# ifconfig -a eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 192.168.2.2 netmask 255.255.255.0 broadcast 192.168.2.255gre0: flags=128<NOARP> mtu 1476unspec 00-00-00-00-FF-00 txqueuelen 1000 (UNSPEC)gretap0: flags=4098<BROADCAST,MULTICAST> mtu 1462ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet)
-
ping 跟测试路由都正常, 只是不明白第2步的时候已经是全通的状态了,后面验证还没找着示例
-
-
-
weave
Docker Weave 是一款轻量级跨主机容器网络方案,无需分布式数据库,支持加密通信与网络隔离,但存在 IP 需手动管理、性能损耗较大等局限。 来源:AI, 极客学院视频部分
-
核心功能
Weave 可创建虚拟网络连接多主机容器,使容器像接入同一交换机般直接通信,无需 NAT 和端口映射, 外部设备与内部系统可双向访问容器服务,且支持穿透防火墙及加密通信 。
-
weave通过在docker集群的每个主机上启动虚拟路由器,将
主机作为路由器
,形成互联互通的网络拓扑,在此基础上,实现容器的跨主机通信。其主机网络拓扑参见下图:
-
关键特性对比
特性 优势 不足 架构依赖 无需 etcd/consul 等分布式数据库,单主机部署组件即可 主机需手动通过 weave launch
加入网络,不支持动态扩缩容网络管理 支持子网隔离(不同子网容器默认不通)、DNS 解析容器主机名 IP 需手动分配,易冲突;通信依赖自定义封包,传输效率低 安全性 可通过密码加密控制面流量,适配不受信任网络 - -
典型使用步骤
-
环境准备:关闭防火墙或开放 6783 端口,各主机安装 Docker 与 Weave。
-
服务器准备
# 两台服务器 ip:10.4.50.130 网卡:ens192 操作系统:centos7 ip:10.4.50.139 网卡:ens192 操作系统:centos7
-
下载
第三方: https://github.com/rajch/weave/blob/master/weave 官方1: https://raw.githubusercontent.com/zettio/weave/master/weave 官方2: curl -L git.io/weave -o /usr/local/bin/weave# 下载,并将它存放在/usr/local/bin/weave # 修改weve权限,使它可以执行 ~]# chmod a+x weave
-
异常1
# Docker 25+ error 'API error (400): client version 1.18 is too old在 Docker 版本 25.0 中,他们已将最低支持的 API 版本从 1.12 更改为 1.24。Weave 仅支持依赖于 Docker API 1.18 的 Docker。# 安装 Docker 引擎版本 25+(其中最低 API 版本高于 1.18) 26版本怎么安装都有异常:分析、https://github.com/weaveworks/weave/issues/4002, 由于 Weaveworks 已经停止运营,这个仓库旨在继续维护 Weave Net,并定期发布版本,我们直接用第三方还在维护的版本、https://github.com/rajch/weave/blob/master/weave, 或者使用低于26版本
-
-
启动weave链接: 下载链接 提取码:2iys
# 官方通过加速器下载 weave docker pull docker.gh-proxy.com/weaveworks/weave docker tag docker.gh-proxy.com/weaveworks/weave:latest weaveworks/weave:latest docker pull docker.gh-proxy.com/weaveworks/weavedb docker tag docker.gh-proxy.com/weaveworks/weavedb:latest weaveworks/weavedb docker pull docker.gh-proxy.com/weaveworks/weaveexec docker tag docker.gh-proxy.com/weaveworks/weaveexec:latest weaveworks/weaveexec# 第三方, 我这里docker26 用的这个 docker tag docker.gh-proxy.com/rajchaudhuri/weave:2.8.4 rajchaudhuri/weave:2.8.4 docker pull docker.gh-proxy.com/rajchaudhuri/weave:2.8.4 docker pull docker.gh-proxy.com/rajchaudhuri/weavedb:latest docker tag docker.gh-proxy.com/rajchaudhuri/weavedb:latest rajchaudhuri/weavedb:latest docker pull docker.gh-proxy.com/rajchaudhuri/weaveexec:2.8.4 docker tag docker.gh-proxy.com/rajchaudhuri/weaveexec:2.8.4 rajchaudhuri/weaveexec:2.8.4# 启动weave ~]# weave launch# 使用bash -x weave launch 可以看到过程毕竟这就是个脚本
-
查看weave启动状态
]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b1d333d51c72 rajchaudhuri/weave:2.8.4 "/home/weave/weaver …" 5 seconds ago Up 3 seconds weave
-
绑定远程机器
# 如果已经执行了第三步, weaves]# weave launch 10.4.50.130 weave is already running; you can stop it with 'weave stop'. weaves]# weave stop# 139上执行 weaves]# weave launch 10.4.50.130# 130上执行 weaves]# weave launch 10.4.50.139
-
启动容器并配置weave网络
# 139上执行 ]# docker run -it --name u2 ubuntucom root@c799badc836c:/# ifconfig 查看网卡 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 # ctrl+p+q 退出 # 给上面的 u2 配置网络 10.0.0.1 ]# weave attach 10.0.0.1/24 c799badc836c 10.0.0.1# 再次查看网卡, 会多一个ethwe网卡,地址就是刚刚命令配置的地址 [root@localhost opt]# docker exec -it c799 ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255 ethwe: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1376inet 10.0.0.1 netmask 255.255.255.0 broadcast 10.0.0.255 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
- 130上配置
# 130上也是一样执行, 地址配成 10.0.0.3/24 ]# docker run -it --name u2 ubuntucom ]# weave attach 10.0.1.1/24 9717 ]# docker exec -it 9717 ifconfig eth0: inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255 ethwe: inet 10.0.1.1 netmask 255.255.255.0 broadcast 10.0.1.255
-
查看两容器是否互通
# 139上ping ]# docker exec -it c799 ping 10.0.0.3 PING 10.0.0.3 (10.0.0.3): 56 data bytes 64 bytes from 10.0.0.3: icmp_seq=0 ttl=64 time=0.103 ms# 130上ping ]# docker exec -it 9717 ping 10.0.0.1 64 bytes from 10.0.0.3: icmp_seq=0 ttl=64 time=0.510 ms# 需要注意的是cidr, 不是同一网段不通
-