Docker - 容器内应用和外部非容器应用互相访问方法 - Go语言中文社区

Docker - 容器内应用和外部非容器应用互相访问方法


Docker搭建开发环境用的非常多,通常开发机器上既有容器形式的应用,又有本机跑着或者调试的程序,它们之间互相依赖,如何让它们之间通信顺畅,有时候是一个挺困难的事情。容器应用和容器外应用互相访问分为三种情况:

  1. 容器内应用和容器内应用
  2. 容器内应用访问容器外应用
  3. 容器外应用访问容器内应用

而根据两个互相通信的容器或应用在不在一台服务器上,我们又多出一个维度的情况:

  1. 容器或应用在一台服务器
  2. 容器或应用不在一台服务器

要想彻底搞清楚互相访问的问题,就需要先弄清楚docker的网络是怎么一回事。为什么网络重要,这么说吧,docker三巨头:服务(容器)、网络 & 存储,作为三巨头之一的网络,还是要多加重视的。

希望我没有侵权

容器三巨头之一: 网络


常用的docker网络模式有三种:bridge、host 和 overlay,可能会有人说,“谁说的?还有macVlan和none 好吧 ?” ,注意,我说的是常用 ?,三种模式各有适用场景:

  • bridge,应用都是容器形式,且都在一个宿主机上,各个容器需要互相通信的场景;
  • host,容器和本机应用混杂且需要相互访问的情况;
  • overlay,在不同宿主机的容器之间需要互相通信的情景。

Bridge网络

分为“default bridge”和“user-defined bridge”(自定义bridge),docker安装好后会默认创建一个bridge网络(docker0),也就是“default bridge”,未指定网络的容器会默认使用这个网络。一般使用自定义bridge较多,我们定义一个私有网络,可以将我们的应用与其他应用相隔离,这在一个共享的开发服务器上非常有用,此外,自定义网络也有下面两个优点:

  • 只有用户定义的bridge网络才有DNS功能,可通过容器名称互相访问,否则只能使用IP进行容器间访问,而IP一是会变,二是不好记;
  • 容器可以在不停的情况下,更换自定义的bridge,贼方便。

比如有一个容器名称为container-a,我们创建两个bridge网络,不指定driver时默认为bridge:

docker network create bridge-a && docker inspect bridge-a

创建自定义bridge网络

docker network create bridge-b && docker inspect bridge-b

创建自定义bridge网络

我们跑一个alpine的基础镜像容器: "docker run --name=container-a -it alpine:2.9.4 sh",然后查看该容器网络:"docker inspect container-a",

container-a的默认网络配置

container-a使用的默认网段"172.17.0.0/16"不就是docker0的bridge网络的网段么。

docker默认启动的bridge网络

将container-a连接到bridge-a网络: docker network connect bridge-a container-a && docker inspect container-a,我们从结果中可以看到,一个docker容器是可以同时使用两个bridge网络的,这个特性就比较有用了,比如我们使用一个数据库容器供多个网络中的应用使用,分别使用不同的数据库。

一个容器可以在多个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就可以访问到宿主机。

可以看到docker0的gateway是172.17.0.1

上面的方法是通用的方法,而在 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加端口访问。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qingyafan/article/details/90680834
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-08 16:08:14
  • 阅读 ( 1417 )
  • 分类:docker

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢