一、开篇:为什么要搞跨主机容器通信?
先给大家说个真实的场景:你做了个外卖订单系统,分了三个核心模块:用户下单模块、订单处理模块、库存扣减模块。一开始你电脑配置够,把三个模块都装在自己电脑的Docker容器里,跑起来完全没问题,模块之间互相访问快得很。但后来用户多了,你电脑扛不住,只能把订单模块移到公司的第二台服务器上。这时候问题来了:原来能直接互相访问的两个容器,现在分别在两台不同的服务器上,就像两个邻居家的猫,中间隔了一堵水泥墙,谁也找不到谁。这时候就需要搞跨主机的容器通信,而最常用的两种方案就是overlay网络和路由模式。
二、先搞懂:容器网络的基础逻辑
要理解后面的两种方案,得先搞懂一个最基础的事:容器为什么能通信?其实容器就是个“隔离的小电脑”,每个容器都有自己的IP地址,就像每个手机都有自己的手机号。同一个电脑上的容器,都连在一个Docker自己搭的“小局域网”里,比如Docker默认的bridge网络,这个局域网里的容器,互相之间就像同个WiFi下的手机,能直接打电话(访问)。但不同电脑的容器,相当于不同城市的手机,不在同个WiFi,得有专门的“长途通信”方案才能互相联系。
三、方案一:overlay网络——给所有容器搭个“跨城市的专属WiFi”
3.1 什么是overlay网络?
overlay网络的核心逻辑,就是给所有需要通信的容器,不管它们在哪个电脑上,都拉到同一个“虚拟专属WiFi”里。这个WiFi是Docker自己在两台电脑的真实网络上“搭”出来的,相当于在两个城市之间铺了一条专用的光纤,所有容器都连在这条光纤上,互相之间就像同个WiFi下的设备,能直接用IP访问。
3.2 overlay网络的具体操作(技术栈:Docker Swarm)
这里我们用Docker官方的Swarm集群来演示,因为overlay网络最常用的场景就是Swarm集群。先给大家说清楚环境:我们有两台服务器,分别叫server1(IP是192.168.1.10)和server2(IP是192.168.1.20),都是CentOS系统,已经装好了Docker。
第一步:先把两台服务器组成Swarm集群。先在server1上执行命令,把它设为集群的管理节点:
# 初始化Swarm集群,指定当前节点的通信IP是192.168.1.10
docker swarm init --advertise-addr 192.168.1.10
执行完后,会输出一个加入集群的命令,类似:
docker swarm join --token SWMTKN-1-xxxxxx 192.168.1.10:2377
然后我们去server2上执行这个命令,把server2加入集群,变成工作节点。
第二步:创建一个overlay网络,叫my-overlay:
# 创建overlay网络,attachable表示允许普通容器(不是Swarm服务)连进来
docker network create -d overlay --attachable my-overlay
第三步:分别在两台服务器上启动两个容器,都连到my-overlay网络: 先在server1上启动一个nginx容器,叫nginx1:
# 启动nginx容器,连到my-overlay网络,容器名设为nginx1
docker run -d --name nginx1 --network my-overlay nginx:alpine
再在server2上启动一个busybox容器,叫busybox1:
# 启动busybox容器,连到my-overlay网络,容器名设为busybox1
docker run -d --name busybox1 --network my-overlay busybox:latest sleep 3600
第四步:测试跨主机通信。我们进入busybox1容器,访问nginx1的IP:
# 进入busybox1容器的命令行
docker exec -it busybox1 sh
然后在容器里执行:
# 先查nginx1的IP,也可以直接用容器名访问,因为overlay网络会自动解析容器名
ping nginx1
执行后你会发现,能ping通!而且就算你把nginx1换到server2上,busybox1还是能找到它,因为这个虚拟WiFi是跨主机的。
3.3 overlay网络的适用场景、优缺点和注意事项
适用场景
- 微服务架构:比如上面说的外卖订单系统,多个模块分布在不同服务器,需要互相频繁访问,而且模块的部署位置经常变;
- 容器集群管理:比如Swarm集群、K8s集群(K8s的Calico、Flannel很多都是基于overlay的逻辑),需要统一管理容器的网络;
- 有状态服务:比如数据库容器,需要固定的网络标识,换服务器后不用改配置。
优点
- 跨主机容器像同局域网一样用,不用管容器在哪个服务器,直接用IP或容器名访问;
- 网络隔离性好:不同的overlay网络之间互相不干扰,就像不同的WiFi之间互相不影响;
- 支持容器动态迁移:容器换服务器后,网络配置自动生效,不用改代码或配置。
缺点
- 有额外的性能损耗:因为是在真实网络上搭的虚拟网络,相当于多了一层“包装”,访问速度会比同主机慢一点;
- 依赖集群管理工具:单独用Docker很难搞overlay,必须结合Swarm、K8s这类集群工具,对新手不友好;
- 网络配置复杂:如果要自定义网络段、配置防火墙,比普通网络麻烦很多。
注意事项
- 两台服务器之间的防火墙必须开放几个端口:Swarm需要的2377、7946、4789端口,不然集群连不上,overlay网络也用不了;
- overlay网络的容器IP是集群统一分配的,不能手动改,不然会冲突;
- 不要给overlay网络分配太大的IP段,不然会浪费地址。
四、方案二:路由模式——给容器开个“直接通外网的门”
4.1 什么是路由模式?
路由模式的核心逻辑,是给每个容器分配一个和服务器真实网络同网段的IP,相当于给每个容器单独装了个“直连外网的门”。比如服务器的真实IP是192.168.1.10,网段是192.168.1.0/24,那容器的IP就设成192.168.1.200,和服务器在同一个网段。这样容器就像服务器上的一个普通设备,能直接和其他同网段的设备通信,也能直接被外面的设备访问。
4.2 路由模式的具体操作(技术栈:Docker + macvlan)
这里我们用Docker的macvlan网络来实现路由模式,因为macvlan是Docker原生支持的,专门用来给容器分配同网段的IP。环境还是之前的两台服务器:server1(192.168.1.10)、server2(192.168.1.20),真实网络的网段是192.168.1.0/24,网关是192.168.1.1。
第一步:先确认服务器的网卡名。执行命令查网卡:
# 查当前服务器的网卡,一般是eth0或者ens33
ip addr show
假设我们的网卡名是eth0。
第二步:在server1上创建macvlan网络,叫my-macvlan:
# 创建macvlan网络,指定网卡是eth0,网段是192.168.1.0/24,网关是192.168.1.1
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my-macvlan
第三步:在server1上启动一个nginx容器,指定IP是192.168.1.100:
# 启动nginx容器,连到my-macvlan网络,指定IP是192.168.1.100
docker run -d --name nginx2 --network my-macvlan --ip 192.168.1.100 nginx:alpine
第四步:在server2上测试访问。直接在server2的命令行执行:
# 访问nginx2的IP,看能不能通
curl 192.168.1.100
执行后你会发现,能直接访问到nginx的默认页面!因为nginx2的IP和server2在同一个网段,相当于server2直接访问同网段的一个设备。
4.3 路由模式的适用场景、优缺点和注意事项
适用场景
- 容器需要直接被外网访问:比如做一个对外的网站,需要给容器分配一个公网IP(如果服务器有公网IP的话);
- 容器需要和同网段的物理设备通信:比如容器要访问同个局域网里的打印机、摄像头,用路由模式最方便;
- 对性能要求极高的场景:比如实时数据处理,不能接受overlay的性能损耗。
优点
- 没有额外性能损耗:容器直接用真实网络,访问速度和物理设备一样;
- 配置简单:不用搭集群,只要会创建macvlan网络就行;
- 网络直观:容器的IP和服务器同网段,一看就知道怎么访问。
缺点
- 容器的IP需要手动管理:如果多个容器都用同网段的IP,很容易冲突,得自己规划IP段;
- 没有自动解析:不能像overlay那样直接用容器名访问,必须用IP;
- 依赖真实网络的配置:如果真实网络的网关、网段变了,容器的配置也要改;
- 容器不能和自己所在的服务器通信:比如server1上的容器nginx2,不能直接访问server1的IP,因为macvlan的限制,相当于容器和服务器是两个独立的设备,不能直接互相访问。
注意事项
- 给容器分配的IP不能和现有设备的IP冲突:比如不能把容器的IP设成192.168.1.10(server1的IP);
- 必须提前规划好IP段:比如192.168.1.100到192.168.1.200专门给容器用,避免和物理设备冲突;
- 解决容器和自己所在服务器的通信问题:如果需要容器访问自己的服务器,可以在服务器上再创建一个macvlan子接口,或者用另一个网络。
五、两种方案怎么选?给大家举几个实际例子
最后给大家总结一下,遇到不同的场景该选哪种方案:
- 如果你做的是微服务,模块多、部署位置经常变,比如外卖订单系统,选overlay网络;
- 如果你做的是对外的网站,需要直接被外网访问,或者要访问同网段的物理设备,比如监控摄像头,选路由模式;
- 如果你做的是实时数据处理,对性能要求极高,不能接受一点点延迟,选路由模式;
- 如果你要搭K8s集群,统一管理所有容器的网络,选overlay网络(K8s默认用的就是类似overlay的逻辑)。
其实两种方案没有绝对的好坏,只有适不适合。就像你出门,坐高铁(overlay)适合跨城市、人数多的情况,走路(路由模式)适合短距离、对灵活性要求高的情况,选对了才能省力气。
评论
围绕“Docker容器跨主机通信的overlay网络与路由模式,各自适用场景深度拆解”参与讨论