Docker容器互联方法

【编者的话】本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示。Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问。本文根据他于DEIS官方博客上发布的文章翻译而成。
这篇系列文章的第二部分会看一下如何连接Docker各容器。

我们在第一节谈及了Docker的bridge接口,它可以让我们连接所有在相同Docker宿主机上的容器。特别需要指出的是,我们看了三个基本并且比较早先的网络驱动技术:端口公开(port exposure),端口绑定(port binding)以及链接(linking)。 如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

在本文,我们将来看这些更高级并且最新的基于bridge接口的使用案例。
同时,我们也会看看使用overlay技术来将不同宿主机上的Docker容器连接起来。

用户定义的网络(User-Defined Networks)

Docker公司在2015年11月初发布了Docker 1.9.0,随之而来整合了一些令人兴奋的关于网络方面的 新内容
。通过这些更新,如果我们现在为了让两个容器间可以相互通信,那么只需要将他们放在同一网络或者子网中。
让我们来证明一次。
首先,来看看我们准备了哪些:

$ sudo docker network ls

NETWORK ID          NAME                DRIVER

362c9d3713cc        bridge              bridge

fbd276b0df0a        singlehost          bridge

591d6ac8b537        none                null

ac7971601441        host                host

现在,让我们来创建网络:

$ sudo docker network create backend

如果起作用了,我们的网络列表上会显示刚才新建立的网络:

$ sudo docker network ls

NETWORK ID          NAME                DRIVER

362c9d3713cc        bridge              bridge

fbd276b0df0a        singlehost          bridge

591d6ac8b537        none                null

ac7971601441        host                host

d97889cef288        backend             bridge

我们可以看到在这里backend已经被bridge驱动创建出来了。这是一个桥接(bridge)网络,就像在前文的第一部分中提到的一样,它也同样适用于所有在该宿主机上的容器。
我们将会用到上一节中创建的client_img和server_img镜像。如果你还没有在你的主机上配置好他们,可以现在查阅第一节并且设置好,这并不会花费太长时间。
什么?你说你已经设置好了?太棒了。
让我们从server_img镜像中运行一个服务器容器并且通过–net选项把它放置于之前配置的backend网络中。
就像下面命令一样:

$ sudo docker run -itd --net=backend --name=server server_img /bin/bash

像之前一样,登录到该容器:

$ sudo docker attach server

如果你看不见shell提示符,按键盘方向键的上箭头。
现在让我们启动在该容器里基于Apache的HTTP服务:

$ /etc/init.d/apache2 start

到这里为止,任何位于backend网络中的容器将可以连接到我们刚才创建的Apache HTTP服务器上。
我们可以通过在另一个终端上开启一个客户端容器并且把它至于backend网络进行测试。
就像这样:

$ sudo docker run -itd --net=backend --name=client client_img /bin/bash

进入容器:

$ sudo docker attach client

同样地,如果你看不见shell提示符,按键盘方向键的上箭头。
接着运行:

$ curl server

你应该可以看见默认的HTML页面。这意味着我们配置的网络是可以正常运行的。
就像在本系列文章的第一节中提及到的一样,Docker负责设置容器名称便于解析,这就是为什么我们可以直接用curl server 这个命令而不用知晓它的IP地址。
我们可以创建多个用户定义的网络,并且可以根据应用程序的拓扑结构把这些容器放在单个或多个网络中。这是非常灵活的,特别是对于那些需要交付微服务(microservices),多租户(multitenancy)及微分段(micro-segmentation)的人员来说是非常有用的。

多主机网络(Multi-Host Networking)

如果我们想要建立一个跨越多台主机的网络该怎么做呢?当然,自从Docker1.9.0之后,你就可以这么做了!
目前为止,我们已经使用了基于本地范围的bridge网络驱动,这意味着桥接网络是在Docker宿主机本地的。Docker现在提供了一个新的全局范围的overlay网络驱动,这意味着overlay的网络可以跨越多台Docker宿主机。并且这些Docker宿主机可以存在于不同的数据中心,甚至不同的云服务提供商中!
为了设置一个overlay网络,以下几点是必须的:

  • 一台内核版本高于3.16的主机
  • 关键的key-value存储(例如 etcd
    , Consul
    Apache ZooKeeper
  • 集群内的主机可以保证连接到以上的key-value存储
  • 每一个集群内的主机都正确配置了基于 Docker Engine
    的后台实例

让我们来看一个案例吧。

我将会使用 multihost-local.sh
脚本和 Docker Machine
这个命令去开启三台虚拟主机。
这个脚本是用于虚拟机的而不是用于容器的。在这之后,我们在这些虚拟机上面运行Docker命令去模拟一个Docker宿主机集群。
在运行过脚本之后,可以看到我现在有的主机清单:

$ docker-machine ls

NAME         ACTIVE   DRIVER       STATE     URL                         SWARM   ERRORS

mhl-consul   -        virtualbox   Running   tcp://192.168.99.100:2376

mhl-demo0    -        virtualbox   Running   tcp://192.168.99.101:2376

mhl-demo1    -        virtualbox   Running   tcp://192.168.99.102:2376

好了,那么让我们倒退回去看下刚才发生了些什么。

这个脚本利用了Docker Machine,这意味着你必须安装它。在本篇文章中,我们安装了0.5.2版本的Docker Machine。你可以参考该版本的 发行注释
说明来下载并安装它。
该脚本(multihost-local.sh)使用了Docker Machine去部署三台基于VirtualBox的虚拟机并且安装并适当的配置了Docker Engine。
Docker Machine可以与很多主流虚拟化管理程序以及云服务提供商一起协助。它现在支持AWS、Digital Ocean、Google Cloud Platform、IBM Softlayer、Microsoft Azure和Hyper-V、OpenStack、Rachspace、VitrualBox、VMware Fusion®、vCloud® Air™ and vSphere®。
我们现在有了三个虚拟机:

  • mhl-consul: 运行 Consul
  • mhl-demo0: Docker 集群节点
  • mhl-demo1: Docker 集群节点

这些Docker集群节点是被配置为协调通过VM来运行Consul,我们的key-value仓库。这也就是这些集群所涉及到的。
很酷吧,让我们再快速地往前看一看。
现在,让我们设置一个overlay网络。
首先,我们需要用一个在mhl-demo0这个VM上的终端,像这样:

$ eval $(docker-machine env mhl-demo0)

然后运行:

$ docker network create -d overlay myapp

该命令建立了一个名为myapp的跨越所有集群中主机的overlay网络。由于Docker通过key-value与该集群上的其他主机协调使得该操作变成了可能。
为了确保它正常的工作,我们可以通过终端登录到每一个集群中的VM去列出这些Docker网络。
复制下面所有的eval命令,然后用相对应的主机名去替换mhl-demo0。
然后运行:

$ docker network ls

NETWORK ID          NAME                DRIVER

7b9e349b2f01        host                    host

1f6a49cf5d40        bridge                  bridge

38e2eba8fbc8        none                   null

385a8bd92085        myapp               overlay

到这里你就看到名为myapp的overlay网络了。
咱们成功啦!
但请记住:我们目前仅仅是创建了一个基于Docker 虚拟机的集群并配置了用于共享的overlay网络。我们实际上并没有创建任何Docker容器。所以让我们接着创建它们并来试一下这个overlay网络。
我们将做以下步骤:

  1. 在mhl-demo0宿主机上运行默认地nginx镜像(这提供给了我们一个预先配置好的Nginx HTTP服务器)
  2. 在mhl-demo1宿主机上运行默认的busybox镜像(它提供给我们一个基本的操作系统并且还包含一个类似于基于GNU的Wget工具)
  3. 将两个容器添加进myapp网络
  4. 测试他们之间的网络连通性

首先,让我们调出在mhl-demo0宿主机上的终端:

$ eval $(docker-machine env mhl-demo0)

然后启动nginx镜像:

$ docker run --name ng1 --net=myapp -d nginx

简而言之,我们现在有以下环境:

  • 一台基于Nginx的HTTP服务器
  • 该服务跑在名为ng1的容器里
  • 它处在myapp网络中
  • 该容器位于mhl-demo0宿主机上

让我们从其他宿主机上的另外一个容器试着去访问该环境,去验证它是可用的。
这一次调出mhl-demo1宿主机上的终端:

$ eval $(docker-machine env mhl-demo1)

然后运行:

$ docker run -it --net=myapp busybox wget -qO- ng1

以上命令其实做了以下几点:

  • 从busybox镜像中创建了一个未命名的容器
  • 将它添加进了myapp网络
  • 运行了wget -qO- ng1命令
  • 并且停止了该容器(我们在这之前是让容器运行的)

在以上的Wget命令中,ng1是我们Nginx的容器名称。Docker可以让我们使用解析到的主机名作为容器名称,甚至该容器是运行在不同的Docker宿主机上。
如果所有操作都是成功的,那么我们应该会看见以下类似的内容:












Welcome to nginx!

你看吧!我们现在拥有了一个基于多主机的容器网络。

总结

Docker给予了诸如轻量级且独立地并能隔离的环境这样的优点。然而,要使容器对我们而言有用途,容器之间以及容器与主机网络之间要能互相通信才是至关重要的。
在这一系列文章中,我们探索了一些容器间本地互联和跨多个宿主机互联的方法。同样地,我们也聊了聊该如何在主机网络中去连接多个容器。

原文链接: Connecting Docker Containers, Part Two
(翻译:薛开成)
===========================================
译者介绍

薛开成,趋势科技南京研发中心工程工具服务事业部基础架构高级工程师,负责容器仓库实施及落地。