安装设计
了解安装过程的工作原理
建立、安装和操作 DC/OS 必须是可重复的过程。使用 10,000 台主机时,即使是较小的出错率也不可接受。DC/OS 包含超过 30 个不同的库、服务和支持包,因此需要采用非标准方法。尝试将这些组件的每一个作为独立的工件在目标主机上安装和配置,会引入故障,阻止客户依赖系统。
构建一个防弹系统是有可能的。构建过程完成后,您将会有一个包含安装和运行所需全部组件的工件。拥有一个工件可以让我们做一些假设和保证。
- 位元在每个主机都相同,但角色不同,它们只是使用不同的组件子集。
- 升级是不可再分的,不存在非普通组件不兼容的问题。
- 下载不依赖多个不同的来源,因为只有一个用于验证是否完成和损坏的不太重要的文件。
设计目标
了解您正在使用的约束很重要。以下是 DC/OS 的设计目标:
- 最大程度降低对主机 OS 的依赖性。这让 DC/OS 能够在尽可能多的环境中运行。
- 主机 OS 应完全可自定义。每个人都有一套不同的工具在使用。这些工具应在没有任何更改或移植的情况下正常工作。硬件具体功能(如内核模块)尤为重要。
- 最大程度降低对主机的依赖性。编排依赖性主机出现的顺序(管理节点、代理节点)很困难。它们应能按任何顺序出现,并且只在依赖关系确立并提供给集群时才开始工作。
- 需要最少外部基础架构。外部基础架构很少存在,例如 PXE 启动映像和 NFS 存储。
- 应该可以选择用于部署的方法。如果您对现有系统感到满意,则无需了解新系统。集成应具有清晰的网络接口,并尽可能简单。
- 可在 DC/OS 和现有系统之间轻松集成,例如配置管理工具和 CloudFormation。集成网络接口必须简单且记录在案。
- 将所有依赖关系和库捆绑成单个工件。正常生命周期流程将会升级或降级软件库以及完全在 DC/OS 之外的依赖关系。如果不依靠这些,系统将变得不那么脆弱,而且将更稳定。
- 必要时,允许用户修改实时系统中的代码和配置。虽然这是一种反面模式,但它有助于在关键时刻将基础架构保持在高水平上。
- 安装必须尽可能接近 100%。即使在运行 1000 个主机集群时有 1% 的故障率也会导致 10 个需要人为干预的故障情况。
- 升级和升级的回滚在主机级别都必须不可再分。
- 可以审核集群的状态。当运行大型集群时,很容易会遇到难以依赖单个主机状态的情况。
封装
我们选择 tarball 作为封装格式,因为它们在任何地方都可用。tarball 是一种可压缩文件格式,将多个文件捆绑到一个档案中。有许多常见的封装格式(deb、rpm、wheel、gem、jar 等),但它们都只是 tarball。遗憾的是,几乎所有的常见格式都是围绕单一分布或语言构建的,使得它们难以跨各种不同的分布和语言使用。一些功能(如安装前和安装后脚本)非常方便,可帮助推动系统进入正确的“状态”。不值得有不可预测的结果和/或未经测试的极端情况这种可能性。因此,我们简化了流程,并使包安装成为一个步骤:tarball 提取。不需要执行任意代码,而且保证了可重复性。
DC/OS 中的所有组件均内置在一个提取至主机系统上 /opt/mesosphere
的 tarball 中。在这个目录内,它看起来很像 /usr/local
。每个组件都在自己的软件包目录中。重要文件链接至 bin
和 lib
等重要目录。
建立
必须组装主工件。DC/OS 构建由不断变化的组件列表组成,因此构建工具看起来像自己的小软件包管理器。每个组件都必须从来源构建,以可重复的方式配置,然后添加到主工件中。
DC/OS 包由两个文件定义:build
和 buildinfo.json
。这些说明了必须下载什么以及如何构建。构建时,工具链处理构建, 封装以及将所有需要的工件纳入主 tarball。
安装
既然有一个所有已构建组件的软件包来运行 DC/OS,因此必须先配置每个安装,然后才能将其置于主机上。如果保持此配置小且长期不变,便能确保集群中的每个主机都会以同样的方式行事。
配置工具将所有组件构建成一个软件包,其含有可让集群运行的所有内容。您将从 DNS 配置和 bootstrap 信息等简短详情列表中选择。这将被添加到您构建的单个 tarball 上。然后,您将拥有针对硬件自定义的软件包,并可再三重复性地创建任何大小的集群。
很难编排安装的推出,尤其是当您需要按特定顺序执行某些操作时。为了尽可能简单地保留所有内容,在主机级别,DC/OS 对集群状态未做任何假设。您可以安装代理节点,然后安装管理节点,或者同时安装这两者!
一旦您的软件包被构建,便可通过运行每个主机上的 dcos_install.sh
来开始。此脚本仅做三件事:
- 将软件包下载到当前主机。
- 将软件包提取到
/opt/mesosphere
中。 - 使用 DC/OS 组件包管理器 (Pkgpanda) 启动安装。
一旦 ZooKeeper 集群在管理节点上达到共识机制数量且 Mesos 出现,每个代理节点都将加入集群。我们已将步骤保持至最低限度,以确保其尽可能可靠。
权衡
显然,还有其他方式可以对其进行构建。让我们看看一些常见问题以及当前决定如此做出的原因。
不可改变的配置
每个集群的配置在开始时生成,并且不可改变。这使得我们可以保证在安装后每个主机上的配置正确。请记住,您将对数千个节点进行此操作。这些有关配置的保证减少了运行 DC/OS 所需的文档数量,使其更易于支持。
如果配置不可改变,主机将没有机会更新或更改其配置的一部分。我们遇到的许多生产问题均通过此设计决策进行了改善。
我应该绑定什么 IP?
决定可访问网络和 Mesos 管理节点的 IP 和网络接口是非常重要的事。以下是我们无法作出默认假设的环境的示例:
- 在诸如 AWS 等水平分割环境中,主机名可能解析为外部 IP 地址,而不是内部 IP 地址。
- 在没有 DNS 的环境中,我们需要您告诉我们它具有哪些 IP 地址。
- 在具有多个接口的环境中,我们无法自动选择要使用的接口。
- 并非所有机器都有可解析的主机名,因此您无法进行反向查找。
由于上述限制,我们努力产生稳定的默认值。要尽可能使其可配置,我们有一个可以写入的脚本,以便返回我们在每个主机上应该绑定到的 IP 地址。文档中有多个示例解释如何针对不同环境编写 ip-detect
脚本,应涵盖大多数使用情形。对于默认情况下不起作用的环境,您将能够编写自己的 ip-detect
,并将其与您的配置进行整合。配置的最重要部分是 ip-detect
,这是集群能够成功出现的唯一方式。
单个软件包与多个软件包、每个提供商的软件包(RPM、DEB 等)
我们采取了如今最常用的默认路线,单独安装这些软件包,而不是将所有包都捆绑到一个镜像中。这可能会马上产生几个问题:
- 之间的移动需要移植和检测各个软件包。
- 软件包安装的故障率不为零。我们在尝试安装软件包时发现故障率为 10-20%。这会阻止集群成功启动,使其更难操作。
- 输送多个软件包比分发一个 tarball 要困难得多。确保多个软件包稳健会产生额外资源消耗。
- 升级必须不可再分。在多个软件包之间要保证这一点更加困难。
Tarball 与容器
我们可以将 DC/OS 封装为大量容器(或具有多个进程的单个容器)。这种方法结合了多个软件包的缺点和 Docker 守护程序的不稳定性。我们发现 Docker 守护程序会定期崩溃;虽然这对于某些应用是可接受的,但这是您不想在基础架构中有的。
安装方法
我们可以支持任何安装方法;然而,目前使用的庞大数量配置和软件包管理却令人生畏。从 Puppet 到定制内部工具,我们已经了解一切。我们希望通过提供与尽可能多的工具配合使用的简单网络接口来实现这些方法。此处的最小公分母是 bash
。
由于难以维护 bash
,因此我们尽可能简化了安装方法。构建的“镜像”可放置在运行主机之上,并且独立运行。解压是进行此项安装所需的全部操作。这是一个很小的简单 bash
脚本,可在任何地方工作,并可与其他工具轻松集成。暴露的整个表面积最小,且未给予对内部的访问权限,如果更改的话,会使您的集群不受支持并使保修无效。
主机镜像
可以制作已配置的整个主机镜像,而不是顶部的 tarball。以下为这不是唯一安装方法的原因:
- 不计其数的发布更新。RHEL 每次发布包更新时,我们都需要对其进行测试、捆绑和分发。这对于 CoreOS 来说变得更加困难,因为我们实际上最终会将该项目分叉。
- 您想选择它们的分发。有些人与 Canonical 存在现有的支持合同,一些则与 RedHat 存在现有支持合同。
- 您想配置基本 OS。存在必须对主机运用的安全策略和配置。
主机镜像是分发和安装 DC/OS 的绝佳方式。使用 bash
安装方法,为您的基础架构创建新的主机镜像就跟把它与 Puppet 等工具集成一样容易。
直接将配置文件暴露给用户
DC/OS 包括大量具有配置选项的组件。我们花了很长时间把正确的组件拼凑起来。这些保证能够在规模生产中提供最佳运行。如果我们暴露这些选项,则会增加运行 DC/OS 集群所需的知识量。
请记住,集群必须看起来几乎相同,以便使软件包安装正常安装。如果我们更改框架依赖的配置参数,我们将无法保证软件包是否可以安装或可靠运行。