这一部分,我们让accountservice服务在本地部署的Docker Swarm集群上运行,并探讨容器编排的核心概念。
- 运行基准测试并搜集度量值。
其实这一部分和Go语言没有什么直接关系,具体来说它是关于Docker以及Docker Swarm的。同样希望你能喜欢这篇文章。
在开始实操之前,快速介绍一下容器编排的概念可能会有用。
随着应用程序变得越来越复杂,并且需要处理更高的负载,我们不得不处理这样的一个事实,我们成千上万的服务实例遍布大量物理硬件上。容器编排让我们把所有硬件当作单个逻辑实体看待。
很好,我们现在本地docker镜像仓库包含了名为someprefix/accountservice的映像。 如果我们想要运行多个节点或者想要共享我们的镜像, 我们可以使用docker push来将镜像对其他我们当前Docker引擎提供的host之外的host拉取后可用。
然后我们可以直接通过命令行运行这个映像。
然而请注意,容器不再是运行在你主机OS的localhost了。它现在位于它自己的网络上下文,并且我们不能直接从我们的实际主机操作系统访问。 当然有办法修复,但是我们先不深入下去,我们先对Docker Swarm进行局部设置,并部署accountservice。
我们先使用Ctrl + C终止这个运行的镜像。
本博客的一个目标就是我们想让我们的微服务运行在容器编排上。 对于我们很多人来说,一般意味着Kubernetes或Docker Swarm。 当然也有其他编排器, 例如Apache Mesos和Apcera, 但是本文明确聚焦的是Docker 1.13的Docker Swarm上的。
Docker Swarm集群至少包含一个Swarm管理器和零到多个Swarm worker。 这里为了简单起见,我们只使用一个Swarm管理器 - 这里最少一个。在这节之后,重要的是你需要让Swarm Manager启动并运行起来。
我们这里的例子,使用docker-machine并制作一个虚拟linux机器运行在我们的Swarm管理器的VirtualBox。 这里我们使用"swarm-manager-1"来标示这个管理器。 你也可以参看官方文档看如何创建Swarm。
如果我们需要创建多节点的Swarm集群,我们将确保存储上面命令产生的连接token, 稍后如果我们需要添加额外节点到swarm中。
Docker的覆盖网络是一种当我们给Swarm添加类似"accountservice"到上面的时候使用的一种机制,这样它能访问在同一个Swarm集群中的其他容器,而无需知道实际的集群拓扑结构。
使用下面的命令创建一个网络:这里我们给网络起名为my_network。
下面是参数的快速解释:
- name: 为我们的服务赋予一个逻辑名称。 这个名字也是集群中其他服务用于定址该服务所使用的名字。 因此另外一个服务想要调用accountservice, 那个服务只需要做一个GET请求: :6767/accounts/10001即可。
- replicas: 我们服务想要的实例数目。如果我们Docker Swarm集群是多节点的, swarm引擎将自动在这些节点之间进行分布。
- network: 这里我们告诉服务绑定我们刚才创建的覆盖网络名。
- p: 映射, [内部端口号]:[外部端口号]。 这里我们使用, 但是如果我们使用6767:80,那么我们在外部调用的时候就要通过端口号80进行服务访问。注意这是一种可以让我们服务从集群外部可以到达的一种机制。通常来说,你无需对外暴露服务。而通常,我们会使用边界服务器(例如: 反向代理),这样可以有一些路由规则,并且可以有安全配置,这样外部消费者不能到达你的服务,除非你使用一种自愿的方式。
- someprefix/accountservice: 这个参数指定了我们希望容器运行的映像的名字。在我们这个例子中是我们在创建容器的时候指定的标签。 注意!如果我们要运行多节点集群,我们需要将我们的映像推送到Docker仓库中,例如推送到公共(免费)的Docker Hub服务上。 当然我们也可以设置私有docker仓库,或者付费来保持镜像免费。
就是这样了。运行下面的命令来看我们的服务是否成功启动了。
很甜美。 我们现在可以使用curl或通过浏览器来查询我们的API。唯一需要知道的就是前面是Swarm的公网IP。即便我们在很多节点的swarm中为我们的服务只运行了一个实例, 覆盖网络和Docker Swarm允许我们请求任意的swarm主机基于端口号来访问服务。也就是说,两个服务在外部不能使用同一端口号暴露。 他们内部端口号可以相同, 但是对外来说必须唯一。
无论如何,请记住我们之前保存的环境变量ManagerIP的值。
如果已经改变了终端会话,可以重新导出它。
使用docker的命令行API来检查Swarm的状态是完全可行的(docker service ls), 但是使用更加图形化的呈现,看起来更有意思。 例如可视化的有, 我们同样可以像部署刚才accountservice服务一样的方式部署这个可视化服务工具。 这样我们可以有另外一种方式来查看我们的集群拓扑结构。 也可以用于确保集群中我们是否让某个服务暴露到给定端口号。
我们可以从预烘培的容器镜像来安装visualizer, 就一行命令:
我也开发了一个小的Swarm可视化器,叫做dvizz, 使用的是Go语言、Docker Remote API和D3.js产生图形。 同样可以使用下面的命令安装这个服务:
看起来有点潦草, 但是不要太认真,它还是非常有趣的, 看看涂上蹦蹦跳跳、上下缩放服务器、随意拖放每个节点。
微服务领域现在只有一个服务(我们普遍存在的accountservice)。 下面我们部署一个前面提到的Spring Boot类型的微服务"Quotes-service", 这个微服务我已经放在公共的Docker仓库中,可以直接部署它。
如果使用docker ps来列举运行的Docker容器,我们可能会看到它已经启动了(或正在启动中)。
注意这里我们没有导出这个服务的端口映射,意味着它不能从集群外部访问,只有内部通过内部端口8080访问。 我们会在后面第七部分服务发现和负载均衡中来集成这个服务。
如果你已经在集群中添加了dvizz服务,你会看到图中会多出一个quotes-service。
要简化事情,我们可以添加一个shell脚本来帮我们做重新构建和重新部署的自动化工作。在goblog的根目录下面,创建一个copyall.sh文件:
这个脚本设置了GOOS环境变量,这样我们可以安全的为Linux/AMD64架构构建静态链接二进制文件, 然后运行一些docker命令来重新构建映像文件以及重新部署到Swarm服务里边。 可以节约时间,并且少输入很多字母。
Go语言项目的构建,我不在本文中深入介绍。 个人认为,我喜欢shell脚本的简洁,虽然我自己也经常使用gradle插件,并且也知道一个好的ol的make也是相当流行。
从现在起,所有的基准测试和搜集CPU/内存度量将用于Docker Swarm中部署的服务。 这意味着之前的文章结果和现在开始之后的结果不可比。
CPU使用和内存使用将使用Docker stats搜集,同时我们会使用之前使用的Gatling测试。
如果你自己运行负载测试, 那么在第二部分引入的要求依然适用。 请注意,需要修改baseUrl参数为Swarm Manager节点的IP, 例如:
到目前为止,我们已经学到如何在本地启动Docker Swarm领域(只有一个节点), 以及如何打包和部署我们的accountservice微服务作为Docker Swarm的服务。
下一节,我们会给我们的微服务添加心跳检查。