docker现在已经是一门很火的工具,在很多大型公司里面已经广泛使用。
docker和虚拟机不一样,虚拟机是硬件的虚拟化,通过Hypervisor实现对资源的完全隔离。
但docker是操作系统的隔离,属于软件隔离利用的内核的Cgroup和Namespace特性来实现的。
既然docker也是有隔离的,那么你们知道docker的网络隔离有哪些吗?
什么是网络??
如果用过虚拟机同学,一定有了解过Nat和网桥模型,也可以叫网桥模型。同样的docker其实也提供了4种网络模型,分别为brifge模式,host模式,container模式,none模式.
brifge模式
brifge模式网络模式是docker默认的网络模型,这种模型其实和我们的网桥模型是差不多的。当Docker进程启动的时候,会在宿主主机上创建一个docker0的虚拟网桥,此主机上启动的docker容器会连接到这虚拟网桥上。docker0虚拟网桥就类似我们家庭见到最多的wifi(高端一点的话我们叫交换机)。这样主机上的所有容器都可以通过docker0虚拟网桥连接了一个二层网络中。
docker运行的时候就会从docker0分配一个ip,并设置docker0的IP地址为容器默认的网关。在主机创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。
使用
$ docker run --name [ContainerName] -d --net=bridge [ImageName]
Host模式
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
说明白一点就是,容器的IP地址和宿主主机的IP地址一样,如果你不想一台服务器上运行多个服务,或者一台主机上做一个高可用的redis集群。那么Host是一种很偷懒的方式,你容器里面的配置ip都可以直接写宿主主机的ip
可以简单看看这种模式的运行图
$ docker run --name [ContainerName] -d --net=host [ImageName]
Container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
Container原意就是容器的意思,也就是说容器共享网络,另一个容器可以填写127.0.0.1/localhost来访问到其他容器的服务,如果你本地开发后交付的时候,运维连配置都不愿意改,你也不想改的情况下,可以考虑这种模式,毕竟国内的人嘛,不像外国享受过程,这里的人只看结果,管你是死是活。只要不是我弄的,出事就找你。应付中小企业用docker 和 k8s的企业运维,可以这么搞。
简单看看效果较好
$ docker run --name [ContainerName] -d --net=container:[ContainerId/ContainerName] [ImageName]
None模式
None很明显啦,就是无网模式咯,一般都不用。因为需要自己配置网络。他和前面有一样的共同点就是会分配自己的Network Namespace,但就是没有给你配置网卡,ip等信息...。完全没到这模式出来的是为了解决什么场景的,有知道的可以在评论区回复告诉小编喔。
最后我们还是要看看他的示意图
$ docker run --name [ContainerName] -d --net=name [ImageName]
说说可能是面试的加分项。
那么接下来得说说docker是怎么跨主机通信的,因为在默认的情况下,docker的网络模式,单台主机上的Docker容器可以通过docker0网桥直接通信,而不同主机上的Docker容器之间只能通过在主机上做端口映射进行通信。这种端口映射方式对很多集群应用来说极不方便。如果能让Docker容器之间直接使用自己的IP地址进行通信,会解决很多问题。按实现原理可分别直接路由方式、桥接方式(如pipework)、Overlay隧道方式(如flannel、ovs+gre)等。
上面的不便就是要管理多个端口,然后就有人提出了Pipework工具,这个工具是简单的docker网络配置工具,通过使用ip、brctl、ovs-vsctl等命令来为Docker容器配置自定义的网桥、网卡、路由等。
- 使用新建的bri0网桥代替缺省的docker0网桥
- bri0网桥与缺省的docker0网桥的区别:bri0和主机eth0之间是veth pair
也就是在所有的主机前在加一层LAN来管理,你可以理解成服务发现与治理就好了。
说到服务发现与治理,那么golang里面有一个好用的方案,那就是etcd。如果想用etcd的话好想有一个方案是Flannel。大概的流程如下。
- 每个主机上安装并运行etcd和flannel;
- 在etcd中规划配置所有主机的docker0子网范围;
- 每个主机上的flanneld根据etcd中的配置,为本主机的docker0分配子网,保证所有主机上的docker0网段不重复,并将结果(即本主机上的docker0子网信息和本主机IP的对应关系)存入etcd库中,这样etcd库中就保存了所有主机上的docker子网信息和本主机IP的对应关系;
- 当需要与其他主机上的容器进行通信时,查找etcd数据库,找到目的容器的子网所对应的outip(目的宿主机的IP);
- 将原始数据包封装在VXLAN或UDP数据包中,IP层以outip为目的IP进行封装;
- 由于目的IP是宿主机IP,因此路由是可达的;
- VXLAN或UDP数据包到达目的宿主机解封装,解出原始数据包,最终到达目的容器。
还有什么说的不足的话,可以评论区,告诉傻梦傻喔