Posted by Hao Liang's Blog on Monday, January 1, 0001

前言 我在2007年加入Google时首次接触到编排器。我的介绍对象不是Borg,而是Ganeti。Ganeti是一个内部开发的集群管理系统,操作在虚拟机上。当时,它是开源版本Xen的一个基本包装器,提供了一个集群解决方案,使我们能够为工程师提供虚拟(而非物理)机器。

我们并没有将Ganeti称为编排器,也没有像谈论Borg那样谈论它。事后看来,我认为将Ganeti视为一种编排器并不算牵强。它不是操作在任务(容器的形式)上,而是操作在虚拟机上。在Google内部,Ganeti充当了从一些工程师可以在物理机器上运行他们的应用程序到每个工程师都在Borg上运行他们的应用程序的桥梁。

几年后,当我们重写用于管理Ganeti集群和虚拟机的生命周期管理系统时,我正式接触到了Borg。我们在Borg上运行它。快进到2020年。COVID大流行爆发了,像其他人一样,我发现自己在家工作。突然间,由于不必通勤到曼哈顿办公室,我每天多了三个多小时。做什么呢?

当然,显而易见的事情是开始某种个人项目。但是什么呢?在与编排器打交道的13年后,我认为从头开始编写一个编排器可能会很有趣。这能有多难呢?

我花了2020年夏天的大部分时间在我的编排器上工作。我将其命名为Cube,以继续星际迷航的主题。令人惊讶的是,我在不到3000行代码中让它工作了。

大约在同一时间,我读了Thorsten Ball的《用Go编写解释器》。虽然我对解释器或编写编程语言并不特别感兴趣,但我对了解它们的工作原理很感兴趣。然后我突然想到!我可以写一本关于用Go编写编排器的书。这将是我在2007年希望拥有的书!于是,这本书诞生了。

在写作过程中,我很早就意识到编排是一个大话题。在谈论编排系统时,很容易被次要问题分散注意力。你如何处理服务发现?你如何处理DNS?共识问题呢?我想剥离所有堆积在编排系统之上的东西,只呈现核心,即所有其他东西所依赖的基础。这并不是说服务发现、DNS和负载均衡不重要。但在编排系统的上下文中,我们谈论这些东西是因为它们是为编排器的核心功能服务的工具:将应用程序调度到节点池上运行并管理它们的生命周期。

简而言之,这本书就是关于:从用户那里接收运行应用程序的请求,识别可以运行该应用程序的机器,然后向选定的机器发送请求以启动应用程序。这样说似乎很简单,不是吗?

除了介绍编排系统的基础概念外,写这本书的另一个目标是使内容对广泛的读者群体具有吸引力。因此,虽然我选择用Go编写Cube编排器,但我希望任何人都能通过这本书并使代码工作,即使你从未写过一行Go代码。所有代码都使用基本的Go特性。虽然我们确实使用了goroutines来进行一些基本的并发处理,但我们没有使用channels(如果你感兴趣,有很多关于并发的优秀资源可以学习)。我们也没有使用泛型。(在Go 1.18发布后不久,我确实尝试重构代码和手稿以使用泛型。虽然我让代码工作了,但我意识到它给这本书引入了不必要的复杂性。这成了需要解释的众多事情中的又一件。)

我希望你在阅读这本书时能感到愉快。在享受乐趣的过程中,我希望你能从这本书中学到我在写作过程中学到的东西。

致谢 在生活中的大多数事情中,我们都得到了很多人的帮助。这本书也不例外。我想首先感谢Manning的所有人,他们帮助这本书成为现实。我想感谢Andy Waldron,他接手了我的书并在其多次变化中始终相信它。Katie Sposato Johnson在帮助我导航Manning的过程中起到了关键作用。没有她的帮助,这本书不会存在。我还要感谢Manning的许多其他工作人员,他们参与了这本书的制作和营销工作。

我要感谢在不同阶段阅读手稿并提供有见地反馈的评审员:Alain Lompo、Alessandro Campeis、Andres Sacco、Becky Huett、Bobby Lin、Christopher Villanueva、Clifford Thurber、David Paccoud、Emanuele Piccinelli、Ernesto Bossi、Fernando Bernardino、Fernando Rodrigues、Geert Van Laethem、Gregory Reshetniak、Katia Patkin、Kosmas Chatzimichalis、Larry Cai、Lucian Enache、Madiha Khalid、Matthias Busch、Michael Bright、Muneeb Shaikh、Nathan B. Crocker、Nghia To、Richard Vaughan、Sanket Naik、Simone Sguazza、Thomas Dybdahl、Timothy R. J. Langford、Tim van Deurzen和Vamsi Krishna。

特别感谢技术校对员Mike Haller,他在书籍进入生产阶段前对代码进行了彻底审查。保持书中呈现的代码与源代码同步是相当具有挑战性的,但Mike在帮助我清理许多不一致之处方面起到了无价的作用。

关于本书 《用Go构建编排器(从头开始)》的写作目的是帮助你更好地理解编排系统的基本组件。无论你是DevOps工程师、站点可靠性工程师(SRE)还是软件工程师,今天的许多技术可能看起来像一个黑盒子。你只需将其部署到云端,然后神奇的“事情”就会发生。正如我们所知,当技术正常工作时,神奇的技术是很棒的!当它失败时——它肯定会失败!——这种神奇的特性可能会成为快速识别问题和解决问题的障碍。随着越来越多的开发人员将他们的应用程序迁移到云端,他们正在(或将要)在编排系统上运行它们。除非他们在一家拥有专门的DevOps或SRE团队的大公司工作,否则他们可能需要自己部署和管理他们的应用程序。这包括在问题出现时处理它们。我的希望是,这本书能去除一些应用程序在编排器上运行的神秘感。

谁应该阅读这本书 《用Go构建编排器(从头开始)》适合任何负责部署和操作编排系统的人(即DevOps工程师和SRE),以及任何负责在编排系统上部署和管理应用程序的人(即软件工程师)。如果你想了解编排器的工作原理,你可以阅读Kubernetes或Nomad的源代码,这两个开源项目都可以在GitHub上找到。Kubernetes有500万行Go代码。Nomad的代码库要小得多,但仍然有超过50万行Go代码。我不知道你怎么样,但我会很难从试图理解50万行代码中获得多少价值,更不用说500万行了!

本书的组织结构:路线图 本书分为五个部分,共13章。第一部分介绍了Cube编排器的思维模型,并设置了将在本书其余部分实现的骨架代码库:

第1章 简要解释了编排系统的目的,然后描述了Cube的思维模型,这是本书其余部分实现的编排器。 第2章 使用第1章的思维模型为Cube编排器的核心概念创建了一个骨架代码库。 第3章 通过详细实现Task对象的骨架,展示了我们将如何实现代码库。 第二部分实现了Worker组件所需的概念:

第4章 详细实现了Worker对象的细节。 第5章 为Worker构建了一个API。 第6章 创建了一个框架,使Worker能够公开其状态和正在运行的任务的状态的指标。 第三部分实现了Manager组件所需的概念:

第7章 详细实现了Manager对象的细节。 第8章 为Manager构建了一个API。 第9章 探讨了故障场景并实现了处理它们的解决方案。 第四部分引导读者重构初始实现中的两个组件:

第10章 描述了调度器接口并实现了一个更复杂的调度算法。 第11章 设计并构建了一个存储接口,使Manager和Worker组件能够将它们的任务存储在内存中或持久化到数据库中。

第五部分实现了一个命令行界面(CLI),使读者能够操作编排器:

第12章 构建了一个CLI,实现了启动Manager和Worker、启动和停止任务以及获取系统中任务状态的命令。 第13章 总结了我们所完成的工作,并提供了一些关于接下来可以做什么的建议。

关于代码 本书包含了许多源代码示例,既有编号的代码清单,也有与普通文本混排的代码。在这两种情况下,源代码都使用固定宽度的字体格式化,如下所示,以便与普通文本区分开来。有时,代码还会加粗,以突出与前一步骤相比发生变化的代码,例如当在现有代码行中添加新功能时。

在许多情况下,原始源代码已经过重新格式化;我们添加了换行符并重新调整了缩进,以适应书中的页面空间。在极少数情况下,即使这样也不够,代码清单中会包含行续标记(➥)。此外,当代码在文本中有描述时,源代码中的注释通常会被移除。许多代码清单还附有注释,突出重要概念。

你可以从本书的在线版本(liveBook)中获取可执行的代码片段,网址为:https://livebook.manning.com/book/build-an-orchestrator-in-go-from-scratch。书中示例的完整代码可以从Manning网站(https://www.manning.com/books/build-an-orchestrator-in-go-from-scratch)和GitHub(https://github.com/buildorchestratoringo/code)下载。

liveBook 讨论论坛 购买《用Go构建编排器(从头开始)》的读者可以免费访问由Manning Publications运营的私人网络论坛,在那里你可以对本书发表评论、提出技术问题,并从作者和其他用户那里获得帮助。要访问论坛并订阅,请将你的浏览器指向:https://www.manning.com/books/build-an-orchestrator-in-go-from-scratch。该页面提供了注册后如何进入论坛的信息、可用的帮助类型以及论坛的行为规范。

Manning对读者的承诺是提供一个平台,让读者之间以及读者与作者之间能够进行有意义的对话。这并不意味着作者必须参与特定数量的讨论,作者在论坛上的贡献是自愿的(且无报酬)。我们建议你向作者提出具有挑战性的问题,以免他的兴趣转移!

关于作者 TIM BORING是一位拥有20多年行业经验的软件工程师。在这些年里,他一直是包括Borg、Kubernetes和Nomad在内的编排系统的用户。

关于封面插图 《用Go构建编排器(从头开始)》封面上的人物是“Femme Baschkirienne”,即“巴什基尔妇女”,取自Jacques Grasset de Saint-Sauveur于1788年出版的一个收藏。插图精细绘制并手工上色。在那个年代,人们可以通过服饰轻松辨别出他们的居住地以及职业或社会地位。Manning通过基于几个世纪前丰富多样的地区文化的书籍封面,庆祝计算机行业的创造力和主动性,这些文化通过这样的插图收藏得以重现。

第1部分 介绍 本书的第一部分为你从头开始编写一个编排系统奠定基础!

在第1章中,你将了解每个编排系统的核心组件。基于这些核心组件,你将构建一个Cube编排器的思维模型,我们将在本书的其余部分一起实现这个模型。

第2章将指导你从第1章学到的思维模型中创建代码骨架。

在第3章中,你将详细实现Task对象的骨架。这个练习将展示我们用来实现Cube代码库其余部分的过程。