容器之间的网络通信
Docker中的不同容器之间需要通过网络来进行通信,那么各个容器之间具体是如何实现通信的呢?接下来,本小节将以非集群环境下的容器通信为例,对Docker容器之间的通信进行讲解。
实现Docker容器之间网络通信的具体步骤如下。
1. 创建容器
(1)创建两个使用默认的bridge网络的容器,具体操作指令如下。
$ docker run -itd --name=container1 busybox
$ docker run -itd --name=container2 busybox
执行上述指令后,会创建两个名为container1和container2的容器,同时他们都是使用默认的bridge进行网络管理的。
(2)创建一个使用自定义的isolated_nw网络(需要预先创建)的容器,具体操作指令如下。
$ docker run --network=isolated_nw -itd --name=container3 busybox
执行上述指令后,会创建一个名为container3的容器,使用--network参数指定了该容器的网络管理为自定义的isolated_nw。
(3)为container2容器新增一个自定义的isolated_nw网络连接,具体操作指令如下。
$ docker network connect isolated_nw container2
执行上述指令后,container2容器就同时拥有了bridge和isolated_nw两种网络管理方式。
执行完前面3个步骤后,container1使用的是默认的bridge网络管理,container3使用的是自定义的isolated_nw网络管理,而container2使用的是默认的bridge网络管理和自定义的isolated_nw网络管理。这3个容器具体的网络管理关系,可以通过图1进行说明。
图1 容器网络关系图
从图1可以看出,container1和container2在同一个默认的bridge网络管理下,这两个容器可以相互通信;而container2又和container3在同一个自定义的isolated_nw网络管理下,这两个容器也可以相互通信;但是container1和container3属于不同的网络环境,所以这两个容器无法进行通信。
2. 容器地址查看
为了演示图1中不同容器之间的网络通信情况,这里需要先查看各个容器的网络地址。
首先,进入container2容器,具体操作指令如下。
$ docker attach container2
然后,使用ifconfig指令查看当前容器被动态分配的地址,如图2所示。
图2 容器IP地址详情
从图2可以看出,在container2容器内部有两个网卡eth0和eth1(这就是使用了两种网络管理方式自动产生的),并分别对应的IP地址为172.17.0.3和172.18.0.2。
接下来,分别进入容器container1和container3,并通过ifconfig指令查看对应容器的IP地址,效果如图3所示。
图3 容器ip地址详情
从图3可以看出,container1的IP地址为:172.17.0.2,container3的IP地址为:172.18.0.3。
小提示:
当使用docker attach指令进入容器内部后,可以在终端使用exit命令或者使用快捷键CTRL+p+q组合键退出当前容器,只不过在使用exit退出容器后,该容器就会停止运行,而使用CTRL+p+q组合键退出当前容器后,该容器会持续运行。
3. 容器通信测试
首先,使用docker attach container1指令进入container1容器内部,使用ping指令连接container3来查看是否能够通信,效果如图4所示。
图4 容器连接效果图
从图4可以看出,在container1内部不管是使用“ping -w 4 IP”(-w 4限制响应4次),还是“ping -w 4 容器名称”的指令都无法连通container3。这也就验证了两个容器不在同一个网络环境下,无法通信的判断。
接着,使用docker attach container2指令进入container2容器内部,使用容器IP分别连接container1和container3进行通信测试,效果如图5所示。
图5 容器连接效果图
从图5可以看出,在container2内部使用“ping -w 4 IP”的指令可以同时连通container1和container3,这也与前面的分析结果相同。
最后,再在container2容器内部使用容器名称分别连接container1和container3进行通信测试,效果如图6所示。
图6 容器连接效果图
从图6可以看出,在container2内部使用“ping -w 4 容器名称”的指令可以连通container3,而连接container1却显示“bad address‘container1’”错误。
通过前面的测试,我们可以得出一个结论:不同容器之间想要相互通信必须在同一个网络环境下;使用默认bridge网络管理的容器可以使用容器IP进行通信,但无法使用容器名称进行通信;而使用自定义网络管理的容器则同时可以使用容器IP和容器名称进行通信。
多学一招:默认网络下使用- -link参数通过容器名称进行通信
前面的示例已经演示说明了使用默认网络管理的容器无法使用容器名称进行通信,而单纯使用IP地址进行通信显然是不可靠的,因为多数情况下IP地址都是动态分配的,当容器重启后其他容器就无法正确连接到该容器了。若想要在默认网络下,使用容器名称进行通信,则需要使用--link参数,该参数是在启动容器时进行容器连接使用的。
在默认网络下,使用--link参数的具体指令如下。
$ docker run -itd --name=container4 --link container1:c1 busybox
执行上述指令后会新建并启动一个名为container4的容器,指令中的-itd用于指定后台交互式运行,--name用于指定生成容器的名称,而--link container1:c1则将新建的container4容器连接到了container1容器且为container1容器定义了别名c1。
这种使用--link参数创建的默认网络下的容器就可以使用容器名称或别名与指定连接的容器进行通信了。所以这里容器container4可以使用容器名称container1或者别名c1与container1进行通信,但容器container1仍不可以使用容器名称与container4进行通信。
不过根据Docker官网的声明,--link是属于Docker低版本遗留的功能,在未来可能会被弃用。这里只有容器需要在默认网络上使用容器名进行通信的情况,才会使用--link功能,官方更推荐使用用户自定义的网络进行容器管理。