Docker网络入门(一) – 默认设置



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

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

让我们从最基础的开始。在本文中,我会让两个Docker主机一起工作,Docker1和Docker2。他们在网络中的位置是这样的:
1.png

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

默认的主机间网络通讯

让我们继续,在每个Docker主机上启动一个容器,看看我们得到什么。我会使用以下命令在每台主机上运行一个busybox容器的拷贝:
Docker run -it --rm busybox

2.png

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

正如我们所看到的,在两个主机上的两个容器都使用了相同的IP地址。这说明了Docker网络的一个重要信息。就是在默认情况下,所有容器网络都隐藏在真实网络之下。如果我们退出容器并检查两台主机的iptables规则,我们会看到以下内容:
4.jpg

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

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

所以在默认模式下,如果Docker1上的busybox容器需要与Docker2上的busybox容器通讯,这可以通过主机网络接口上的一个暴露端口完成。也就是说,在这个场景下网络图是这样的:
6.jpg

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

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

默认主机内网络通信

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

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

可以简单的在Docker run的属性上传递link属性,来实现一个容器与另一个容器连接。例如我们启动一个名为busybox1的busybox容器。
Docker run --name busybox1 -p 8080:8080 -it busybox


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

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

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

有趣的是,我现在有一堆环境变量,这些变量告诉我在busybox1上的端口映射配置。这不仅非常棒,这也对我们开始考虑在容器中抽象服务非常重要。没有这些信息,写出充分利用Docker和其动态性的应用会非常困难。在docker网站上,那里有很多关于连接和环境变量的完整信息。

最后但不是最重要的,我想谈一下'ICC'标识。我在上面提到任意两个在同一个Docker主机上运行的容器默认能相互通讯。这是因为'ICC'标识的默认值是true。ICC表示容器间通讯(Inter Container Communication)。如果我们将这个标识设置为false,那只有被连接的容器才能相互通讯,并且只能通过容器暴露的端口进行通讯,让我们看一个例子。

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

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

修改other_args行为这样:
12.png



译者注:
在译者运行的运行环境(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端口。
13.jpg


译者注:
eboraas/apache的最新版本可能运行有问题。如果遇到问题可以使用eboraas/apache:oldstable标签的版本,亲测没有问题。反正是测试,不一定要用最新版本。
在这里可以看到我启动了一个叫做web的容器、映射端口,并且做为daemon运行。现在我们启动第二叫db的容器,并连接这个web容器。
14.png

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

啊哈!如我们期待的工作。我只能访问连接容器暴露的端口。像我提到的,容器连接和网络几乎无关。ICC非常接近我们实际网络的策略并且和我们连接容器时实际发生的事情无关。


译者注:
在物理机上测试原文的描述是没有问题的。
但是在vagrant创建的虚拟机(virtual box,网络配置为public_network,网段和物理机一致)上测试的结果是:
1、--icc=true 可以ping通,link也没有问题
2、--icc=false ping不通,link也不起作用,例如 wget始终就是失败的。
但是将网络改为private_network,测试就OK了。奇怪的是再将网络改回public_network也是OK的。原因不明
在接下来帖子里,我将讨论一些Docker网络的非默认选项。

========================================

原文链接:Docker Networking 101 – The defaults (翻译:黄剑豪 校对:魏小红)

6 个评论

很好的翻译。赞一下。
如果方便的话,最好能给出原文链接。
http://www.dasblinkenlichten.com/docker-networking-101/
原来想贴的,但是被墙了,我想了一下就没有贴出来。
请 @李颖杰 协助编辑一下本文,增强可读性。
赞一个~~
很棒的翻译,有图有真相,最重要的是译者自己还实践了一遍。
值得一赞,易明白非常好教材

要回复文章请先登录注册