本文讲的是<b>Docker网络连接探索</b>,【编者的话】本文作者分别从两个方面解释了Docker的网络连接,包括主机间的网络通讯和主机内部的网络通讯。总结一下,默认情况下,主机间的Docker容器通讯只能通过端口映射的方式进行,而主机内部的容器通讯可以通过连接的方式进行。当然,不要忘记ICC参数。
我最近的几篇博客一直在讨论Docker,但是却一直没有提到过Docker如何管理网络。我们知道Docker可以通过端口映射的方式来暴露容器服务,但这一方式也随之带来了一些新的挑战。
讨论与网络相关的话题,我们首先要理解网络的相关知识,并且要知道容器的连接方式。本文主要是回顾Docker基本的网络设置。
所以让我们先从最基本的设置开始吧。在本文中,我们将会使用两个Docker容器:docker1和docker2,它们的网络结构如下图所示。
接下来我们分别在每一个Docker主机上启动一个Docker容器,然后看看会发生什么。我们将通过以下命令在Docker主机上运行一个busybox容器:
因为我们本地并没有busybox镜像,所以Docker会从远程仓库中下载该镜像。容器运行后就会进入一个Shell,让我们来看看相应的网络配置。如下图所示。
嗯,如你所看到的,两个Docker主机上的容器拥有相同的IP地址。这一点非常重要,也就是说,默认情况下,所有的容器网络都会隐藏在实际网络之下。如果我们退出容器,并检查每一个主机上的防火墙规则,那我们会发现:
这里是一个对所有容器有效的策略路由规则(隐藏在NAT下)。这个规则允许所有的容器都可以和外部网络(实际网络)通讯。但是我们不允许外界规则返回到容器内。如前所述,这可以通过端口映射的方式实现点到点的网络接口。举个例子,我们可以通过下面的命令实现在Docker主机上映射8080端口到busybox容器的80端口。
如果我们运行了刚才的命令,那么我们将会看到,防火墙创建了一个关联NAT的规则,完成了从容器的80端口到主机的8080端口的功能。
因此在默认模式下,如果在docker1主机上运行的busybox容器,想要与docker2上的容器进行通讯,它只能将容器内的端口映射到主机上端口。在这种情况下,网络拓扑如下图所示.......
图中有三个不同的网络区域,包括10.20.30/24的物理网络以及两个容器相关的网络。两个容器网络都基于相应主机的docker0的网桥接口。默认情况下,该网络将介于172.17.0.0/16。docker0桥接接口自身的IP地址为172.17.42.1。我们可以通过ifconfig命令查看整个Docker的网络情况。
这里我们可以看到docker0网桥,eth0网口的地址为0.20.30.0/24和本地回环信息。
任何基于同一个docker0网桥的容器都可以通过IP地址直接通讯,
这并不需要用NAT方式或者其它的网络通讯手段来实现。还有一个有趣的实现方法,那就是容器连接。让我们看下面的场景例子,如下图所示。
让我们假设我们要运行的容器都运行于同一个Docker主机上。假定这两个容器之间需要进行网络通讯。我不知道你有没有注意到,Docker并没有为容器指定一个固定的IP地址(注:可能有一些方法可以做到这点,但是据我所知,没有哪一个原生Docker支持这种做法),现在只能动态分配IP地址,这使得在某个容器上创建对外的服务是一件非常困难的事情。这个时候,就是容器连接的用武之地了。
为了从一个容器连接到另一个容器,你只需要在<code>run</code>命令中使用<code>link</code>参数即可。举个例子,让我们先启动一个名为busybox1的容器:
上面的命令将会启动一个运行在busybox的镜像上的名为busybox1的容器,它通过主机的8080端口映射到容器的8080端口,这没什么新鲜的。现在,我们启动第二个名为busybox2的容器。命令如下:
请注意,命令中我使用了<code>--link</code>参数,它将告诉busybox2容器连接到busybox1容器。现在busybox2容器已经启动,让我们看看在容器上到底发生了什么?我们注意到通过busybox1这个名字我们可以直接ping通busybox1容器。
如果我们查看<code>/etc/hosts</code>,我们将会发现Docker创建了一个主机条目,里面是从busybox1容器到busybox2容器的正确的IP地址。是不是很酷?如果我们检查下容器环境变量,我们又将发现一些有趣的东西,如下图所示。
最后,我想谈谈<code>ICC</code>参数。正如我前面提到的,如果有两个容器,它们都在同一个Docker主机内,那它们默认就可以进行通讯。这是真的,因为Docker默认设置了<code>ICC</code>参数并且将它的值设置为true。ICC是标准的容器通讯。如果我们设置将它的值设置为false,那容器只有通过连接或者暴露出的端口才能进行通讯。让我们看下面这个例子。
注意:在主机上改变 ICC的参数必须基于一个运行的Docker。目前我运行在CentOS 6.5上。
首先,让我们在docker1主机上把<code>ICC</code>标识设置为false。为此,我们编辑<code>/etc/sysconfig/docker</code>文件。这看起来像是我们第一次编辑它。
改变<code>other_args</code>所在行的值为<code>-ice=false</code>。
保存该文件并重启Docker服务(<code>service docker restart</code>)。一旦服务启动成功,ICC将不可见,然后我们继续测试。
在docker1主机上,我将要下载并运行一个Apache容器,同时将容器的80端口映射到主机的8080端口上。
这里我们可以看到我通过守护进程的方式启动了一个名为web的容器,并且映射了端口。现在让我们启动第二个名叫DB的容器并连接到刚才的web容器上。
注意:刚才的DB容器并不能ping通web容器。让我们试着允许web容器在暴露的端口上访问。
哈哈!正如我期望的那样现在起作用了,我只能连接容器到暴露的端口上。
原文发布时间为:2015-01-22
本文作者:jeffsui
本文来自云栖社区合作伙伴DockerOne,了解相关信息可以关注DockerOne。
原文标题:Docker网络连接探索