安装设计

了解安装过程的工作原理

建立、安装和操作 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。每个组件都在自己的包目录中。重要文件链接至 binlib 等重要目录。

建立

必须组装主工件。DC/OS 构建由不断变化的组件列表组成,因此构建工具看起来像自己的小包管理器。每个组件都必须从来源构建,以可重复的方式配置,然后添加到主工件中。

DC/OS 包由两个文件定义:[ buildbuildinfo.json。这些说明了必须下载什么以及如何构建。构建时,工具链处理构建、封装以及将所有需要的工件纳入主 tarball。

安装

既然有一个所有已构建组件的包来运行 DC/OS,因此必须先配置每个安装,然后才能将其置于主机上。如果保持此配置小且长期不变,便能确保群集中的每个主机都会以同样的方式行事。

配置工具将所有组件构建成一个包,其含有可让群集运行的所有内容。您将从 DNS 配置和 bootstrap 信息等简短详情列表中选择。这将被添加到您构建的单个 tarball 上。然后,您将拥有针对硬件自定义的软件包,并可再三重复性地创建任何大小的群集。

很难编排安装的推出,尤其是当您需要按特定顺序执行某些操作时。为了尽可能简单地保留所有内容,在主机级别,DC/OS 对群集状态未做任何假设。您可以安装代理节点,然后安装管理节点,或者同时安装这两者!

一旦您的包被构建,便可通过运行每个主机上的 dcos_install.sh 来开始。此脚本仅做三件事:

一旦 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 群集所需的知识量。

请记住,群集必须看起来几乎相同,以便包安装起作用。如果我们更改框架依赖的配置参数,我们将无法保证包是否可以安装或可靠运行。