可以通过查看将有状态服务部署为任何其他服务时会发生什么来开始探索Swarm集群中的有状态服务。
Jenkins就是一个很好的例子。我们创建的每个作业都是一个XML文件,安装的每个插件都是一个HPI文件,每个配置的更改都保存为XML。你获得了一个印象。我们在Jenkins中做的每一件事最后都是文件,所有这些文件组成了它的状态。没有这些文件,Jenkins就不能运行。Jenkins也是我们在遗留应用中遇到问题的一个很好的例子。如果今天设计它,那么它可能会使用一个数据库来存储它的状态。还将允许我们扩展它,因为所有的实例都将通过连接到同一个数据库来共享相同的状态。如果今天从零开始设计它,那么可能会做出很多其他的设计选择。作为遗留(应用/系统)不一定是坏事。当然,今天拥有的经验将帮助我们避免过去的一些陷阱。另一方面,长期使用意味着它是经过了实战检验的,有很高的使用率,有大量的贡献者,有大量的用户,等等。每件事都是一种妥协,我们不可能拥有一切。
对于一个成熟的、经过实战检验的应用,与年轻的、现代的但往往未经验证的应用,我们先不去比较它们的利弊。相反,让我们看一下Jenkins作为有状态服务的代表,在使用Terraform创建的Swarm集群中运行时行为是怎样的:
我们输入了其中一个manager并创建了jenkins服务。
请稍候,直到jenkins服务开始运行。可以使用docker service psjenkins检查当前状态。
现在Jenkins正在运行,我们应该在浏览器中打开它:
给Windows用户的说明
Git Bash可能无法使用open命令。如果是这样,则请执行terraform output swarm_manager_1_public_ip来查找manager的IP,并在你选择的浏览器中直接打开URL。例如,上面的命令应该替换为以下命令:
如果输出为1.2.3.4,则应该在浏览器中打开http://1.2.3.4/jenkins。
正如你从第6章中所得知的,我们需要从日志或其文件系统中获取密码。然而,这一次,这样做要复杂一些。Docker Machine将本地(笔记本上的)目录挂载到它创建的每个虚拟机中,这样,我们就可以在不登录虚拟机的情况下得到initialAdminPassword。
至少AWS中还没有这样的东西,所以需要找出哪个EC2实例在运行Jenkins,找到容器的ID,然后登录它来获取文件。这样的事情很容易手工完成,但是,由于我们致力于自动化,所以将使用复杂方法来做这件事。
我们将通过登录其中一个manager并列出服务任务来开始查找密码:
输出如下(为简洁起见,移除了ID和ERROR):
幸运的是,AWS EC2实例在其名称中包含了内部IP。可利用这个优势,代码如下:
我们列出了服务任务,并将其通过管道发送给tail命令,以便只返回最后一行。然后使用awk得到第四列。cut命令打印第四个字节的结果以有效地删除ip-。所有这些都通过管道传输给tr命令替换掉-,最后,结果保存在环境变量JENKINS_IP中。
如果这对你来说太诡异,也可以手工赋值(在我的例子中是172.31.16.159)。
既然知道了运行Jenkins的节点,就需要获取容器的ID。因为我们修改了docker.service配置,允许我们向远程引擎发送命令,所以可以使用-H参数。
获取Jenkins容器ID的命令如下:
可以使用-H告诉本地客户端连接到运行在tcp://$JENKINS_IP:2375中的远程引擎。使用ps命令的安静模式-q列出了所有运行中的容器,因此只返回了ID。还应用了一个过滤器,以便只得到名为Jenkins的服务。结果存储在环境变量JENKINS_ID中。
现在可以使用IP和ID登录容器并输出存储在文件/var/jenkins_home/secrets/ initialAdminPassword中的密码。
在我的例子中,输出如下:
请复制密码,返回到Jenkins UI,并粘贴它。
在继续之前要完成Jenkins的设置。你已经从第6章中了解了使用Jenkins自动化持续部署流程的演练,因此将让你独立进行此操作。
结果应该类似于图14-1中的屏幕。
图14-1 初始设置后的Jenkins主界面
这是一个简单的问题,相信你会知道如何回答。不管出于什么原因,如果Jenkins实例发生了故障,会发生什么?
让我们模拟故障并观察结果:
使用环境变量JENKINS_IP和JENKINS_ID向运行Jenkins的远程节点发送强制删除命令rm-f。(www.xing528.com)
没有什么是永恒的。服务迟早都会有故障。如果服务没有故障,运行它的节点也会有故障。通过删除容器,模拟在现实世界中会发生什么.
经过一段时间后,Swarm会检测到jenkins副本有了故障,并实例化一个新的副本。可以通过列出jenkins任务来确认这一点:
输出如下(为简洁起见,移除了ID):
到现在为止一切正常。Swarm正在做我们想让它做的事情。它确保我们的服务(几乎)总是在运行。
剩下的唯一事情就是返回UI并刷新屏幕。
屏幕应该类似于图14-2中的屏幕。
太尴尬了。失去了我们所做的一切,又回到了起点。因为Jenkins状态没有在容器外持久存在,所以当Swarm创建一个新的Jenkins时,它从一张白纸开始。
如何解决这个问题呢?可以使用哪些方案来解决持久性问题?
请在继续之前删除jenkins服务:
图14-2 Jenkins的初始配置界面
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。