在这里,大家先看下在我们安装docker之后,linux/window会给我们新增一个网docker0的网卡。
主机之间的通信的离不开网卡,在docker容器之中也是一样,我们都知道docker container本质也是基于一个小的linux内核去运行的。因此每个container他也有独立的ip,那么container之间又是如何去通信的呢?
我们先来看一下,首先运行两个tomcat容器
docker run -d --name tomcat01 -p 8081:8080 tomcat-network
docker run -d --name tomcat02 -p 80821:8080 tomcat-network
分别进入容器查看ip信息
docker exec -it tomcat01 ip a
docker exec -it tomcat02 ip a
可以看到每个容器中都存在lo本地网卡以及与外界通信的eth0网卡,我们也能够发现tomcat01与tomcat02之间的eth0是处于同一个网段的,当然他们也就能够互相ping通。我们从外界机器去访问只能通过docker container 映射出来的端口加上docker宿主机器的ip才能去范文,直接访问docker container的ip是没法访问的,那么docker是如何是做的这些呢?
Network Namespace在linux机器上,网络的隔离是通过network namespace来管理的,不同的network namespace是互相隔离的:
- 查看当前机器的network namespace,发现没有,我们来新增一个namespace
ip netns list
ip netns add ns1
- 查看该namespace下网卡的情况
ip netns exec ns1 ip a
我们发现该lo本地网卡处于down的状态,我们来启动一下
ip netns exec ns1 ifup lo
再次查看一下网卡的情况,发现处于UNKNOW状态了
我们按照上面方式再次创建一个ns2
ip netns add ns2
ip netns exec ns2 ifup lo
此时ns1与ns2是以namespace来隔离,具体的模型个人感觉与nacos的命令空间隔离。
此时ns1与ns2如上述图所展示的,在同一个centos下,他们之间通过namespace来进行隔离,那么如何让ns1与ns2之间互通呢?
- Virtual Ethernet Pair veth pair 是一个成对的端口,可以实现上述功能,并且他们之间默认是能够互相访问的。
我们使用它来进行创建
ip link add veth-ns1 type veth peer name veth-ns2
ip link
发现多veth-ns1与veth-ns2
我们再将veth-ns1加入ns1中,将veth-ns2加入ns2中
ip link set veth-ns1 netns ns1
ip link set veth-ns2 netns ns2
完成之后我们在分别查看宿主机、ns1、ns2的link情况
ip link
ip netns exec ns1 ip link
ip netns exec ns2 ip link
我们发现,之前处于宿主机中的veth-ns1与veth-ns2都不存在了,然后在ns1与ns2中都分别多了网卡。
虽然分别多了两个网卡,但是他们并没有绑定ip,显然还没具备通信的能力。我们在分别给他们绑定上ip
ip netns exec ns1 ip addr add 172.25.45.11/24 dev veth-ns1
ip netns exec ns2 ip addr add 172.25.45.12/24 dev veth-ns2
查看
ip netns exec ns1 ip a
ip netns exec ns2 ip a
已经绑定上了ip,发现这两个网卡都是处于down状态。启动网卡
ip netns exec ns1 ip link set veth-ns1 up
ip netns exec ns2 ip link set veth-ns2 up
发现ns1与ns2直接的网络已经通了。
上面我们尝试了在centos中使用network namespace进行了网络隔离,并且使用veth pair进行了网络通信,那么按照上面的描述,实际上每个container都会有自己的network namespace,并且是独立的。
我们首先运行两个container
docker run -d --name tomcat01 -p 8081:8080 tomcat-network
docker run -d --name tomcat02 -p 8082:8080 tomcat-network
docker exec -it tomcat01 ip a
docker exec -it tomcat02 ip a
也可以尝试一下,他们也是可以互相ping通的。
查看ceontos 的网络 ip a,可以发现
我们可以发现在centos中是可以ping通container中的tomcat的网络的,既然可以ping通,那么centos与tomcat又属于不同的network namespace,是怎么连接的,我们看一下图
也就是说,在tomcat01中有一个eth0和docker0中有一个veth是成对的。类似于我们上面创建的ns1与ns2,我们还可以通过一个工具类确认一下。 安装brctl
yum install bridge-utils
brctl show
其实可以认为vethxxx@if394、vethxxx@if396.然后container中存在if395、if397可以理解为是根据这个序号成对的。那么为什么tomcat01与tomca02直接可以访问呢。直接看图
这种网络模式我们称为Bridge,其实也可以通过命令查看docker中的网络模式:
docker network ls
关于这块docker官网中也有对应说明,bridge也是docker中默认的网络模式。
我们来查看一下docker中的bridge
docker network inspect bridge
可以看到bridge中存在两个container,在tomcat01容器中是可以访问互联网的。NAT是通过ptagbles实现的。
在docker中,我们也是可以自定义自己的网络的。这种情况适用于搭建某一类的集群的时候,例如:redis集群(172.18.0.1,xxxxx)、mysql集群(172.19.0.1,xxxx)
- 创建自己的网络
docker network inspect tomcat-net
也可以自定义网段
docker network create --subnet=172.18.0.0/24 tomcat-net
- 查看网段
docker network inspect tomcat-net
现在多出了一个我们自己的网段。
我们再来创建toncat容器,并且指定使用network-net
docker run -d --name net-tomcat01 --network tomcat-net tomcat-network
看下一下网络信息 我们在net-tomcat01中ping一下之前创建的tomcat01看看是否能够ping通。
发现ping不同。
如果此时,tomcat01能够连接上tomcat-net的话,那么应该就可以解决这个问题了。
连接尝试:
docker network connect tomcat-net tomcat01
我们在查看一下tomcat-net的网络
发现tomcat01也在里面了。
我们在来ping一下
docker exec -it faa90a3043ac ping 172.19.0.3
docker exec -it faa90a3043ac ping tomcat01
发现不仅可以通过ip访问,也能够通过名字访问。但是无法访问tomcat02的,也可以通过上述方式进行网络连接。