现实生活中我们的web程序总是需要去访问redis、nginx、db等其他服务,为了应用隔离,我们不会把web程序和中间件部署在同一个容器中,因此就需要用到了容器间的通信。
tips:Docker中容器的name和id可以替换,下文中均使用name
需要学习的几个Docker命令
-
docker inspect 容器id/镜像id
获取容器/镜像的元数据信息 -
docker network ls
列出Docker的网络服务 -
docker network create -d bridge 网桥名
创建网桥 -
docker network connect 网桥名 容器id/容器name
将容器和网桥绑定
虚拟IP通信
Docker容器创建时会自动分配虚拟IP,虚拟IP无法从外部直接访问,但是在Docker环境中是互通的。
启动一个centos容器模拟web服务
docker run -d --name web -it centos bash
因为centos容器启动时会自动退出,因此需要使用-it结合bash使其阻塞
启动一个centos容器模拟mysql服务
docker run -d --name mysql -it centos bash
两个容器启动后,使用命令查看mysql容器的IP地址
docker inspect mysql
如图,在元数据的 Networks>IPAddress中可以看到mysql服务的虚拟ip(172.17.0.3)
进入web容器中尝试访问mysql
docker exec -it web bash
ping 172.17.0.3
可以看到网络通畅,重复上述步骤在mysql容器中ping web服务器的虚拟ip得到相同的结果。
由于容器创建成本较低,使用IP通信在新建或重启容器后需要修改配置信息(或设置为IP),因此不建议使用IP进行容器间的通信
容器间单向通信
除了使用虚拟IP通信,我们还可以使用容器间的单向通信技术,需要在容器启动时指定link对象,并使用name进行通信
启动一个centos容器web-link模拟web服务,并link到mysql容器
docker run -d --name web-link --link mysql -it centos bash
进入web-link容器中尝试访问mysql容器,发现web-link已经能正常访问到mysql容器了!
此时查看服务器的host文件
发现Docker已经帮我们配置了mysql的IP使用同样方法进入mysql容器,并尝试访问web-link容器,提示unKnown
由此可见,link可以实现容器间通信且为单向通信。
问:如果我在两个容器中都配置了单向通信,是不是就能实现双向通信了呢?
博主在Docker版本 20.10.17默认配置情况下是不可以的,感兴趣的可以自己测试
基于Bridge实现容器双向通信
在Docker中连接同一Bridge的容器是互联互通的,因此可以使用自定义网桥来实现特定容器间的互联互通。
查看系统网络配置
docker network ls
可以看到一个名为bridge的网桥,该网桥为Docker默认网桥,承担起容器与外界的通信的桥梁。
由上文可知此时centos1和centos2容器之间无法使用名称进行通信,接下来我们将创建一个自己的网桥来实现容器间的双向通信。
创建两个centos容器
docker run -d --name centos1 -it centos /bin/bash
docker run -d --name centos2 -it centos /bin/bash
创建一个自己的网桥
docker network create -d bridge my-bridge
- create 创建一个网络配置
- -d 指定类型
将容器与网桥进行绑定
docker network connect my-bridge centos1
docker network connect my-bridge centos2
此时可以看到容器的源数据(docker inspect centos1
)中已经有了相关的网桥信息
测试centos1容器与容器centos2是否互通
可以看到我们使用网桥成功将两个容器网络连接起来了!