本系列往期文章:
概述:Docker 入门(一)
镜像:Docker 入门(二)
volume:Docker 入门(三)
场景:假设我们有一个 web 应用,需要显示总共连接的次数,同时我们使用另一个 redis 服务去记录这个数值,显然 web 是需要连接到 redis 上的,而在 docker 容器中,每个容器都默认有自己独立的虚拟网络,那么容器之间应该如何连接?
01
—
link
首先我们启动一个 redis 容器,并通过 --name 指定容器名也叫 redis :
docker run --name redis redis
然后,启动 web 容器,通过 --link 指定连接的容器并指定这个连接的名称(注意以下指令都是在 docker run 后面添加的部分):
--link redis:redis_connection
而我们的 web 程序中直接使用上面定义的连接名 redis_connetion 即可:
这样 web 容器便可以连接上 redis 容器了,如下图所示:
使用 link 方法,其会在容器启动时(容器每次启动都会默认配置不同的虚拟网络)找到连接的目标容器并在本容器内部设置环境变量并修改 /etc/hosts 文件,这也是我们可以直接使用连接别名而不用指定具体 IP 地址的原因。
但是,不建议使用这种方式,同时这种方式也将会在未来被移除。
02
—
net
1、net 方式一,如下图所示:
我们先将 redis 容器的端口暴露到本地宿主机,然后在 web 中指定本地宿主机具体的 IP 地址,这样也可以实现连接,但是需要注意的是,在 web 中不能直接使用 localhost ,因为前面已经提到了,每个容器都有自己独立的虚拟网络,使用 localhost 将会指向的是这个容器内部,而不是宿主机。
这种方式,我们也可以看到,很麻烦,一方面 redis 需要暴露端口,另一方面还必须知道宿主机具体的 IP 地址。
2、net 方式二,如下图所示:
这里与前一种方式不同的是,我们直接通过 --net host 指定容器直接使用宿主机网络,这样在 web 中就可以直接通过 localhost 连接到 redis 了,不用知道宿主机具体的 IP 地址,对比上一种方式看似有一点小的改进。
但是这种方式的问题在于,对于 MacOS 系统无法使用,因为在 MacOS 上 Docker 仍然是跑在一层虚拟机中的,这种方式目前还无法穿透这层虚拟机直接将 localhost 映射到宿主机本地,同时,直接使用宿主机网络,容器其实会全部暴露出来,存在安全隐患,因此也不建议使用这种方式。
3、net 方式三,如下图所示:
这里通过 --net container 的方式直接指定 web 使用与 redis 相同的网络,这样既避免了无谓的端口暴露,同时又能保持容器与宿主机之间的隔离,这种方式是建议使用的。
但是存在需要注意的地方,那就是 --net container 指定容器网络与 -p 暴露端口不能同时使用,换句话说,本来我们的 web 容器是需要 -p 暴露端口到宿主机,这样我们才能在本地访问到 web 服务,但是因为我们已经使用了 --net container 指定其使用与 redis 相同的网络,所以不能再使用 -p 了,那怎么办?可以在另一个 redis 容器上使用 -p ,将本来应该由 web 直接暴露的端口间接的由 redis 暴露,毕竟此时我们的 web 和 redis 容器都已经使用了同一个网络,所以这样做也是没问题的,但还是有点别扭的。
03
—
自定义网络
官方在宣告 link 方式将会被移除的同时,推荐的替代方式就是自定义网络。
创建一个简单的自定义网络:
docker network create -d bridge my-network
将 web 和 redis 容器连接到同一个自定义的网络中,并直接在 web 中的 redis host 指向 redis 容器的别名,即可完成连接,如下图所示:
对于自定义网络,我们不仅能够在容器启动时通过 --net 直接指定,还能够在容器已经启动完成后通过:
docker network connect [network-name] [container]
后续添加进去,这也就意味着我们可以方便快速的完成容器网络的切换与迁 移。
通过自定义网络,我们还能够定义更加复杂的网络规则,比如网关、子网、IP 地址范围等等,当然更多的细节还请查阅官方文档。
04
—
结语
本文通过一个简单的示例描述了容器之间互相连接的几种不同方式,重点关注下自定义网络就好了,本篇完。