使用 MCollective 进行编排,第二部分
在我的上一篇文章中,我介绍了如何使用 MCollective 进行通用编排任务。像 Puppet 和 Chef 这样的配置管理工具可以帮助您从头开始引导服务器并推送新版本的配置文件,但通常,配置管理脚本在特定的时间运行,并且没有特定的顺序。当您需要执行某种任务时,特别是像软件升级这样的任务,并且需要按一定的顺序执行并在出现问题时停止升级时,就需要编排。借助像 MCollective、Ansible 甚至 SSH for 循环这样的编排软件,您可以从中心位置启动命令,并在特定的服务器集上运行它们。
尽管我更喜欢 MCollective,因为它与替代方案相比具有改进的安全模型,并且与 Puppet 集成,但我在这里讨论的所有内容都应该是您可以适应任何不错的编排工具的内容。
因此,在本文中,我扩展了上一篇关于 MCollective 的文章,并描述了如何使用它来分阶段执行您通常手动运行的所有命令,以将内部软件更新部署到应用程序服务器。
我在关于 MCollective 的第一部分结尾描述了如何使用它将 OpenSSL 更新推送到您的环境,然后重启 nginx
mco package openssl update
mco service nginx restart
在本例中,我对环境中的每台服务器运行了这些命令;但是,您可能需要使用某种 MCollective 过滤器来仅在部分基础设施上重启 nginx。在我的例子中,我创建了一个名为 hagroup 的自定义 Puppet fact,并将我的服务器分成三个不同的组,分别标记为 a、b 和 c,并沿容错线划分。有了这个自定义 fact,我可以一次仅在一组服务器上重启 nginx
mco service nginx restart -W hagroup=c
这种方法对于部署 OpenSSL 更新非常有用,但幸运的是,如果您幸运的话,这些更新每年只会发生几次。您更有可能遇到的,并且非常适合编排的常见任务是将您自己的内部软件部署到应用程序服务器。尽管每个人都以略有不同的方式执行此操作,但以下模式非常常见。此模式基于您拥有冗余、容错的应用程序,并且可以使任何单个服务器离线进行软件更新的假设。这意味着您使用某种负载均衡器来检查应用程序服务器的健康状况,并将不健康的服务器移出轮换。在这种环境中,一个简单的串行更新方法可能如下所示
-
获取运行该应用程序的所有服务器的列表。
-
从列表中的第一台服务器开始。
-
在您的监控系统中为该服务器设置一个短暂的维护窗口。
-
告诉您的负载均衡器耗尽任何到此服务器的现有会话。
-
更新该服务器的可用软件包列表。
-
停止该服务器上的服务。
-
更新该服务器上的软件。
-
启动该服务器上的服务。
-
确保服务已成功启动。
-
执行健康检查以确保服务健康。
-
将服务器添加回负载均衡器轮换。
-
对列表中的其余服务器重复执行。
如果这些步骤中的任何一个失败,管理员将停止更新并调查和修复问题。通常,如果将要发生故障,那将在软件更新或健康检查阶段,此过程的目的是确保如果升级不顺利,您可以在将损坏的软件推送到其余环境之前在第一台服务器上停止。
传统上,管理员可能会手动执行上述所有步骤,方法是登录到不同的服务器并与不同的 Web 界面进行交互。他们接下来通常遵循的步骤是将一系列 SSH 命令包装到一个 shell 脚本中,该脚本将执行这些操作,然后维护一些本地配置文件,这些文件定义了服务器列表。
使用 MCollective,该过程类似,主要区别在于 MCollective 不需要拥有这些机器上的 SSH root 权限。相反,MCollective 通过将一组有限的命令放入所有服务器都检查的作业队列中来执行其任务。这些命令受到您在特定服务器上安装的 MCollective 插件的限制,并且 MCollective 在清理其默认包含的插件的输入方面做得很好。
部署列表中的上述大多数命令都可以使用 MCollective 包含的默认插件完成。我使用 Nagios 进行监控,尽管 MCollective 确实包含一个插件,允许您执行 NRPE 命令(一个 Nagios 代理,它在每台服务器上运行,允许 Nagios 运行本地命令来检查磁盘空间、RAM 等),但它不包含任何可以直接在 Nagios 中设置维护模式的功能。
上述命令列表中缺少的另一个部分是与负载均衡器交互的能力。现在很多人可能会跳过这一步,因为他们正在使用像 nginx 的内部负载均衡能力之类的东西,并且可能没有简单的方法来设置像维护模式这样的东西来耗尽到主机的现有连接。在这种情况下,您可以直接跳到停止服务,并让健康检查检测到故障。但是,这种方法有丢失现有连接的风险,而且因为我使用 Haproxy 作为我的负载均衡器,所以我可以使用其内置的命令模式来在特定的服务器上设置维护模式,如果我登录到负载均衡器。
幸运的是,MCollective 能够使用您自己的自定义插件扩展其现有的命令集以执行特定任务。不幸的是,即使是编写、打包和部署简单的 MCollective 插件,在您第一次执行时也可能有点复杂,而且它足够复杂,需要一篇专门的文章来介绍。MCollective 的插件文档是一个很好的起点,特别是关于编写使用 MCollective 的 RPC 框架的插件的文档,它使您必须编写的代码更加直接,即使您不熟悉 Ruby。
当您编写自定义 MCollective 插件时,您选择一个新的插件名称(例如,haproxy),然后定义您想要传递给新插件的命令列表(例如 disable_server
和 enable_server
)。如果命令需要传递某种参数,您还需要定义这些参数。然后,您使用它们的 RPC 框架将这些命令和参数映射到基本的命令行命令,或者如果您熟悉 Ruby,您可以深入研究使用原生 Ruby 库。
我编写了一个自定义的 Nagios 插件和一个 Haproxy 插件,它们会将我的自定义命令分别发送到它们的命令文件和命令套接字。因此,要在 server1.example.com 上为 Nagios 和 Haproxy 设置维护模式,我将输入以下命令
mco rpc nagios maintenance server=server1.example.com duration=5m
mco rpc haproxy disable_server server="serverrole/server1"
因为我利用了 MCollective 的 RPC 框架,所以我必须在我的自定义命令前面键入 rpc
。
接下来我提供我的插件的名称,然后是我想要运行的命令,然后是任何自定义参数。然后在 Nagios 服务器端,我拦截该命令并将其格式化为我可以写入 Nagios 本地命令文件的格式,以便它可以执行。在 Haproxy 插件的情况下,此命令会发送到碰巧正在运行 Haproxy 的任何服务器。如果特定的 Haproxy 服务器在其配置中没有定义我的服务器,它不会做任何有害的事情,否则,它会将其设置为维护模式。
有了这些插件,您可以将上述通用步骤列表替换为特定的 MCollective 命令
-
mco find -S "domain=example.com and resource('Package[myapp]).managed=true"
-
mco rpc nagios maintenance server=myapp1.example.com duration=5m
-
mco rpc haproxy disable_server server="myapp/myapp1"
-
mco rpc package apt_update -I myapp1.example.com
-
mco service myapp stop -I myapp1.example.com
-
mco package myapp update -I -I myapp1.example.com
-
mco service myapp start -I myapp1.example.com
-
mco service myapp status -I myapp1.example.com
-
mco nrpe check_app_health -I myapp1.example.com
-
mco rpc haproxy enable_server server="myapp/myapp1"
我最终将所有这些命令包装在一个基本的 shell 脚本中,该脚本将特定应用程序的名称作为参数,然后执行第一个 mco find
命令以获取已安装该软件包的服务器列表。然后在这一点上,我只是在一个基本的 for
循环中运行下一组命令。在适当的地方,我在这里和那里添加了一个 sleep
命令,以便给服务一些时间来启动。如果任何命令失败,脚本将退出并报告错误,以便管理员可以进行调查。否则,它将按顺序遍历每台服务器。
当然,此脚本的更高版本变得更加复杂,因此它可以接受一些自定义参数,将输出记录到已知的日志文件中,并且在命令之间休眠的效率更高。但对于系统管理员来说,最终结果是一个简单的“deployapp”脚本,他们可以运行该脚本,以正确的方式,每次都正确地更新应用程序,而不会有跳过或忘记服务器或过程中步骤的风险。