ITPub博客

Docker网络入门 – 默认设置

翻译 作者:hjianhao 时间:2015-06-21 23:00:43 0 删除 编辑

译者注: {
这是我在国外的博客上看到的一系列关于docker和kubernetes网络分析的文章,感觉描述得比较清晰,便于刚接触docker和kubernetes的朋友了解相关的知识。在看的同时顺便就翻译了,方便和网友一起交流探讨。
我不仅仅是翻译,还按照文章中描述的进行了实际测试,对于测试中出现的问题和由于环境不同或者软件版本更新带来的变更也在译者注中给出说明。
我并没有按原文一字一句的翻译,对于理解这些知识点没有帮助的语句我一般都忽略了。
我的测试环境和笔者不同,我使用的是单台物理机,用Vagrant模拟多台VM Host,VM Host使用和物理机相同网段的public网络,操作系统是CentOS 7.0, Docker版本1.6.2)
}

Docker可以通过端口映射(port mapping)来将容器的服务暴露出去,但是这会带来一些有趣的挑战。

让我们从最基础的开始。在本文中,我们将与两个docker主机一起工作,docker1和docker2。他们在网络中的位置是这样的:

没什么复杂的。两个主机使用非常简单的网络配置。 我们假设你已经安装了docker并以默认配置运行。 此时,我为每台主机配置一个静态IP,配置一个DNS服务器。

默认的主机间网络通讯
让我们继续,在每个docker主机上启动一个容器,看看我们得到的。 我会使用以下命令在每台主机上运行一个busybox容器的拷贝:

点击(此处)折叠或打开

  1. docker run -it --rm busybox

让我们看看容器使用了什么IP地址:

就像我们看到的那样,在两个主机上的两个容器都使用了相同的IP地址。这带来了docker网络的一个重要方面。就是在默认情况下,所有的容器网络都隐藏在真是网络之下。如果我们推出我们的容器并检查两台主机的iptables规则,我们会看到以下内容:

里面有一个对所有容器的masquerade(hide NAT)规则。这个允许所有的容器可以连接外部网络,但是不允许外部网络访问容器。 就像前面所说的,如果要外部网络访问容器,可以通过将容器的端口映射到主机的端口达成。例如我们可以使用以下命令将8080端口映射到主机的80端口。

点击(此处)折叠或打开

  1. docker run -it –rm –p 8080:80 busybox

当我们运行了这个命令,我们看到iptables创建了一个相关的NAT规则将目标为主机的8080端口的流量转发到了容器的80端口

所以在默认模式下,如果docker1上的busybox容器需要与docker2上的busybox容器通讯,智能通过在主机网络接口暴露端口的方式进行。这就是说,在这个场景下网络图是这样的:


在这张图上我们有三个不同的网络区域。我们有一个物理网络10.20.30.0/24,同时也有两个docker主机创建的用于容器的网络。这些网络依靠每个主机上的网桥docker0。默认情况下,这个网络永远是172.17.0.0/16。docker0网桥接口的IP固定为172.17.42.1。我们可以在物理主机上通过查看接口了解到。


这里我们可以看到docker0网桥,10.20.30.0/24网络上的eth0接口,和本地环回接口


默认主机内网络通信

这个场景有点直白。任何位于相同docker0网桥的容器可以直接通过IP交互,不需要NAT或者任何其他网络技巧来。然而又一个有趣的docker增强应用于这个场景。容器连接似和网络没啥关系,让我以以下场景做为例子。

让我们假设我们想在同一个docker主机运行两个busybox。让我们假设这两个容器需要相互对话以交付而服务。我不确认你是否注意到这点,docker实际不会设计为给一个容器提供指定的IP地址(注意:可以通过其他方式做到这点,但据我所知是没有一个是docker原生的方法)。这让我们面临动态IP地址空间分配的问题。然而,这让一个容器消费另一个容器的服务变得困难。这就需要容器连接发挥作用了。

让一个容器与另一个容器连接,简单的通过在将link属性传递给docker run的属性就可以了。例如我们启动一个名为busybox1的busybox容器。

点击(此处)折叠或打开

  1. docker run --name busybox1 -p 8080:8080 -it busybox
这会启动一个名为busybox1容器,运行busybox镜像,将主机的8080端口映射到容器的8080端口。除了对容器命名,这里没有新的东西。让我再启动一个名为busybox2的容器:

点击(此处)折叠或打开

  1. docker run --name busybox2 --link busybox1:busybox1 -it busybox


注意我列入了一个'--link'命令。这个会告诉容器busybox2连接到busybox1。现在busybox2加载了,让我们看一下在容器中发生了什么。首先我们注意到我们能通过名字ping通busybox1。

如果我们查看'/etc/hosts'文件,我们可以看到docker在busybox2容器中的主机条目中列入了busybox1的正确地址。非常漂亮是不是? 同时,如果我们检查容器的环境变量,我们还可以看到一些有趣的项。

有趣的是,我现在有一堆环境表里告诉我在busybox1上的端口映射配置。这不仅非常棒,这也对我们开始考虑在容器中抽象服务非常重要。没有这些信息,写充分利用docker和其动态性来写应用变得非常困难。对于连接和这里有哪些环境变量被创建在docker网站上有更多完整的信息。
最后但不是最重要的,我想谈一下'ICC'标识。我在上面提到任意两个在同一个docker主机上运行的容器默认能相互通讯。这是因为'ICC'标识的默认值是true。ICC表示容器间通讯(Inter Container Communication)。如果我们将这个标识设置为false,那只有被连接的容器才能相互通讯,并且只能通过容器暴露的端口进行通讯,让我们看一个例子。

注意:变更一个主机的ICC标识基于你运行Docker的操作系统不同有不同的方法,在我的例子里,我运行的是CentOS 6.5。

首先,让我在docker1主机上将ICC标识设置为false。要完成这个,编辑/etc/sysconfig/docker文件。 第一次编辑时,他应该看起来像这样:


修改‘other_args'行为这样:

译者注 {
在译者运行的运行环境(CentOS 7.0和docker 1.6.2)上,第一次编辑文件应该是这样的。
# Modify these options if you want to change the way the docker daemon runs
OPTIONS='--selinux-enabled'
OPTIONS=''
将第二行OPTIONS变为:
OPTIONS='--icc=false'

在Ubuntu 14.04和docker 1.6.2上,编辑的文件是/etc/default/docker。
增加参数:
DOCKER_OPTS='--icc=false'

在Ubuntu 15.04中,不再采用Upstart,而是采用Systemd,所以服务配置文件是/etc/systemd/system/multi-user.target.want/docker.service
在ExecStart中增加启动参数
}

保存文件重启docker服务。在我的例子里,完成这个的命令是'service docker restart' (译者注:CentOS7建议使用systemctl restart dockekr)。 当服务重启后ICC将会被禁用,我们可以继续测试。
在docker1主机上,我们将下载一个apache容器并运行,暴露容器的端口80到主机的8080端口。
译者注 {
eboraas/apache的最新版本可能运行有问题。如果遇到问题可以使用eboraas/apache:oldstable标签的版本,亲测没有问题。反正是测试,不一定要用最新版本。
}


在这里我们看到我启动了一个叫做web的容器,映射端口,并且做为daemon运行。现在我们启动第二叫db的容器,并连接这个web容器。


注意db容器并不能ping通web容器。让我们尝试通过web容器暴露的端口访问它:

啊哈!如我们期待的工作。我只能访问连接容器暴露的端口。像我提到的,容器连接和网络几乎无关。 ICC非常接近我们实际网络的策略并且其和当我们连接容器时实际发生的事情无关。
译者注 {
在物理机上测试原文的描述是没有问题的。
但是在vagrant创建的虚拟机(virtual box,网络配置为public_network,网段和物理机一致)上测试的结果是:
1、--icc=true 可以ping通,link也没有问题
2、--icc=false ping不通,link也不起作用,例如 wget始终就是失败的。
但是将网络改为private_network,测试就OK了。奇怪的是再将网络改回public_network也是OK的。原因不明
}

在接下来帖子里,我将讨论一些docker网络的非默认选项。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2015-06-21

  • 博文量
    1
  • 访问量
    2107