社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
Docker搭建开发环境用的非常多,通常开发机器上既有容器形式的应用,又有本机跑着或者调试的程序,它们之间互相依赖,如何让它们之间通信顺畅,有时候是一个挺困难的事情。容器应用和容器外应用互相访问分为三种情况:
而根据两个互相通信的容器或应用在不在一台服务器上,我们又多出一个维度的情况:
要想彻底搞清楚互相访问的问题,就需要先弄清楚docker的网络是怎么一回事。为什么网络重要,这么说吧,docker三巨头:服务(容器)、网络 & 存储,作为三巨头之一的网络,还是要多加重视的。
常用的docker网络模式有三种:bridge、host 和 overlay,可能会有人说,“谁说的?还有macVlan和none 好吧 ?” ,注意,我说的是常用 ?,三种模式各有适用场景:
Bridge网络
分为“default bridge”和“user-defined bridge”(自定义bridge),docker安装好后会默认创建一个bridge网络(docker0),也就是“default bridge”,未指定网络的容器会默认使用这个网络。一般使用自定义bridge较多,我们定义一个私有网络,可以将我们的应用与其他应用相隔离,这在一个共享的开发服务器上非常有用,此外,自定义网络也有下面两个优点:
比如有一个容器名称为container-a,我们创建两个bridge网络,不指定driver时默认为bridge:
docker network create bridge-a && docker inspect bridge-a
docker network create bridge-b && docker inspect bridge-b
我们跑一个alpine的基础镜像容器: "docker run --name=container-a -it alpine:2.9.4 sh",然后查看该容器网络:"docker inspect container-a",
container-a使用的默认网段"172.17.0.0/16"不就是docker0的bridge网络的网段么。
将container-a连接到bridge-a网络: docker network connect bridge-a container-a && docker inspect container-a,我们从结果中可以看到,一个docker容器是可以同时使用两个bridge网络的,这个特性就比较有用了,比如我们使用一个数据库容器供多个网络中的应用使用,分别使用不同的数据库。
同时我们可以将某个bridge网络移除: docker network disconnect bridge container-a,就会只剩下bridge-a。
Host网络
host网络比较容易理解,如果指定容器使用host网络模式,容器会使用宿主机的网络,不会相隔离。也就是说,容器暴露的端口会直接映射到宿主机的相同端口。如果容器没有暴露端口,那么指定不指定host是没啥效果的。
Overlay网络
overlay网络用于docker自带的集群模式(docker swarm),如果没有使用swarm,创建overlay网络会报错:
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
相较于docker swarm,使用kubernetes的较多,工作中也是使用kubernetes,overlay网络相当于kubernetes中flannel创建的联通各个node的网络,这里就不多介绍overlay网络了。
如果不想那么复杂,但又想不同机器上容器或应用互相访问,可以使用extra_hosts来解决,下面我们会谈到。
1、容器或应用在一台宿主机上
1.1 容器A访问容器B
这种情况最好使用自定义到bridge网络,上面也提到了,自定义到bridge网络自带“容器名 => 容器IP”的解析能力,因此在容器A要想访问容器B,直接使用容器名称即可。用例子证明一下,我们使用alpine基础镜像起两个容器,都使用默认的bridge网络,即不指定网络即可,检查两个容器是否可以通过容器名互通,然后加入一个自定义的bridge网络,再验证两个容器是否可以通过容器名称互通。
docker run -itd --name=container_a alpine:3.9.4
docker run -itd --name=container_b alpine:3.9.4
得到两个容器
我们进入容器a,看是否可以通过容器名访问容器b:
并不能,那我们新建一个bridge网络,并将两个容器加入这个网络:
访问成功!如果你在一台机器上开发,应用都是在容器内的,可以将容器都加入自定义的bridge网络,然后容器之间通过容器名互相访问,即使容器重启,也不用担心IP变动造成的访问问题了。当然,docker-compose可以自动化以上的操作。
1.2 容器内访问容器外应用
正常情况下,如果都是非容器应用,各个应用之间可以通过"localhost"或"127.0.0.1"来访问本机其他端口的应用,然而如果应用在容器中,你会发现访问不到不在容器中的应用。这是因为"localhost"或"127.0.0.1"是loopback地址(可参考这篇文章来看什么是loopback),会局限在容器内。
那么如何从容器内访问宿主机应用呢?我们上面提到docker默认启动一个bridge网络(docker0),如果启动的容器没有指定自定义的网络,docker会在docker0中选取一个未被使用的IP赋给容器。既然是bridge,所以我们可以通过docker0的Gateway访问到宿主机。查看一下docker0的gateway,在容器中使用gateway的ip就可以访问到宿主机。
上面的方法是通用的方法,而在 docker for mac 额外提供了一个DNS记录,可以访问到宿主机: "host.docker.internal",不过在Linux中就不能使用了。
1.3 容器外应用访问容器A
容器内应用要想开放访问,容器需要使用host网络,或者将端口映射到宿主机的端口,这么做了以后,就可以像访问本地应用一样访问容器应用了。
2、容器或应用不在一台宿主机上
2.1 机器A容器访问机器B本地应用
直接访问,没有什么特殊,机器A容器中访问机器B的IP地址和应用的端口即可。
2.2 机器A本地应用访问机器B容器
和1.3类似,只要机器B中的容器使用host网络或者将端口映射到宿主机(机器B)端口,就可以通过宿主机IP加端口访问。
2.3 机器A容器访问机器B容器
机器A的容器无需特殊配置,机器B中的容器使用host网络或者将端口映射到宿主机(机器B)端口,就可以通过宿主机IP加端口访问。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!