一、计算机网络模型
我们都知道计算机网络模型细分可以分为七层网络模型(自上而下):应用层、表示层、会话层、传输层、网络层、数据链路层、物理层,当然也可根据不同的标准分为三层、四层、五层等等。
我们这里不讲网络模型的细节,只是大致讲一下两台机器通信的大致流程:A与B想要通信,则A的数据从应用层一路传输到物理层,每次经过一次包装,然后通过A的物理层的网卡把数据包传输到B物理层的网卡上,B接收到数据包以后一步步向上解密然后把解密后的信息传输到应用层。
二、Linux中网卡
上面大致讲了两台电脑想要通信的基本流程,有个大致理解就行了,想要了解每一步具体细节的小伙伴可以专门找网络方面的知识好好看一下,这里就不细说网络方面的内容。
既然是讲Docker的网络,那么我们可以就先了解一下Linux网络相关的东西,因为我们Docker项目基本都是部署在服务器上的,一般都是Linux系统。
上面我们说了,两台机器的数据传输是通过网卡发送给对方,那么我们就要着重说一下Linux的网卡。
(一)命令
以下三个命令都能看到Linux机器上的网卡信息:
ip link show
ls /sys/class/net
ip a
可以看出来我有四个网卡,docker0,eth0,lo,vethfcea4a9@if8。
lo是本地网卡,eth0是机器跟互联网打交道的网卡,docker0是安装docker时docker自己创建的网卡。
(二)网卡信息解读
上面我们通过命令展示了网卡的信息,那我们可以通过以下信息了解其中参数的大致意思。
1、参数解读
state后面代表网卡的状态,分别有UP/DOWM/UNKOWN等;
link/ether后面代表的是MAC地址;
inet后代代表的是网卡绑定的ip地址,网卡本身并没有通信能力,绑定了ip地址才能进行通信。
2、配置文件
Linux中网卡对应的其实就是文件,存储在机器上的:/etc/sysconfig/network-scripts/目录下
3、给网卡增加ip地址
我们可以直接修改网卡的文件来完成对网卡的修改,例如我们可以跟网卡加上临时ip,这样其就能访问某一个网段的ip了。
ip addr add xxx.xxx.xxx.xxx/xx dev eth0 :给网卡eth0增加一个ip
ip addr delete xxx.xxx.xxx.xxx/xx dev eth0 :删除网卡eth0绑定的ip
4、网卡的启动和关闭
重启网卡:service network restart 或者 systemctl restart network
启动/关闭某个网卡:ifup/ipdown eth0 或者 ip link set eth0 up/down
三、Network Namespace
在Linux上网路的隔离是同network namespace来管理的,不同的network namespace是相互隔离的
ip netns list:查看所有的network namespace
ip netns add ns1:添加一个名为ns1的network namespace
ip netns delete ns1:删除一个名为ns1的network namespace
(一)namespace通信
1、创建两个namespace
ip netns add ns1:
ip netns exec ns1 ip a:查看ns1下网卡的信息
ip netns exec ns1 ifup lo或者ip netns exec ns1 ip link set lo up :启动本地lo网卡
可以发现ns1下的lo本地网卡已经从DOWN变成了UNKNOWN。
同样的命令创建一个namespace ns2
2、创建成对的网卡分别绑定对应的namespace
目前已经创建了两个namespace分别为ns1和ns2,如何让两个namespace通信呢?
现有的一个技术叫做veth pair:Virtual Ethernet Pair,会生成一个成对的网卡,这两个网卡是默认可通信。
接下来就是通过veth pair创建一对网卡veth-ns1和veth-ns2
ip link add veth-ns1 type veth peer name veth-ns2
再运行ip link
查看目前已经有的网卡,可以看到已经生成了两个网卡
再将veth-ns1加入到ns1中,将veth-ns2加入到ns2中
ip link set veth-ns1 netns ns1
ip link set veth-ns2 netns ns2
再运行一下命令查看主机和ns1、ns2上的网卡的情况
ip link
ip netns exec ns1 ip link
ip netns exec ns2 ip link
可以看到宿主机新创建的两个网卡已经消失不见了,分别绑定到了ns1和ns2上了。
虽然ns1和ns2已经绑定了veth-ns1和veth-ns2,但是veth-ns1和veth-ns2并没有ip地址,还是无法通信,我们手动给veth-ns1和veth-ns2绑定ip。
3、给新创建的网卡绑定ip并启动
ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2
注意:给两者绑定的ip必须是同一个网段的才能通信
然后再查看一下网卡信息,发现两个namespace对应的新网卡处于DOWN的情况:
ip netns exec ns1 ip a
ip netns exec ns2 ip a
启动两个命名空间下的新网卡:
ip netns exec ns1 ip link set veth-ns1 up
ip netns exec ns2 ip link set veth-ns2 up
然后再用上面的命令可以看到状态已经变成UP了,再在ns1上ping ns2上veth-ns2绑定的ip:192.168.0.12,再在ns2上ping ns1上veth-ns1绑定的ip:192.168.0.11,可以发现均可以ping通。
ip netns exec ns1 ping 192.168.0.12
ip netns exec ns2 ping 192.168.0.11
四、container网络-Bridge
(一)何为Bridge网络桥接
为了研究桥接网络,我们先用tomcat镜像启动两个tomcat容器,tomcat01和tomcat02,分别映射到主机8088和8089端口。
docker run -d --name tomcat01 -p 8088:8080 tomcat
docker run -d --name tomcat02 -p 8089:8080 tomcat
然后查看一下:docker ps -a,可以发现已经成功启动。
然后去tomcat01中运行ip a查看其互联网网卡绑定的ip是172.18.0.3
然后再去tomcat02中查看其互联网网卡绑定的ip为172.18.0.4
然后在tomcat01中ping tomcat02的ip发现能ping通,tomcat02中ping tomcat01的ip发现也能ping通。
其实tomcat01和tomcat02是两个不同的namespace,但是他们两个却能通信,这就是桥接网络。
(二)深入分析Bridge网络桥接
其实tomcat01和tomcat02不可能无缘无故的能通信,而且二者处于不同的namespace,也不会是直接通信的。通过上面的分析我们能知道,veth pair能生成成对的网卡以便两者通信。那么这个也是同一个道理,tomcat01会和虚拟机上的docker0生成成对的网卡,tomcat02也会和虚拟机上的docker0生成成对的网卡,两者是通过docker0作为中间桥梁进行通信,所以称为桥接。大致图如下:
为了验证我们的猜想,我们可以工具来协助我们。
在我们的虚拟机上安装:yum install bridge-utils
,然后再运行brctl show
命令,可以看到docker0绑定了两个网卡,veth0952dba,vethffb79fe
然后我们在主机上运行ip a,可以看到除了之前出现的网卡还出现了上面两个网卡,veth0952dba对应@if8,vethffb79fe对应@if20。
然后我们分别进入tomcat01和tomcat02,然后查看其网卡信息,会发现tomcat01里有个eth0@if19,tomcat02里有个eth0@if21。那就很明显了,18对应19,20对应21。
Bridge桥接是docker网络中的默认网络模式。
我们可以再运行:docker network inspect bridge
查看一下bridge详情
可以看到已经把tomcat01和tomcat02桥接了起来。
五、container网络-Host&None
(一)Host网络
host网络就是用宿主机的ip对外
我们可以创建一个新的tomcat容器,名字为my-tomcat-host,然后指定使用host网络模式,然后查看其ip,会发现跟宿主机ip一样。
然后查看host网络类型的都有哪些,可以看到my-tomcat-host在其中了:
(二)None网络
None网络就是不对外暴露ip,不跟外界进行通信,没有网络。
同理创建一个my-tomcat-none的tomcat容器然后设置其网络类型为none,然后运行ip a查看其网卡信息,会发现其没有对外的网卡eth0,只有一个本地网卡lo。
然后再查询虚拟机上的none类型的网络,会发现my-tomcat-none在其中:
六、端口映射
我们用docker启动一个tomcat容器以后可以再容器内部用localhost访问,但是在虚拟机本身上访问该容器只能在容器内拿到容器的ip,然后通过ip加端口访问。如果我们想在虚拟机上直接通过localhost访问已经启动的容器呢?那只能通过端口映射,将容器的端口映射到虚拟机本身的端口,然后再运行localhost访问。
1、创建一个tomcat容器名字为port-tomcat
docker run -d --name port-tomcat tomcat
2、直接在port-tomcat内部通过localhost访问
docker exec -it port-tomcat bash
curl loaclhost:8080
3、若想在虚拟机上访问新启动的容器,则必须获取启动容器的ip,然后通过ip+端口访问
docker exec -it port-tomcat ip a:获得新启动容器的ip
然后在虚拟机上通过ip:8080访问
4、若想在虚拟机上通过localhost直接访问呢?先把之前启动的删除然后重启一个tomcat容器端口映射到虚拟机上未使用的端口
docker rm -f port-tomcat
docker run -d --name port-tomcat 8090:8080 tomcat
然后在虚拟机上用localhost直接访问:curl localhost:8090