下一代集成服务简介及其优势

61 阅读7分钟

长期以来,集成服务一直是Banzai云管道平台的一个关键功能,只需在用户界面上点击几下或从Banzai CLI上发出一条命令,就能使复杂的基础设施组件准备好使用。

一些最重要的集成服务。

  • 监控和日志
  • DNS
  • 秘密管理
  • 漏洞扫描

目前这一代的集成服务已经增加了很多价值。

  • 我们可以通过集成服务API轻松地按需启用和禁用复杂的功能,而无需用户提供任何额外的工具
  • 我们可以一键将这些服务升级到最新版本,只要升级时不需要特别的步骤就可以了
  • 我们可以利用现有的Helm图表,在后台使用Helm库进行部署 image.png

目前的架构和功能为我们提供了很好的服务,但也有一些我们一直想解决的不足之处。

规格和默认 🔗︎

集成服务的配置有两个层次。管道API级别的配置,我们称之为规格,以及部署级别的配置,通常是由规格和一些额外的默认值组成的一组Helm图表值。默认值是好的,因为它使规格更小,对用户来说更容易理解,但没有一组默认值会适合每一种使用情况。我们需要一种方法,让用户在必要时定义并坚持自定义覆盖,但目前这还不可能。

紧密耦合 🔗︎

异步工作流与实际的服务部署实现是紧密耦合的。使用Helm是有好处的,因为我们有现成的包,但是我们在Pipeline中计算实际的Helm图表值,这意味着如果图表版本之间的数值结构发生变化,它就无法兼容。我们可以扩展代码以处理多个图表版本,并理解多个数值方案,但这将要求我们在每次想要增加对新服务版本的支持时都要发布Pipeline。耦合也是另一种方式。集成服务代码不能简单地在任何Kubernetes集群上使用,而该集群必须由Pipeline管理。

状态管理 🔗︎

集成服务的期望状态("规格")被保存在数据库中。由于没有任何东西可以自动调和这个状态,如果有人在后台有意或无意地更新资源,我们可能会出现规格与集群中的实际状态渐行渐远的情况。这种方法的另一个问题是紧耦合,因为没有Pipeline和它的数据库就无法管理服务。

服务版本 🔗︎

为了避免兼容性问题,我们决定当用户启动一个动作(激活、更新或停用一个服务)时,总是将服务更新到实际Pipeline发布的版本中。由于这不是自动的,我们不能保证用户可以干净地升级,如果他们碰巧落后于多个版本。

升级钩和降级 🔗︎

升级并不总是像运行新版本的安装程序来代替旧版本那样简单。有时我们必须删除或修改资源,以便能够安装新版本的服务。例如,Cert manager在从0.13升级到0.14时,要求用户删除其部署。我们还想支持降级,这可能是也可能不是与升级对应的对称性,使事情更加复杂。

下一代的集成服务将如何帮助解决这些问题? 🔗︎

我们要引入的主要变化是将集成服务的配置和部署与规范完全分离。我们通过引入一个外部组件--Kubernetes操作员--来实现这一点,该操作员负责了解如何基于自定义资源来安装服务。操作员通过自定义资源接收所需的服务版本、服务规格和用户的自定义覆盖,并自动持久化,而不需要将其放入数据库。

这种过渡也意味着集成服务将能够独立工作,并由外部管理。用户可以继续使用Pipeline跨供应商配置其集群,并通过Kubernetes自定义资源管理集成服务定义,同时使用他们最喜欢的gitops工具,如ArgoCD

image.png

综合服务运营商 🔗︎

让我们来看看运营商,了解它是如何工作的,更重要的是,它如何解决我们上面强调的问题。

服务安装 🔗︎

与运营商的互动如下:我们通过指定服务的名称创建一个代表我们的服务的资源,运营商会在资源状态中为我们填写可用的版本。

现在我们可以设置所需的服务版本(如果我们知道存在哪些版本,也可以跳过前一步),让运营商为我们安装。我们可以通过它的资源状态跟踪进度。

服务升级 🔗︎

升级有点复杂,因为我们可能要做一些特定的事情才能从版本A升级到版本B。它们可以像修补现有资源一样简单,也可以像备份数据库和应用模式变化一样复杂。

另一个常见的问题是不能在一个步骤中升级多个版本,相反,我们必须走过中间的版本。这是有道理的,因为我们不想支持所有遗留版本的单步升级,所以仅仅依靠一步步的升级。

在内部,我们的服务有安装器和升级器。

  • 安装者知道如何安装一个服务的特定版本。
  • 升级者知道如何从一个版本过渡到另一个版本。

如果我们把这些结合起来,我们就可以计算出具有所有需要的中间环节的可用目标版本。

例如,有三个安装器--A、B、C--和两个升级器--A->B、B->C--我们可以通过两个步骤从A升级到C,A->B->C。

升级器也应该支持降级,这在我们不得不回滚一个变化时非常重要。

但让我们回到与运营商的互动上。一旦有新的运营商出来,了解较新的服务版本,它就会自动用它们的新选项更新所有的资源状态。它还会计算出资源状态中暴露的每个目标版本的升级步骤,这样我们就知道当我们选择其中一个目标时,应该期待什么。

鉴于这一切,一旦我们在集群上升级运营商,所有的服务将自动显示为可升级,以防有新版本可用。

规格 🔗︎

到目前为止,我们已经了解了如何控制服务版本,但另一个重要方面是我们如何管理规格。简而言之:规格是我们服务的部署配置,Pipeline通过服务的自定义资源来验证和控制。我们可以保持规范的模式稳定,不受底层部署配置在服务版本之间如何变化的影响。在内部,操作者理解该规范,并通常从它那里组装图表值,这在以前是Pipeline的责任。

秘密 🔗︎

几乎每个服务都需要秘密。Pipeline有自己的抽象来管理秘密。在幕后,它实际上使用Vault来保护它们的安全。但是,我们如何将它们转移到操作员那里呢?目前的工作方式是,我们将集成服务所需的秘密作为普通的Kubernetes秘密复制到所管理的集群中,并在规范中提供秘密名称,以便运营商可以使用它。

状态管理 🔗︎

还有最后一件事值得了解,那就是这将如何解决前面提到的状态管理和一致性问题。这不是没有代价的,但鉴于我们可以直接在自定义资源上设置规格,并从那里读取状态,我们不需要再把任何东西放入数据库。从这一点上看,被管理的集群是权威的,一个全面的集群备份和恢复解决方案应该可以很好地处理集成服务,而不需要任何额外的努力。

总结 🔗︎

下一代集成服务利用Kubernetes自定义资源定义,在用户需要时给予他们控制权。通过为这些服务开放Kubernetes原生接口,Pipeline可以专注于高水平的抽象和配置,而不被实际执行所束缚。