我们使用HashiCorp Nomad

2020-06-06 23:39:03

在这篇博客文章中,我们将带您了解在全球200多个边缘城市运行的服务的可靠性模型。然后,我们将介绍部署新的动态任务调度系统HashiCorp Nomad如何帮助我们提高每个数据中心的服务可用性,包括我们如何部署Nomad以及我们在此过程中克服的挑战。最后,我们将向您展示我们目前如何使用Nomad,以及我们计划如何在未来使用它。

对于这篇博客文章,我们将区分每个数据中心中运行的两种不同类别的服务:

面向客户的服务:我们客户使用的所有堆栈产品,如缓存、网站管家、DDoS防护、限速、负载均衡等。

管理服务:运行数据中心所需的软件,不在客户流量的直接请求路径中。

我们面向客户的服务的可靠性模型是在每个数据中心的所有机器上运行它们。这很有效,因为它允许通过添加更多机器来动态扩展每个数据中心的容量。

由于我们在每台机器上运行的动态负载平衡系统Unimog,扩展变得特别容易。它的作用是根据当前资源使用情况不断重新平衡流量,并检查服务的运行状况。这有助于提供对单个机器故障的恢复能力,并确保所有机器上的资源使用率几乎相同。

例如,这里是我们的一个数据中心一天的CPU使用率,其中每个时间序列代表一台机器,不同的颜色代表不同代的硬件。Unimog使所有处理流量的机器保持大致相同的CPU利用率。

我们的一些大型数据中心拥有大量机器,但有时我们需要在每个位置可靠地运行管理服务的单个或几个实例。

目前有几个选项可以做到这一点,每个选项都有自己的优缺点:

将服务部署到数据中心的所有计算机:缺点:它不必要地使用了本可以用于服务客户流量的资源,而且不划算。

将服务部署到每个数据中心的几台静态计算机上:缺点:当这些几台计算机意外故障时,它会面临服务不可用的风险。

第三个更可行的选择是使用动态任务调度,以便在确保可靠性的同时只使用适量的资源。

对于我们希望在每个数据中心运行的管理服务,必须在两个不太理想的可靠性模型选项之间进行选择,这并不理想。

事实上,其中一些服务,即使它们不在请求路径中,也需要继续运行数据中心。如果运行这些服务的计算机变得不可用,在某些情况下,我们必须在恢复它们时临时禁用数据中心。这样做会自动将用户重新路由到下一个可用的数据中心,并且不会造成中断。事实上,整个Cloudflare网络设计为在数据中心被禁用和自动恢复的情况下运行。但是,最好将最终用户路由到他们附近的数据中心,因此我们希望最大限度地减少任何数据中心级别的停机时间。

这让我们意识到,我们需要一个系统来确保在每个数据中心中运行一定数量的服务实例,而不管最终运行该服务的是哪台物理机。

面向客户的服务在每个数据中心的所有机器上运行,不需要登录到该新系统。另一方面,当前在具有次优可靠性保证的固定机器子集上运行的服务和不需要在所有机器上运行的服务都是很好的入职候选。

虽然Kubernetes是另一个选择,但我们决定使用HashiCorp的Nomad,原因如下:

满足了我们最初的要求,即在每个数据中心可靠地运行资源隔离的二进制文件的单个实例。

几乎没有依赖关系,并且与领事直接集成。Consul是我们已经在每个数据中心部署的另一款HashiCorp软件。它提供分布式键值存储和服务发现功能。

轻量级(一站式二进制),易于部署和调配新群集,这在部署与我们拥有的数据中心一样多的群集时是一个优势。

具有模块化任务驱动程序(部分负责执行任务和提供资源隔离)架构,不仅支持容器,还支持二进制文件和任何自定义任务驱动程序。

是开源的,并且是用Go编写的。我们在团队中有围棋语言的经验,而且Nomad在GitHub上有一个响应迅速的维护人员社区。

Nomad Server:组成集群的实例负责调度,每个数据中心5个,以提供足够的容错能力。

Nomad Client:执行实际任务的实例,在每个数据中心的所有机器上运行

为了保证Nomad Server集群的可靠性,我们在属于不同故障域的计算机上部署了实例:

在不同的多节点机箱中(我们的大多数边缘硬件都以多节点机箱的形式提供,一个机箱包含四个单独的服务器)。

我们还向我们的配置管理工具添加了逻辑,以确保我们始终保持一致数量的Nomad Server实例,而不管服务器几乎每天都在进行扩展和退役。

逻辑相当简单,随着服务器扩展和退役的发生,Nomad Server角色被重新分配到新的机器列表。然后,我们的配置管理工具确保Nomad Server在旧机器上关闭之前在新机器上运行。

此外,由于服务器扩展和退役一次影响机架的一个子集,并且Nomad Server角色分配逻辑提供机架多样性保证,因此群集始终保持正常运行。

Nomad作业文件被模板化并签入到git存储库中。然后,我们的配置管理工具可确保在每个数据中心安排作业。从那时起,Nomad将接管并确保作业在每个数据中心的所有时间都在运行。

通过向每个Nomad客户端公开机架元数据,我们能够确保特定服务的每个实例在不同的机架上运行,并且绑定到不同的故障域。这样,我们可以确保一个服务器机架的故障不会影响服务运行状况,因为服务也在不同的机架上运行,不受故障的影响。

我们利用Nomad与Consul的集成将Nomad作业动态添加到Consul Service Catalog。这允许我们通过查询Consul来发现特定服务当前在每个数据中心的何处运行。此外,启用Consul DNS接口后,我们还可以使用基于DNS的查找来定位在Nomad上运行的服务。

为了能够正确运行与我们拥有的数据中心一样多的Nomad集群,在这些集群上运行的Nomad集群和服务上具有良好的可观察性是至关重要的。

我们使用普罗米修斯抓取每个数据中心中运行的Nomad Server和客户端实例,并使用AlertManager对关键指标发出警报。使用普罗米修斯指标,我们构建了Grafana仪表板来提供每个集群的可见性。

我们设置Prometheus实例以发现在Nomad上运行的服务,方法是使用以下Prometheus配置查询Consul Service Directory并定期抓取它们的指标:

-consul_sd_configs:-server:localhost:8500作业名称:management_service_via_consul reabel_configs:-action:Keep regex:management-service source_labels:-__META_CONSUL_SERVICE。

然后,我们使用这些指标来创建Grafana仪表板,并为在Nomad上运行的服务设置警报。

为了限制对Nomad API端点的访问,我们启用了相互TLS身份验证,并为与Nomad交互的每个实体生成客户端证书。这样,只有拥有有效客户端证书的实体才能与Nomad API端点交互,以便安排作业或执行任何CLI操作。

部署新组件总是伴随着一系列挑战;下面列出了我们在此过程中必须克服的几个障碍。

当开始使用exec驱动程序运行chroot环境中隔离的二进制文件时,我们注意到在initramfs上运行的无状态根分区不受支持,因为任务不会启动,并且我们在日志中收到以下错误消息:

2月12日19:49:03机器游牧-客户端[258433]:2020-02-12T19:49:03.332Z[错误]client.alloc_runner.task_runner:运行驱动程序失败:alloc_id=fa202-63b-33f-924-42cbd5 task=server error=";无法使用Executor启动命令:rpc错误:code=未知desc=CONTAINER_linux.go:346:启动容器进程导致&。PIVOT_ROOT无效参数\";\";";";

我们提交了GitHub问题并提交了变通拉取请求,该请求被及时审查并合并到上游。

同时,为了最大限度地提高隔离安全性,我们通过修改引导过程在我们的设置中启用了PIVOT_ROOT,其他团队成员开发并提出了内核邮件列表的补丁,以使其在将来更容易实现。

一个非常重要的方面是确保在Nomad上运行的任务的资源使用不会中断同一台机器上托管的其他服务。

磁盘空间是每台机器上的共享资源,必须能够为Nomad设置配额。我们通过将Nomad数据目录隔离到每台机器上的专用固定大小挂载点来实现这一点。但是,Nomad目前不支持开箱即用的磁盘带宽和IOPS限制。

Nomad作业文件有一个可以限制内存和CPU使用的资源部分(内存以MB为单位,CPU以MHz为单位):

这在幕后使用cgroup,我们的测试表明,虽然内存限制是按照预期实施的,但CPU限制是软限制,只要主机上有可用的CPU,就不会强制实施。

如上所述,所有机器当前都运行相同的面向客户的工作负载。使用Nomad动态调度单个作业以在单机上运行,挑战了这一假设。

虽然我们的动态负载平衡系统Unimog会根据资源使用情况平衡请求,以确保它在所有机器上几乎相同,但是资源使用高峰的批处理类型作业可能会带来挑战。

确保Unimog调整以适应此批处理类型的工作负载,并且不会最终陷入正反馈循环。

现在,每个数据中心都部署了Nomad,我们能够通过逐步自注册来提高运营所必需的管理服务的可靠性。我们迈出了第一步,加入了我们的重启和维护管理服务。

在每个数据中心,我们都运行一项服务,促进机器的在线无人值守滚动重启和维护。此服务过去在每个数据中心的一台知名计算机上运行。这使得它容易受到单机故障的影响,并且在停机时会阻止计算机在重新启动后自动启用。因此,登上Nomad以提高其可靠性是一项伟大的第一项服务。

我们现在可以保证此服务在每个数据中心始终运行,而不受单个机器故障的影响。现在,其他机器不再依赖于众所周知的地址来定位此服务,而是查询Consul DNS并动态计算出服务正在运行的位置以与其交互。

就这项服务的可靠性而言,这是一个很大的改进,因此,在接下来的几个月里,预计会有更多的管理服务相继出现,我们对此感到非常兴奋。

边缘可靠性可用性游牧调度