使用Docker Swarm和Docker Networking部署容器

本文介绍了如何使用Docker 1.9的新网络功能在Swarm集群上部署容器,包括设置集群、使用Docker Swarm和Docker Networking,以及服务发现的实现。通过Ansible配置Swarm集群,使用Consul和Registrator进行服务注册和发现,演示了如何在多主机网络中实现容器间的通信和负载均衡。
摘要由CSDN通过智能技术生成

本文的目的是探索1.9版中引入的新Docker网络功能。 我们将它们应用于Docker Swarm集群。 出于实践目的,我们将容器部署到使用Vagrant在本地创建的Swarm集群中,并将Consul作为服务注册表运行,将Registrator作为工具运行,以监视Docker守护进程并注册/注销我们运行/停止的容器。 合并后,Consul和Registrator将充当我们集群中的服务发现。 我不会详细介绍Docker Swarm或服务发现的工作原理。 您可以在以下文章中找到有关这些主题的更多信息。

我们将直接跳过Swarm集群中使用的Docker网络功能。

设置集群

首先是第一件事。 让我们设置三个VM,将它们用作练习基础。 swarm-master节点将充当节点,而其他两个VM将代表由两个节点组成的集群。 所有三个VM都将运行Ubuntu,并使用VirtualBoxVagrant创建。 请确保两者均已安装。 您还需要Git来克隆将在本文中使用的代码。 如果您是Windows用户,请先按照在Windows上运行Linux VM中介绍的说明进行操作,然后再介绍以下内容。

让我们从创建将模拟Swarm集群的VM开始。

git clone https://github.com/vfarcic/docker-swarm-networking.git

cd docker-swarm-networking

vagrant up swarm-master swarm-node-1 swarm-node-2

vagrant ssh swarm-master

现在已经创建了VM,并且我们在swarm-master内部,让我们为VM提供Docker,Docker Compose,Consul,Registrator和Swarm。 我们将通过Ansible做到这一点 。 如果您不熟悉Ansible,则可以在此博客中找到很多示例。

ansible-playbook /vagrant/ansible/swarm.yml \
    -i /vagrant/ansible/hosts/prod

swarm.yml剧本确保Docker正在运行并配置为支持Swarm。 它还为服务器配备了Docker Compose,Consul,Swarm和Registrator。

让我们仔细检查一切是否按预期进行。

export DOCKER_HOST=tcp://localhost:2375

docker info

curl localhost:8500/v1/catalog/nodes | jq '.'

DOCKER_HOST变量告诉Docker将命令发送到在端口2375上运行的Swarm主服务器 。 随后是docker info ,该docker info显示Swarm集群中有两个节点。 最后,最后一条命令请求在Consul中注册的所有节点的列表,并获得所有三个VM(一个Swarm主节点和两个Swarm节点)作为响应。

目前,我们已经启动并运行了Swarm集群,可以开始使用Docker网络了。 但是,在继续介绍实际示例之前,让我们快速了解其背后的想法。

使用Docker Swarm和Docker Networking进行部署

不久前,Docker推出了新版本1.9。 毫无疑问,它是自1.0版以来最重要的发行版。 它为我们提供了两个期待已久的功能; 多主机网络和持久卷。 网络使不赞成使用链接,这是我们需要在多个主机之间连接容器的功能。 不再需要代理来链接构成服务的多个容器。 这并不是说代理没有用,而是我们应该将其用作服务和网络的公共接口,以连接形成逻辑组的容器。 新的Docker网络和代理服务具有不同的优势,应用于不同的用例。 代理服务尤其提供负载平衡,并可以控制对我们服务的访问。 Docker网络是连接形成单个服务并驻留在同一网络上的各个容器的便捷方法。 Docker网络的一个常见用例是需要连接到数据库的服务。 我们可以通过网络连接这两个。 此外,服务本身可能需要扩展并运行多个实例。 具有负载均衡器的代理服务应满足该要求。 最后,其他服务可能需要访问此服务。 由于我们想利用负载平衡,因此访问也应该通过代理进行。

多主机网络

该图代表一个常见的用例。 我们有一个扩展的服务,在节点1和3上运行着两个实例。与这些服务的所有通信都是通过代理服务执行的,该代理服务负责负载平衡和安全性。 想要访问我们服务的任何其他服务(无论是外部还是内部)都需要通过代理。 在内部,服务使用数据库。 服务和数据库之间的通信是内部的,并通过多主机网络执行。 此设置使我们可以轻松地在集群内扩展,同时保持组成单个服务的容器之间的所有通信内部。 换句话说,组成服务的容器之间的所有通信都是通过网络完成的,而不同服务之间的通信是通过代理完成的。

有多种创建多主机网络的方法。 我们可以手动设置网络。

docker network create my-network

docker network ls

network ls命令的输出如下。

NETWORK ID          NAME                           DRIVER
f8a50a3c9c13        swarm-node-1/host              host
8ae6cefc3957        swarm-node-2/host              host
5f68a88668f6        swarm-node-2/bridge            bridge
397107ba0daf        swarm-node-2/none              null
b655577f0030        swarm-node-1/bridge            bridge
efb02b0fa9b9        swarm-node-1/docker_gwbridge   bridge
eb5ff0f0136a        swarm-node-1/none              null
71b80ae02620        my-network                     overlay
ac4261d5e27a        swarm-node-2/docker_gwbridge   bridge

您可以看到其中一个网络是我们之前创建的my-network 。 它涵盖了整个Swarm集群。 我们可以将此网络与–net参数一起使用。

docker run -d --name books-ms-db \
    --net my-network \
    mongo

docker run -d --name books-ms \
    --net my-network \
    -e DB_HOST=books-ms-db \
    -p 8080 \
    vfarcic/books-ms

在继续之前,让我们确认Swarm已在集群中分发了容器。

docker ps --filter name=books --format "table {{.Names}}"

就我而言,输出如下。

NAMES
swarm-node-2/books-ms
swarm-node-1/books-ms-db

您可以看到每个容器都已部署到不同的节点。 这是Docker Swarm的主要目的; 在整个集群中分布容器。 问题是,如果这些容器位于单独的节点上,它们如何相互通信?

我们开始了两个组成一个服务的容器。 books-ms是与充当数据库的books-ms-db通信的API。 由于两个容器都具有–net my-network参数,因此它们都属于my-network网络。 结果,Docker更新了主机文件,为每个容器提供了一个可用于内部通信的别名。

让我们进入books-ms容器,并查看hosts文件。

docker exec -it books-ms cat /etc/hosts

exec命令的输出如下。

10.0.0.2    3166318f0f9c
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.0.2    books-ms-db
10.0.0.2    books-ms-db.my-network

主机文件中有趣的部分是最后两个条目。 泊坞窗检测到的书籍,MS-DB容器使用相同的网络,并通过添加书籍-MS-DB(数据库容器的名称)和书籍-MS-db.my网络数据库容器(名称更新hosts文件加网络的名称)别名。 如果使用某种形式的约定,那么对服务进行编码的方式很简单,即它们使用诸如别名之类的别名与位​​于单独容器中的资源(在本例中为数据库)进行通信。

我们还将环境变量DB_HOST传递给book-ms 。 这向我们的服务指示了用于连接数据库的主机。 我们可以通过输出容器的环境看到这一点。

docker exec -it books-ms env

命令的输出如下。

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=eb3443a66355
DB_HOST=books-ms-db
DB_DBNAME=books
DB_COLLECTION=books
HOME=/root

如您所见,环境变量之一是DB_HOST ,其值是books-ms-db

我们现在拥有的是Docker网络,该网络创建了主机别名books-ms-db ,该主机别名指向Docker创建的网络的IP。 我们还有一个环境变量DB_HOST ,其值是books-ms-db 。 服务的代码使用该变量连接到数据库。 您可能使用其他逻辑。 重要的是,Docker使用别名来更新主机文件,该别名可用于访问属于同一覆盖网络的任何其他容器。

与运行create network命令相比,还有一种更好的方法来创建网络 。 在尝试之前,让我们停止这两个容器并删除网络。

docker rm -f books-ms books-ms-db

docker network rm my-network

这次,我们将通过Docker Compose运行容器。 尽管我们可以在docker-compose.yml中使用net参数,从而执行与之前完全相同的过程,但是最好使用新的Docker Compose参数–x-networking

cd /vagrant/booksms

docker-compose --x-networking up -d db app

我们刚刚运行的命令的输出如下。

Creating network "booksms" with driver "None"
Creating booksms_app_1
Creating books-ms-db

在创建服务应用程序数据库之前 ,Docker创建了一个名为booksms的新网络。 网络的名称与项目的名称相同(默认为目录名称)。

我们可以通过运行docker network ls命令来确认该网络已创建。

docker network ls

输出如下。

NETWORK ID          NAME                           DRIVER
6e5f816d4800        swarm-node-1/host              host
aa1ccdaefd70        swarm-node-2/docker_gwbridge   bridge
cd8b1c3d9be5        swarm-node-2/none              null
ebcc040e5c0c        swarm-node-1/bridge            bridge
6768bad8b390        swarm-node-1/docker_gwbridge   bridge
8ebdbd3de5a6        swarm-node-1/none              null
58a585d09bbc        booksms                        overlay
de4925ea50d1        swarm-node-2/bridge            bridge
2b003ff6e5da        swarm-node-2/host              host

如您所见, 覆盖网络bookms已创建。

我们还可以再次检查容器内的主机文件是否已更新。

docker exec -it booksms_app_1 cat /etc/hosts

输出如下。

10.0.0.2    3166318f0f9c
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.0.3    books-ms-db
10.0.0.3    books-ms-db.my-network

最后,让我们看看Swarm如何分发我们的容器。

docker ps --filter name=books --format "table {{.Names}}"

输出如下。

NAMES
swarm-node-2/books-ms-db
swarm-node-1/booksms_app_1

Swarm将应用程序容器部署到swarm-node-1 ,将db容器部署到swarm-node-2

最后,让我们测试book-ms服务是否正常运行。 我们不知道Swarm将哪个容器部署到了该容器,也不知道哪个端口被暴露。 由于我们还没有代理,因此我们将从Consul检索IP和服务的端口,发送PUT请求以将数据存储到位于不同容器中的数据库,最后发送GET请求检查我们是否可以检索记录。 由于我们没有能够确保将请求重定向到正确的服务器和端口的代理服务,因此我们必须从Consul检索地址和端口。 有关如何设置代理服务的更多信息,请查阅《 使用Docker Swarm扩展到无限》,《 Docker Compose和Consul》一文。

ADDRESS=`curl \
    localhost:8500/v1/catalog/service/books-ms \
    | jq -r '.[0].ServiceAddress + ":" + (.[0].ServicePort | tostring)'`

curl -H 'Content-Type: application/json' -X PUT -d \
  '{"_id": 2,
  "title": "My Second Book",
  "author": "John Doe",
  "description": "A bit better book"}' \
  $ADDRESS/api/v1/books | jq '.'

curl $ADDRESS/api/v1/books | jq '.'

最后的命令输出如下。

[
  {
    "author": "John Doe",
    "title": "My Second Book",
    "_id": 2
  }
]

如果该服务无法与位于其他节点的数据库进行通信,则我们将无法放置或获取数据。 部署到单独服务器的容器之间的网络正常工作! 我们要做的就是在Docker Compose( –x-networking )中使用一个附加参数,并确保服务代码利用了hosts文件中的信息。

Docker网络的另一个优点是,如果一个容器停止工作,我们可以将其重新部署(可能重新部署到单独的服务器上),并且假设使用它的服务可以处理临时连接丢失,则可以继续使用它,就像什么也没发生一样。

Docker网络是人们期待已久的功能,它使我们可以分发容器而不必担心它们是否能够相互通信。 最后,我们可以分发容器而没有引入链接的限制(链接的容器必须在同一服务器上运行)。 不再需要我们某些人过去必须采用的解决方法。 这是一项令人兴奋的功能,可以肯定地使Docker Swarm迈上一个新台阶。

自己试试吧。 研究Docker网络引入的其他选项。 完成后,您可能需要停止我们创建的VM,以便为其他任务释放资源。

exit

vagrant halt

翻译自: https://www.javacodegeeks.com/2015/11/deploying-containers-docker-swarm-docker-networking.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值