docker中的网络
众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。
一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace
在Docker安装时,他会自动创建三个网络,bridge(类似桥接)、None(无网络)、host(类似NAT)


Bridge模式
容器的默认网络模式,在docker安装的时候会自动创建一个名为docker0的Linux Bridge网络,在不指定网络模式从情况下,创建的容器都会默认挂到这个docker0网络上。

容器间通信测试
在这种情况下,因为它们在同一个网络上,所以这些容器能够互相的访问。(很好理解,参考vmware的桥接模式)

宿主机也是在这个网络内的,它默认的ip为172.17.0.1

容器向外通信测试
Q:前面讲了,这里的网卡是一张虚拟网卡,那么容器是如何向外界通信的呢?
A:这里为了实现跨网络的隔离和通信,docker借助了iptables的机制。
为了实现内部容器访问外界的需求,docker在FORAWRD链中加入了自己的规则,从而实现bridge网络之间的隔离和通信。


bridge模式做隔离
在这种模式下,我们改怎么做隔离呢?一种简单粗暴的办法就是
在ExecStart参数(在docker.service中修改)中设置–icc=false,但这种情况下会导致所有的容器间都无法互相访问,只有使用–link才能使两个容器互相通信。(结果:容器之间隔离,能够访问宿主机和外网)
在宿主机中查看docker状态,找到配置文件的路径。



此时发现无法访问其他容器(仍能访问宿主机)。但仍然能够正常访问外部网络。

但如果我们只想要一部分的容器不能和另一部分的容器交换的话,用上述方法就不太现实了。因此另一种方法则是使用命名空间。虽然两个容器都使用了网桥模式,但只要它们的命名空间不相同就可以实现隔离。
(结果:不同命名空间的容器无法互相访问,其他没变化)
在这里,我们创建了两个net空间(就相当于创建了其他虚拟网卡)
然后只需要把容器给加进去就自然形成隔离了。

在创建容器的时候选择网络即可。

Host模式

host模式类似于VMWARE中的NAT模式,在这种模式下,容器没有自己的IP,它会直接使用宿主机的网络命名空间。
在这种情况下,容器中和宿主机的所有网络相关的应用全都是共享的,就跟跑在宿主机上一样。但是文件系统和进程列表等还是隔离的,
这种模式下,就相当于容器和宿主机没有了隔离(仅限于网络),因此容器和宿主机会竞争网络的使用情况,比如,你宿主机占用了80端口,容器就不能占用。容器的崩溃也可能会导致宿主机的崩溃。
但它有有着相应的优势,从它的构造就可以看出,在整个网络请求过程中,无需进行NAT转换,而且也不需要通过linux bridge的转发。也就是说性能上比较占优。
网络测试
下图是在容器中执行的命令,我们可以看到在容器中是和宿主机公用一个网络空间,能够访问宿主机访问到的所有资源。

这里是在宿主机上执行的操作,我们尝试在宿主机kill到容器的监听端口80服务,发现容器直接死了(容器依靠这个服务)

Container模式

前面讲了host模式是让当前创建的容器和宿主机共享一个网络命名空间。而这种情况下往往是不安全的,存在逃逸的风险。
而Container模式就是使用其他容器的命名空间,可以指定创建的容器和已经存在的一个容器共享网络命名空间。也就是说,两个容器共享ip、端口范围、host等等。
在这种情况下,在做跨容器的网络数据传输的时候,可以通过localhost来完成,一方面极大的加快了网络传输效率,另一方面也减少了网络链路的流量。

None模式
这个模式下容器有独立的网络命名空间,但没有任何的网络配置,只有一张loopback环回网卡用于进程通信。
可以说是一张白纸,在这种情况下,我们可以为它进行任意配置,从而满足我们的网络拓扑要求。
可以看到,创建出来的容器没有任何网络。可以说它将网络创建的责任完全交给用户,因此可以实现更加灵活复杂的网络。

Overlay模式(跨主机)
主机间的网络通信只能经由主机上可对外通信的网络接口进行,跨主机在数据链路层直接连接虚拟网桥的需求必然难以实现,也就是说上述的网络模式除了host模式(但是它不安全)外都做不到跨主机的通信。除非借助宿主机间的通信网络构建的通信“隧道”进行数据帧转发
Overlay网络模式,在多个docker daemon 主机之间穿件一个分布式的网络,该网络(overlay)位于docker主机层次之上,允许容器(同一集群服务的容器)之间加密通讯。也就是说Overlay模式是用来解决容器在跨主机的情况下的通信问题的。
使用overlay模式的网络会虚拟出一个网络比如10.0.9.3这个ip地址,在这个overlay网络模式里面,有一个类似于服务网关的地址,然后把这个包转发到物理服务器这个地址,最终通过路由和交换,到达另一个服务器的ip地址。
要实现overlay网络,我们会有一个服务发现。比如说consul,会定义一个ip地址池,比如10.0.2.0/24之类的。上面会有容器,容器的ip地址会从上面去获取。获取完了后,会通过ens33来进行通信,这样就实现跨主机的通信。
使用 overlay 网络需要满足下面的这些条件:
- 正常工作的 key-value 存储服务,比如 consul、etcd、zookeeper 等(服务注册发现)
- 可以访问到 key-value 服务的主机集群
- 集群中每台机器都安装并运行 docker daemon
- 集群中每台机器的 hostname 都是唯一的,因为 key-value 服务是通过 hostname 标识每台主机的
docker swarm Overlay网络搭建
初始化 swarm 或将 Docker 主机加入现有 swarm 时,会在该 Docker 主机上创建两个新网络:
- 一个名为 的覆盖网络ingress,它处理与 swarm 服务相关的控制和数据流量。当您创建一个 swarm 服务并且不将其连接到用户定义的覆盖网络时,它会ingress 默认连接到该网络。
- 一个名为 的桥接网络docker_gwbridge,它将单个 Docker 守护进程连接到参与 swarm 的其他守护进程。
下面我们利用docker swarm简单创建一个overlay网络,然后测试其连通性。
docker swarm init #初始化docker集群

docker network create -d overlay --subnet=10.10.1.1/24 --attachable test_overlay #创建一个Overlay网络。这里为了防止ip冲突,我给它设置了网段,如果不使用--attachable参数的话,这个网络只能被swarmservice使用(即只能docker server去使用),不能被独立的容器所使用的(不能被docker run使用)。这个时候在其他节点上是看不到我们创建的这个test_overlay网络的,当服务部署在work节点上的时候,才可以看到这个网络。

将不同节点的两个容器加入我们创建的overlay网络,测试联通性、
这里需要使用docker server才能指定节点创建我们的容器,首先给目标节点添加标签属性
docker node update --label-add role=work test2 #给test2这个节点添加work的标签
docker service create --constraint node.labels.role==work --network=test_overlay -d ruyueattention/php:v1PS
,docker service ls && docker service ps
随后在节点test2上可以成功看到创建了一个overlay网络,并且容器也跑了起来。

成功访问跨主机的容器。

非swarm中Overlay网络搭建
如果我们不想用swarm的话,怎么实现呢?
在这种情况下,想要使用overlay网络就得先提前准备好分布式键值数据库,比如etcd、consul、zookeeper等
我们需要借助服务注册发现的软件。这里用的是consul
因为在Linux中,一切皆文件,因此这里原理其实就相当于把docker的网卡配置文件给弄到一个云上,大家共享这个信息。这样就实现了在A创建网卡,B也会同步。(不确定)
部署运行consul服务
https://www.consul.io/downloads

这里让consul服务运行在0.0.0.0上,以让多个docker能够成功访问到它。
consul agent -dev -client 0.0.0.0
随后我们访问目标的8500端口即可成功访问服务。

将consul设置为docker集群存储
所有的宿主机都需要设置
添加docker.service中的ExecStart参数
-H tcp://0.0.0.0
—cluster-store=consul://192.168.2.209 —cluster-advertise=ens33—cluster-store=consul://192.168.2.209
:#docker daemon存储地址指向的key value service地址—cluster-advertise=ens33
:#从本机的ens33网卡通过2376端口收集网络信息,存储在consul上。systemctl daemon-reload
systemctl restart docker

创建overlay网络
现在我们只需要在任意一个宿主机上创建网络,网络就会同步到其他的容器上了。
这里,我们可以看到这个网卡的作用范围为global


测试网络
可以看到,容器内也是存在三张网卡的。

