为什么不同命名空间的docker容器可以相互通信?
一、什么是容器网络栈
所谓容器能看见的“网络栈”,被隔离在自己的Network Namespace当中
- 网卡(network interface)
- 回环设备(loopback device)
- 路由表(Routing Table)
- iptables规则
当然 ,容器可以直接声明使用宿主机的网络栈:-net=host(不开启Network Namespace),这样可以为容器提供良好的网络性能,但是也引入了共享网络资源的问题,比如端口冲突。
大多数情况下,我们希望容器能使用自己的网络栈,拥有属于自己的IP和端口
二、容器如何和其他不同Network Namespace的容器交互 ?
- 将容器看做一台主机,两台主机通信直接的办法,就是用一根网线连接,如果是多台主机之间通信,就需要用网络将它们连接到一台交换机上
- 在linux中,能够起到虚拟交换机作用的设备是网桥(Bridge)
网桥是一个工作在数据链路层的设备,功能是根据MAC地址学习来将数据包转发到网桥不同端口上,为了实现上述上的,Docker项目默认在宿主机上创建了一个docker0的网桥,连接在上面的容器,可以通过它来通信
三、如何把容器连接到docker0网络上
需要一种叫Veth Pair的虚拟设备。当Veth Pair被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现 ,而且从其中一个网卡出的数据包,可以直接出现在它对应的另一张网卡上,即使两张卡在不同的Network Namespace里
这就使Veth Pair常常被用作连接不同的Network Namspace的网线
四、示例演示
下面将在宿主机启动两个容器,分别是nginx-1和nginx-2演示,nginx-1容器访问nginx-2是如何通信的
1. 运行一个nginx-1容器
docker run -d --name=nginx-1 nginx
2.查看nginx-1的网络设备
root@d5bfaab9222e:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.2 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:ac:12:00:02 txqueuelen 0 (Ethernet)
RX packets 3520 bytes 8701343 (8.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3010 bytes 210777 (205.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0的网卡,是Veth Pari设备的其中一端
3.查看nginx-1的路由表,通过route命令查看
root@d5bfaab9222e:/# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.18.0.1 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
所有172.18.0.0/16网段的请求,都交给eth0处理,这是Veth Pair设备的一端,另一端在宿主机上
4.查看宿主机的网桥
通过brctl show查看
root@VM-0-8-ubuntu:/home/ubuntu# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c635ddb8 no veth4d1c130
可以看到,docker0上插入上veth4d1c130网卡
5.再运行一个nginx-2
docker run -d --name=nginx-2 nginx
6.再查看宿主机网桥
root@VM-0-8-ubuntu:/home/ubuntu# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c635ddb8 no veth4d1c130
vetha9356e9
可以看到,docker0插上了两张网卡veth4d1c130、 vetha9356e9
此时,当容器nginx-1(172.18.0.2)ping容器nginx-2(172.18.0.3)的时候,就会发现两个容器是可以连通的
五、nginx-1能访问nginx-2的原理是什么?
被限制在Network Namespace的容器进程,是通过Veth Pair设备+宿主机网桥的方式,实现跟其它容器的数据交换
1.nginx-1访问nginx-2时,IP地址会匹配到nginx-1容器的每二条路由规则
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
凡是匹配这条规则 的IP包,应该经过本机的eth0网卡,通过二层网络发往目的主机
2.要通过二层网络到达nginx-2 ,需要有172.18.0.3的MAC地址,找到
nginx-1容器需要通过eth0网卡发送一个ARP广播,通过IP来查看对应的MAC地址
这个eth0网卡,是一个Veth Pair,它的一端在nginx-1容器的Network Namespace,另一端位于宿主机上(Host Namespace),并且插入在了宿主机的docker0网桥上
一旦虚假网卡(veth4d1c130)被插在网桥(docker0)上,调用网络的数据包会被转发给对应的网桥,所以ARC请求会被发给docker0
3.docker0转发数据到到相应的nginx-2
docker0会继续扮演二层交换机的角色,根据数据包的上的MAC地址(nginx-2的MAC地址),在它的CAM表里查对应的端口,会找到vetha9356e9,然后将数据包发往这个端口,这样数据包就到了nginx-2容器的Network Namespace里
nginx-2看到它自己的eth0网卡上出现了流入的数据包,然后对请求进行处理,再返回响应给nginx-1
可以打开iptables的TRACE功能查看数据包的传输过程,通过tail -f /var/log/syslog
# iptables -t raw -A OUTPUT -p icmp -j TRACE
# iptables -t raw -A PREROUTING -p icmp -j TRACE
原理图如下

为什么不同命名空间的docker容器可以相互通信?的更多相关文章
- Docker容器跨主机通信之:直接路由方式
一.Docker网络基本原理 直观上看,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)与外界相通,并可以收发数据包:此外,如果不同子网之间要进行通信,需要额外的路由机制. Docker ...
- Docker容器跨主机通信
默认情况下Docker容器需要跨主机通信两个主机节点都需要在同一个网段下,这时只要两个Docker容器的宿主机能相互通信并且该容器使用net网络模式,改实现方式为网桥模式通信: 除此之外我们还可以通过 ...
- docker容器内外相互拷贝数据
从宿主机上拷贝文件到容器内 注意:一下红色字体为宿主机文件 docker cp 文件 容器名:目录 # docker cp httpd-2.4.34.tar.gz node4:/opt/ 从宿主机上拷 ...
- Docker容器跨主机通信--overlay网络
一.Docker主机间容器通信的解决方案 Docker网络驱动 Overlay: 基于VXLAN封装实现Docker原生Overlay网络 Macvlan: Docker主机网卡接口逻辑上分为多个子接 ...
- Docker容器跨主机通信之:OVS+GRE
一.概述 由于docker自身还未支持跨主机容器通信,需要借助docker网络开源解决方案 OVS OpenVSwich即开放式虚拟交换机实现,简称OVS,OVS在云计算领域应用广泛,值得我们去学习使 ...
- docker容器之间的通信
容器之间互通 新建两个容器 docker run -d --name box1 busybox /bin/sh -c "while true;do sleep 3600;done" ...
- docker images之间相互通信 link
同一个host上的两个container 首先启动一个nginx. container起名叫netease_nginx docker run --detach --name netease_nginx ...
- Docker: Docker容器之间互相通信
最简单的方法,关闭防火墙(只建议用于开发环境) systemctl stop firewalld
- Docker容器学习梳理 - 容器间网络通信设置(Pipework和Open vSwitch)
自从Docker容器出现以来,容器的网络通信就一直是被关注的焦点,也是生产环境的迫切需求.容器的网络通信又可以分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信.下面将分别针对这两方面,对容 ...
随机推荐
- change,Ringo题目
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- SqlServer 2014 Enterprise 企业版安装程序下载与安装教程
场景 SqlServer2014 企业版比标准版 多一些功能,比如在企业版中能使用分区函数,但是在标准版Express 中就不能使用. SqlServer 2014 企业版安装包下载: 关注公众号: ...
- Hive函数大全-完整版
现在虽然有很多SQL ON Hadoop的解决方案,像Spark SQL.Impala.Presto等等,但就目前来看,在基于Hadoop的大数据分析平台.数据仓库中,Hive仍然是不可替代的角色.尽 ...
- Elastic Stack 笔记(三)Kibana5.6 安装
博客地址:http://www.moonxy.com 一.前言 Kibana 是 Elastic Stack 公司推出的一个针对 Elasticsearch 的开源分析及可视化平台,可以搜索.查看存放 ...
- JDBC连接时出现的问题总结
java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more tha ...
- SpringBoot的注解注入功能移植到.Net平台(开源)
*:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...
- [Linux] CentOS安装GNOME时,fwupdate-efi-12-5.el7.centos.x86_64 conflicts with grub2-common-1:2.02-0.65.el7.centos.noarch
参考文章:https://createdpro.com/a/100006 该问题源于文件的版本冲突: grub2-common包的冲突,所以要将该包使用yum update grub2-commonn ...
- Mybatis源码解析,一步一步从浅入深(七):执行查询
一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...
- JQuery学习笔记之手网琴效果
这种东西在网上多的是,最近在学JQuery,所以就写了个随笔 <!DOCTYPE html> <html lang="en"> <head> & ...
- 【面试必备】小伙伴栽在了JVM的内存分配策略。。。
周末有小伙伴留言说上周面试时被问到内存分配策略的问题,但回答的不够理想,小伙伴说之前公号里看过这一块的文章的,当时看时很清楚,也知道各个策略是干嘛的,但面试时脑子里清楚,心里很明白,但嘴里就是说不清楚 ...