浅谈docker的几种网络模式

Royal
2022-06-23 / 0 评论 / 486 阅读 / 正在检测是否收录...

最近项目在做安全加固的时候突然遇到一个问题,一共三个板卡,每个板卡上面部署了三套执行体(php,java,python各一套),要求同一个板卡上面的三个执行体的容器彼此之间隔离,不能互相通信,也不能使用ping命令。
解决这个问题之前,我们先了解下docker的网络通信模式有哪些?

  • docker容器的通信模式分类
    通过命令查看docker安装后默认的网络模式列表
docker network ls

l4qeylkr.png
通过打印发现一共包含bridge桥接模式,host主机模式、none三种默认的模式,其实还有另外两种是默认不显示的,需要手动定以后,才能通过docker network ls命令查看才会显示出来!

模式名称简介备注
bridge容器拥有独属于自己的虚拟网卡和和虚拟IP等网络资源,它们分别通过docker0虚拟网卡与宿主机的eth0网卡交互,进而和外界网络交互默认模式
host容器没有自己的任何独立的网络资源(比如:容器的IP、网卡和端口),完全和宿主机共享网络空间弊端:同一个端口只能同时被一个容器服务绑定
none该模式关闭了容器的网络功能,仅有独自的网络空间(一个空架子),并且该模式不会给容器分配任何网络资源,包括虚拟网卡、路由、防火墙、IP、网关、端口等光秃秃的一个容器,没有任何的网络资源,就是自娱自乐的光杆司令(很少用)
container它是bridge和host模式的合体,优先以bridge方式启动启动第一个容器,后面的所有容器启动时,均指定网络模式为container,它们均共享第一个容器的网络资源,除了网络资源,其他资源,容器彼此之间依然是相互隔离的第一个以bridge方式启动的容器服务挂掉,后面依赖它的容器,都暂停服务
自定义该模式也更为灵活,可以通过-d 指定自定义的网络模式的类型,可以是bridge或者overlay,其中overlay功能更为强大,可以指定多个subnet子网网段。该模式,在容器之间使用别名相互通信,有着举足轻重的作用(重要)

通过这个表我们发现,docker的容器的通信模式一共有5种,默认采用的是bridge桥接模式,我们再来看下这5种模式怎么使用。

  • 网络模式的使用方式

docker run 后面添加 --net参数即可。

  1. --net=bridge 采用桥接方式
  2. --net=host 采用主机模式
  3. --net=container 采用容器模式
  4. --net=none 采用独立的无网络模式
  • 该采用哪种模式才能实现容器之间的隔离

我们先来看下目前我们采用的哪种网络模式,通过docker inspect打印容器信息,发现我们容器运行模式位host模式。
l4qfm4zj.png
通过启动命令我们也能发现我们采用了host主机模式

docker run -dit --net=host --privileged=true --restart=always --name=debian_nginx_ci_v1 -e MIMIC_BRACKET_HOST="32.60.90.42" -e MIMIC_BRACKET_PORT="8091" debian_nginx_ci:v1

什么是主机模式呢?
主机模式意味着容器和宿主机共享Network namespace
l4qfobn5.png
从上图可以看出,如果在启动容器后使用的是host模式,那么这个容器将不会获得一个独立的Network Namespace(网络命名空间),而是和宿主机系统共用一个Network Namespace。并且这就意味着容器将不会虚拟出自己的网卡以及配置自己的ip等,而是使用宿主机的ip以及端口。不过呢,在其他方面例如文件系统等还是与之隔离的。

  1. 这种方式最大优势在于网络性能比较好,网络传输速率高。
  2. 但是缺点也很明显——网络的隔离性很弱。而且这种host模式还有个最大的劣势就是容器的端口不能重复占用,一旦宿主机上某个端口被占用,那么容器就不能在使用。比如宿主机上有个nginx占用了80,那么容器的nginx就不能在使用80端口了。

因此这种方式是无法实现我们开篇说的容器彼此之间隔离,不能互相通信,也不能使用ping命令的需求。
我们再来看下container模式满足么?
它是bridge和host模式的合体,优先以bridge方式启动启动第一个容器,后面的所有容器启动时,均指定网络模式为container,它们均共享第一个容器的网络资源, 除了网络资源 ,其他资源,容器彼此之间依然是相互隔离的
很显然这种方式也不行!!
那么只剩下最后一种bridge模式了
什么是bridge模式?
l4qnhwc2.png
该模式就是我们在启动docker服务后默认的docker网络模式,其会在主机上创建一个名为docker0的虚拟网桥,这个主机上的所有启动的容器就会连接到这个虚拟网桥上。
l4qnle1t.png

docker0和自定义网络肯定不通,我们是使用自定义网络的好处就是网络隔离:

  • bridge模式的使用
    我们先通过自定义创建网络的方式,创建一个php的网络,指定子网、IP地址范围、网关等网络配置

    docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 php

    通过docker network ls查看是否创建成功
    l4qmhyeu.png
    可以看到多了一个php的网络,查看自定义网络细节

    docker network inspect php

    l4qmjr5k.png

注:如果创建网络时候报以下错误,是因为docker服务启动之后开启了防火墙需要重启docker服务

systemctl restart firewalld.service

l4qmmea7.png

然后我们再用同样的方法创建一个python服务的网络
l4qmvea0.png

如果在创建的过程中报Error response from daemon: Pool overlaps with other one on this address space 说明网段被占用,换一个网段即可。

l4qmxe6h.png
然后分别启动php的容器和python的容器并指定到对应的网络

docker run -dit --net=php --privileged=true --restart=always --name=ubuntu_apache_ci_v1 -e MIMIC_BRACKET_HOST="33.60.90.43" -e MIMIC_BRACKET_PORT="8091" ubuntu_apache_ci:v1

docker run -dit --restart=always --net=python --privileged=true --name=cm_ca_env cm_ca_env:v1

我们先进入php的服务容器中拿到对应的ip地址如下:
l4qn40h1.png
可以看到php的容器的ip地址为192.168.0.2/16
再进入到python的服务容器中,通过curl方式和ping的方式来请求php的服务发现都是不通的。
l4qn7dtx.png
我们再来验证下,同一网络内的容器是否互通呢?
l4qna9n9.png
我们把python的服务删掉,然后重新启动使用php的网络。进入到容器中再试下结果:
l4qncax9.png
l4qndqpz.png

  • 总结
    可以看到,在python的容器中不管是连接php的服务还是自己容器内的服务都是想通的,因此得出结论,如果需要保证同一宿主机上的容器彼此服务隔离必须采用bridge的模式,并且不能使用同一自定义网络(同一网段)。
    Docker网络bridge桥接模式,是创建和运行容器时默认模式。这种模式会为每个容器分配一个独立的网卡,桥接到默认或指定的bridge上,同一个Bridge下的容器下可以互相通信的。我们也可以创建自定义bridge以满足个性化的网络需求,保证了一个容器代码被篡改,不会波及到其他服务。
  • 解决bridge模式下外网访问问题
    我们先来看下bridge模式下的一些特性:
  • docker run 命令不带--net参数时,默认就是桥接模式。
  • 桥接模式下容器的虚拟IP,容器内部彼此之间可以访问,非宿主机的其他其他主机无法直接访问容器内部的服务。
  • 桥接模式下,虽然外界主机不能直接访问宿主机容器内部的服务,但是可以通过间接方式访问宿主机docker run -p时,对外暴露的映射端口。
    因此使用-p 宿主机端口:容器端口映射的方式,通过访问宿主机端口而不能直接访问容器端口的形式来访问!
0

评论

博主关闭了当前页面的评论