docker的网络模式,了解docker的网络模式对docker通信尤为重要。
(一)网络模式介绍
查看显示的三种网络模式,其实还有一种是容器模式。一共4种
docker network ls
bridge模式:使用–net =bridge指定,默认设置;
host模式:使用–net =host指定;
none模式:使用–net =none指定;
container模式:使用–net =container:NAMEorID指定。
(二)bridge模式(docker默认的网络模式)
①介绍
在默认情况下,docker 会在 host 机器上新创建一个 docker0 的 bridge:可以把它想象成一个虚拟的交换机,所有的容器都是连到这台交换机上面的。docker 会从私有网络中选择一段地址来管理容器,比如 172.17.0.1/16,这个地址根据你之前的网络情况而有所不同。
sudo yum install net-toolsifconfig -a
②数据流程
容器内部发送一条报文,查看路由规则,默认转发到 172.17.0.1(如果是同一个网段,会直接把源地址标记为 172.17.0.2 进行发送)
通过 eth0 发送的报文,会在 vethXXX 被接收,因为它直接连在 docker0 上,所以默认路由到 docker0
这个时候报文已经来到了主机上,查询主机的路由表,发现报文应该通过 eth0 从默认网关发送出去,那么报文就被转发给 eth0(就是前面提到的要打开 linux 系统的自动转发配置)
匹配机器上的 iptables,发现有一条 -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE,也就是 SNAT 规则,那么 linux 内核会修改 ip 源地址为 eth0 的地址,维护一条 NAT 规则记录,然后把报文转发出去。(也就是说对于外部来说,报文是从主机 eth0 发送出去的,无法感知容器的存在)
③流程演示方便理解
启动两个容器
docker run --name a1 -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done"docker run --name a2 -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done"
容器互相通信
docker exec -it a1 /bin/sh ifconfig#查看到a1的ip是172.17.0.2exitdocker exec -it a2 /bin/sh ifconfig#查看到a2的ip是172.17.0.3#在a2容器内可以ping通172.17.0.2ping 172.17.0.2#在a1容器内尝试ping下a2的ip 172.17.0.3#在a1容器内可以ping通172.17.0.2ping 172.17.0.3
记录ip太麻烦了,可以通过link的方式直接让容器包含起来
这样只是单向的,还需要删除a1,重新创建才能添加link a2,
docker run --name a2 --link a1 -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done"docker exec -it a2 /bin/shping a1
④自定义网络
但是建议大家不要使用link的方式,如果容器千千万都link,人就受不了了。还是自定网络比较靠谱。下面说说自定义网络
docker network create -d bridge net-test
测试网络通信,创建容器,进行通信
不需要ip的方式两个容器都是通的。自定义网络牛Xclass
docker run --name test3 --network net-test -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done"docker run --name test4 --network net-test -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done"docker exec -it test3 /bin/shping test4exitdocker exec -it test4 /bin/shping test3exit
自定义网络的IP段看下。172.18网段。
docker network inspect net-test
container 里面包括test3 和test4
(三)host模式(共享主机的网络模式)
docker 不会为容器创建单独的网络 namespace,而是共享主机的 network namespace,也就是说:容器可以直接访问主机上所有的网络信息。在实际微服务的环境中不建议使用这种。
#network 更换成host docker run --name test5_host --network host -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done" docker exec -it test5_host /bin/shifconfig
跟宿主机是一样的
直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。Docker host 的另一个用途是让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理 iptables。容器中,对这些设备有全部的访问权限。因此docker提示我们,这种方式是不安全的。如果在隔离良好的环境中(比如租户的虚拟机中)使用这种方式,问题不大。
(四)none模式(空网络模式)
这种none的也就自己通过exec的方式访问。
docker run --name test7_none --network none -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done" docker exec -it test7_none /bin/shifconfig
其实还真有应用场景。封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用 none 网络。比如某个容器的唯一用途是生成密码,就可以放到 none 网络中避免密码被窃取。
(四)container 模式(容器之前的共享模式,学习k8s这个很重要)
一个容器直接使用另外一个已经存在容器的网络配置:ip 信息和网络端口等所有网络相关的信息都是共享的。需要注意的是:这两个容器的计算和存储资源还是隔离的。
# test7_container 依赖a1的网络模式 docker run --name test7_container --network container:a1 -d busybox /bin/sh -c "while true;do echo hello docker;sleep 10;done" # 分别进入test7_container 和a1查看ifconfig 发现两个是一样的docker exec -it test7_container /bin/shifconfigexitdocker exec -it a1 /bin/shifconfigexit
kubernetes 的 pod 就是用这个实现的,同一个 pod 中的容器共享一个 network namespace。