我们将云操作移至Kubernetes操作员
#go #kubernetes #infrastructure #questdb
如今,

kubernetes运营商似乎无处不在。其中数百个可在您的群集中安装。运营商管理从X.509证书到企业-Y数据库部署,服务网格和监视堆栈的所有内容。但是,为什么还为许多人说已经令人费解的系统添加更复杂性呢?使用控制集群资源的操作员,如果您有一个错误,您现在遇到了两个问题:弄清楚众多的Kubernetes原始人正在引起问题,并了解该Dang操作员如何为问题做出贡献!

因此,当我提出将定制运营商引入我们的云基础架构堆栈中的想法时,我知道我必须真正出售它作为对公司的真正好处,所以人们不会认为我在花费我的花费在RDD蒸气软件上的时间。批准开始该项目后,我花了几天的时间学习了Kubernetes内部内容,搜寻互联网和广泛地寻找有关操作员开发的内容,并撰写(并重写)成为我们的QuestDB Cloud Operator的基础。

经过数月的努力,我们终于将这个Kubernetes运营商部署到了我们的生产云中。在我们现有的“单次滚动”配置模型的基础上,操作员添加了新功能,使我们能够执行复杂的操作,例如自动从节点失败中恢复,并且还将策划即将到来的QuestDB Enterprise功能,例如高可用性和诸如高可用性和冷藏。

如果我们正确地完成了工作,您作为当前或潜在的最终用户将继续享受不断增长的QUESTDB部署的稳定性和轻松管理,而不会注意到单一的差异。这是我们如何完成这项工程专长的故事,以及为什么我们首先做到了。

原始系统体系结构

为了管理云中的客户实例,我们使用基于队列的系统,该系统能够使用简单地称为“ Provisioner”的集中式控制平面在不同的AWS帐户和区域中提供数据库。

Provisioner Architecture

当用户在QuestDB云中创建,修改或删除数据库时,应用程序后端服务器异步发送了一个将更改描述为后端工作的消息,然后将该消息附加到Kafka日志上。每个消息都包含有关目标数据库(其唯一标识符,常驻群集以及有关其配置,运行时和存储的信息)以及要执行的特定操作集的信息。

这些教学消息被许多供应者工人之一接收,每个人都订阅了特定的Kafka日志分区。一旦提供者工人收到一条消息,它将被解码,并在同一过程中执行其说明。指令根据需要执行的特定操作而有所不同。这些范围从简单任务(例如应用程序级重新启动)到更复杂的任务,例如用户想要暂停一个活动实例以节省未使用资源的成本,例如拆除基础数据库的节点。

每个高级指令都分解为较小的可组合颗粒任务。因此,供应商以相对较低的水平协调资源,明确管理K8S原始词,例如州企业,部署,入口,服务和PersistentVolumes,以及EC2实例,安全组,Route Groups,Route 53 Records和EBS卷(EBS)等AWS资源。

通过单独的Kafka队列将准备进度报告回该应用程序(我们将其称为“八卦”队列)。接收到新信息时,后端工人正在收听此队列以获取新消息,并在我们的后端数据库中更新客户数据库的状态。

Provisioner Flowchart

每个颗粒状操作还具有相应的回滚过程,以防配置者在运行一组命令时出现错误。这些回滚旨在将目标数据库的基础结构保持在一致的状态,尽管重要的是要注意,这不是最终用户的操作所预期的所需状态。一旦遇到错误并执行回滚,将通过八卦Kafka队列通知后端有关原始错误的通知,以便将任何相关信息归还给最终用户。我们的内部监视系统还将触发这些错误的警报,以便呼叫工程师可以调查问题并开始适当的补救步骤。

自从我们first launched our public cloud offering以来,该系统在过去几个月中已被证明是可靠的,但该框架仍然留出了改进的空间。我们最近的大部分数据库开发工作涉及高可用性和冷藏都需要为我们现有系统添加更多基础架构组件。并将新组件添加到任何分布式系统中倾向于提高系统的总错误率。

随着我们继续增加基础架构的复杂性,上述回滚策略的风险不足以从新的错误类别中恢复。我们需要一个更响应和动态的供应系统,该系统可以自动响应故障并采取主动的补救措施,而不是触发警报并有可能唤醒我们全球分配的工程师之一。

这是Kubernetes操作员可以拿起松弛并改善我们现有的基础设施自动化的地方。

引入Kubernetes操作员

既然状态工作负载已经开始在Kubernetes生态系统中成熟,从业人员正在编写操作员来自动化这些工作负载的管理。处理全面任务的运营商,例如配置,快照,迁移和升级的集群数据库系统,已开始成为整个行业的主流。

这些运营商包括定义新类型的Kubernetes API资源的自定义资源定义(CRD),这些资源描述了如何管理每个特定数据库系统的复杂性。然后,由这些CRD创建自定义资源(CRS),这些CRD有效地定义了特定数据库资源的预期状态。 CRS由操作员控制器部署管理,这些部署协调各种Kubernetes原始图,以根据CR清单将群集状态迁移到其所需状态。

Operator Terminology

我相信,通过编写我们自己的Kubernetes运营商,我们可以通过允许Provisioner只专注于高级任务来利用此模型,而操作员则处理管理每个客户数据库的细节细节。由于操作员通过资源手表直接挂在Kubernetes API服务器上,因此它可以立即对群集状态的变化做出反应,并不断调和集群资源,以实现由自定义资源规范描述的所需状态。这使我们能够自动化更多的基础架构管理,因为控制平面一直在有效地运行,而不仅仅是在明确的配置操作中。

通过部署在我们的群集之一中的操作员,我们现在可以通过针对单个资源执行API调用和CRUD操作来与客户数据库进行交互,这是一个新的自定义资源定义,代表整个QUESTDB云部署。该CRD允许我们维护一个中央kubernetes对象,该对象代表客户群集中客户QUESTDB数据库部署的整个状态的规范版本。它包括诸如数据库版本,实例类型,音量大小,服务器配置和基础节点映像等字段,以及诸如节点的IP地址和DNS记录信息之类的关键状态。基于这些规格字段值以及对它们的更改,操作员对所有相关的kubernetes和aws primitives进行了连续的对帐,以匹配高级QuestDB构造的预期状态。

新体系结构

这使我们进入了我们的新体系结构:

Operator Architecture

此图类似于旧图,但这里有一个钥匙差。 QUESTDB运算符实例现在在每个群集内部运行!现在,它仅负责修改单个对象:QUESTDB自定义资源,而不是对所有低级Kubernetes和AWS构建块负责供应商负责。可以通过更改描述整个部署的所需状态的单个清单来对QUESTDB部署状态进行任何修改。

该解决方案仍然使用供应商,但容量比以前更有限。供应商继续充当应用程序与每个租户集群之间的通信链接,并且仍负责协调高级操作。但是,它现在可以将低级数据库管理职责委托给操作员不断运行的对帐循环。

操作员的好处

自动修复

由于运算符模型最终是一致的,因此面对错误,我们不再需要依靠回滚。相反,如果操作员遇到其对帐循环中的错误,则默认情况下使用指数退回。

操作员已注册到集群中所有QuestDB及其子组件中的所有QuestDB的资源手表。因此,这些组件中的任何一个或QUESTDB规格本身的更改都会触发操作员内部的对帐循环。如果组件意外变异或经历某些状态漂移,则将立即通知操作员此更改,并自动尝试将其余基础设施带到其所需状态。

此属性对我们非常有用,因为我们为每个数据库提供一个专用节点,并结合使用污点和nodeSelectors来确保所有部署的POD都在此单个节点上运行。由于这些设计选择,我们现在面临无法访问的节点硬件故障的风险。典型的kubernetes恢复模式无法拯救我们。

因此,不用使用警报 - 先进的补救范围,在收到警报后,呼叫工程师会在该数据库下降之后关注运行手册,而是允许我们编写自定义节点的节点故障转移逻辑,该逻辑在该数据库后立即触发。群集知道一个反应式节点。现在,我们的工程师可以在整个晚上睡觉,而操作员会自动执行以前负责的补救步骤。

更简单的配置

而不是必须在典型操作中协调数十个单个对象,而是在执行更高级别的指令时只需修改单个kubernetes对象即可。这大大降低了Provisioner Codebase内部的代码复杂性,使我们更容易编写单元和集成测试。呼叫工程师也更容易快速诊断和解决客户数据库的问题,因为有关特定数据库的所有相关信息都包含在单个Kubernetes Spec Spectest中,而不是在每个命名空间内的各种资源类型中分布。虽然,正如前几点所示,希望我们的待命工程师首先要解决的问题更少!

更容易升级

15周的Kubernetes释放Cadence可能会使较小的基础设施团队保持最重要的责任。这个相对较快的时间表,加上每个发行版的短寿命,这意味着对组织保持群集的最新时间至关重要。如果您不运行自己的控制平面,那么这将被放大,因为供应商往往会很快放弃对旧K8S版本的支持。

EKS End Of Life Schedule

由于我们在每个数据库自己的节点上运行每个数据库,而且我们只有两个可以管理整个QuestDB云基础架构,因此我们可以轻松地花费大部分时间将客户数据库节点升级到新的Kubernetes版本。相反,我们的操作员现在允许我们自动执行接近零下的节点升级,并在CRD上进行单个字段更改。

一旦操作员检测到数据库基础节点映像中的更改,它将处理升级周围的所有编排,包括尽可能长时间保持客户数据库在线并清理升级后的陈旧资源。有了此自动化,我们现在可以针对基础架构的子集进行部分升级,以测试新版本,然后再将其推广到整个群集,并在需要时无缝返回到较旧的节点版本。

控制平面位置

通过部署每个群集操作员,我们可以通过避免从供应商到远程租户群集进行的大多数跨区域来改善供应操作所需的时间。我们只需要通过在QUESTDB规范上执行CRUD操作来启动配置过程,即可启动跨区域的API调用,而本地群集操作员将处理其余的操作。这改善了我们的API呼叫网络延迟和可靠性,减少了任何给定操作以及整体数据库供应时间的重试次数。

资源协调

现在,我们拥有一个Kubernetes资源来代表整个QuestDB部署,我们可以将此资源用作构建更大的抽象的原始资源。例如,现在我们可以轻松地创建一个大量(但临时)的实例来处理大量数据,将数据保存到群集中的persistentVolume,然后旋转另一个较小的数据库以充当查询接口。由于Kubernetes资源的固有合成性,QuestDB自定义资源的可能性无尽!

Devops的东西

测试操作员

在我们的堆栈中部署如此重要的软件之前,我想对其行为和运行时特征尽可能自信,然后才使其在我们的群集中疯狂。因此,在我们有足够的信心将新的基础设施部署到开发中,并最终进行生产之前,我们撰写并进行了一系列单位和集成测试。

使用controller-runtime/pkg/envtest库对内存Kubernetes API服务器编写单元测试。 EnvTest允许我们快速迭代,因为我们可以针对新的API群集进行测试,该群集在大约5秒内开始,而不必每次我们想运行测试套件时都需要旋转一个新的群集。即使是Kind(例如Kind)等现有的微群集工具也无法使我们获得这种性能水平。由于EnvTest也未与任何控制器打包,因此我们还可以将测试群集设置为特定状态,并确保除非我们在测试代码中明确进行,否则不会修改该状态。这使我们能够完全测试特定的边缘箱,而不必担心控制平面级的控制器从我们下方修改各种对象。

但是单位测试是不够的,尤其是因为我们操纵的许多原始词本身都是相当高的抽象。因此,我们还旋转了一个测试EKS群集,以与我们的开发和生产环境相同的表现进行实时测试。该集群允许我们使用Live AWS和K8S API进行测试,并且在测试Node恢复和升级等测试功能时是不可或缺的。

我们还能够利用Ginkgo的并行测试运行时来运行我们在多个并发过程的集成测试。这提供了多个好处:我们可以在10分钟内运行整个集成测试套件,并重复使用相同的套件以在类似生产的环境中加载操作员。使用这些测试,我们能够识别代码中需要进一步优化的热点,并尝试节省API调用以减轻我们自己的Kubernetes API服务器的负载,同时也保持在各种AWS速率限制下。直到一遍又一遍地进行这些测试之后,我才感到有信心将操作员部署到我们的开发人员和产品簇中。

监视

由于我们使用Kubebuilder framework构建了操作员,因此在开箱即用的情况下为我们处理了大多数标准的监视任务。我们的操作员会自动揭示一组丰富的普罗米修斯指标,以衡量对帐绩效,K8S API调用的数量,工作等级统计和与内存相关的指标。我们能够通过利用grafana/v1-alpha plugin将这些指标摄入预建的仪表板,该仪表板脚手架脚手架脚手架以监视操作员资源的使用和性能。我们要做的就是将它们添加到我们现有的Grafana表现中,我们很高兴!

迁移到新范式

没有关于从旧到新的迁移策略的讨论,就没有关于大型基础设施变更的文章是完整的。在我们的情况下,我们将操作员设计为供应商管理的数据库实例的撤销删除。这涉及许多乏味的YAML表现出来,以确保操作员协调的资源将与我们集群中的资源相匹配。

达到了此资源奇偶校验后,我们使用Kubernetes所有者依赖性关系来在每个子资源中创建所有者参考,指向新的QuestDB自定义资源。和解循环的一部分涉及确保这些所有权参考已就位,如果没有,则会自动创建。这样,操作员可以通过其主要的对帐编码器无缝“继承”遗产资源。

由于操作员无法对QuestDB CR拥有的资源进行任何更改,因此我们能够逐步推出。由于具有此属性,我们可以创建一个QuestDB CR,并仅在与该数据库关联的群集资源上监视操作员的行为。一旦一切表现为预期,我们就开始推出其他自定义资源。这很容易在供应者方面控制​​;通过检查给定数据库的QUESTDB CR存在。如果CR存在,那么我们可以确定我们正在与操作员管理的实例打交道,否则该提供者将像操作员存在之前一样行事。

结论

我为我们为这个项目所做的辛勤工作感到自豪。从一个空的git仓库开始,到这里是一段漫长的旅程。在过去的几个月中,我曾多次询问所有这些工作是否值得遇到麻烦,尤其是因为我们已经有了在生产中进行战斗测试的供应系统。但是,在我的同事的支持下,我一直到最后。我绝对可以说这是值得的,因为我们已经看到了转向这种新范式的直接好处!

使用我们的QuestDB CR作为构建块为新功能铺平了道路,例如使用我们的SQL COPY command添加大型散装CSV上传。新的节点升级过程将在每个新的K8版本中节省我们无数小时。即使我们还没有经历过硬件故障,我也相信我们的新运营商也会无缝处理这种情况,而无需对待呼叫工程师。尤其是由于我们是一个小团队,对于我们来说,使用自动化作为一种​​力量 - 武器,可以帮助我们管理云基础架构,而Kubernetes运营商为我们提供了以前无法实现的下一级自动化。


确定最佳拟合的最佳方法是通过自己的数据使其真实。 QuestDB Cloud提供200美元的免费信贷。或者,如果您宁愿先使用示例数据,请查看我们的live Web Console