原文:
annas-archive.org/md5/0ee032b8a98d994ca98c6a4bd4d654be译者:飞龙
第五章:补丁管理策略
在 Linux 系统的日常操作中,平均系统管理员最常见的任务大概是补丁管理(即补丁更新)。与 Windows 和 macOS 世界不同,系统管理员通常负责处理各种操作系统和应用程序的补丁更新任务,涵盖了主系统和第三方生态系统。同时,系统中通常内置或通过第三方提供应用程序管理工具,以协助完成这项可能令人生畏的工作。
补丁管理,当然还有系统更新,是我们工作中的重要部分,虽然它可能感觉平凡,但确保它做得正确非常重要。而今天的生产 Linux 系统比十年前更加复杂和多样化。补丁管理也变得比以往任何时候都更为重要,我们预计这一趋势随着时间的推移只会越来越明显。
我们将首先了解补丁和更新是如何提供的,以及我们所说的不同安装方法的含义。
在本章中,我们将学习以下内容:
-
二进制、源代码和脚本软件部署
-
补丁理论与策略
-
管理员的编译工作
-
Linux 安装与重新部署策略
-
重启服务器
二进制、源代码和脚本软件部署
软件有各种形态和大小。因此,软件部署并不是一刀切的事。软件的标准部署方式有三种:直接作为二进制包、通过需要编译成二进制包的源代码,或者作为脚本。我们将深入探讨这些方式,因为理解每种方式的含义及其适用场景非常重要。
编译型和解释型软件
许多系统管理员从未作为开发人员工作过,通常也不了解软件的存在形式。编程语言主要有两种基本类型:编译型和解释型。
编译语言是用一种语言(源代码)编写的,通过编译器生成二进制可执行代码,这些代码可以直接在操作系统上运行。这可能是一个过于简化的说法,但我们不是开发人员,仅需要关注原始代码被编译成二进制格式即可。对于 Linux,这种格式被称为ELF,即可执行与可链接格式。编译后的二进制文件在操作系统上运行。
解释型语言有所不同。它们不像编译成二进制那样,而是保持原样,并由一个叫做解释器的程序实时处理,解释器本身是一个二进制可执行文件,它将代码作为输入文件来处理。因此,解释型软件要求操作系统上安装适当的解释器,以便该软件能正常工作。例如,如果你有一个 Python 程序,并希望在某个系统上运行,那么你需要确保该系统上安装了 Python 解释器来处理这个文件。
这两种软件方法完全正常且有效。作为系统管理员,我们将始终与这两种方法打交道。现代计算机(和解释器)速度非常快,因此两者之间的性能差异几乎没有什么关切,其他因素(主要是开发人员的考虑)通常在决定软件如何编写时更为重要。
软件并不完全如此简单,存在一些奇怪的概念,比如看似解释型的代码,实际上却在最后一刻被编译并像二进制文件一样运行。一些像基于.NET 和 Java 的语言,虽然是编译的,但并不是编译成二进制文件,因此本质上是结合了两种方法的一种混合体,兼具两者的优点。
然而,通常我们将所有软件视为二进制可执行文件(直接在操作系统上运行,无需帮助)或解释型软件(需要操作系统上的编程语言环境或平台来运行)。为了理解代码部署的目的,像.NET 和 Java 这样的语言,以及JIT(即时编译)的语言,如 Perl,由于其行为,通常被归类为解释型语言。
常见的预编译语言包括 C、C++、Rust 和 Go。常见的解释型语言,或者看起来像是解释型语言的,包括 Python、PHP、Perl 和 Ruby。更让人困惑的是,任何解释型语言都可以被编译。标准编译语言甚至可以被解释!更重要的不是语言本身做了什么,而是在特定情况下它是怎么做的?本质上,任何语言都可以根据我们在实践中的处理方式来选择编译或解释。然而,在现实世界中,没有人会解释 C++,也没有人会编译 Python。但如果你愿意,还是有可能的。
作为系统管理员,我们实际上对软件的构建没有发言权,我们只需要按给定的方式部署软件。我们最需要理解的是,我们可能对整个平台的控制和影响力有多少。如果我们运行一个二进制应用程序,那么我们的实际选项可能仅限于我们所运行的内核版本。但如果我们要安装一个 PHP 脚本,我们可能还需要决定如何安装 PHP,选择哪个版本,选择哪个 PHP 提供者,等等。在某些情况下,这可能变得相当复杂。
在几乎所有商业场景中,我们部署的大多数软件将是二进制格式。通常,我们甚至可能不知道(或不关心)特定的软件,因为整个过程通常会由其他人处理。盲目安装软件的情况非常常见。
系统管理员安装由脚本构成的软件的情况越来越常见,这些脚本是可以直接读取的代码。这些文件只是由解释器处理。因此,软件从未以二进制形式存在于磁盘上。由于现代计算机系统如此强大,尽管这一过程在效率上似乎存在问题,但通常并不成问题。现在,许多流行的软件包都是以这种方式编写和交付的,因此大多数系统管理员通常会与脚本安装打交道。
在许多情况下,脚本的安装与二进制软件包使用相同的自动化方法,这使得整个过程通常对管理员透明。作为系统管理员,你可能并不总是知道自己正在部署的是什么类型的软件包,除非你深入其底层组件。这种情况在非关键软件包中尤为明显,尤其是使用依赖解决系统部署的软件包(例如 PHP 或 Python),它们为你处理了平台的集成,或者这些依赖项已经为其他组件提前安装好了。
今天,我们预期脚本的安装将成为一项常见的任务,这可能不会代表部署到系统上的大多数软件包,但它很容易构成系统上主要的工作负载代码。我的意思是,操作系统、支持工具和大型系统库通常是二进制软件包。但最终的工作负载,系统之所以存在,往往有很大可能是脚本,而非编译后的二进制文件。
最后,最后一种类型是不能直接运行的源代码,必须先编译成二进制软件包才能运行。我们将在接下来的两个部分中深入讨论这个主题,因此这里只会简单提及。你可以争辩说,这种方法仍然是二进制安装,因为最终部署的软件包是二进制的,这完全正确。然而,为了获取和部署这个二进制文件,必须遵循的工作流程截然不同,因此这成为了一种有效的三级部署选项。一些系统会自动执行编译步骤,因此有可能出现一个部署包,它在编译并安装二进制文件的同时,系统管理员甚至都没有察觉。
误导性的源代码安装使用
由于我们稍后将在本章深入讨论的原因,从源代码安装软件通常会有不好的声誉。在某些方面,这是应得的,而在某些方面,又并非如此。
因为源代码安装在实际上是自由和开源软件世界的独特存在,它在 1990 年代和 2000 年代时遭到厂商和 IT 从业人员的猛烈攻击,目的是为了抹黑它,因为它严重影响了传统的闭源产品(以及那些只支持闭源软件的人的工作)。这当然是完全虚构的,但由于源代码授权复杂难懂,很容易让那些没有掌握该话题细微差别的人产生恐惧和怀疑。
然而,更重要的是,源代码安装被贴上了不专业且不必要的标签,原因是它被认为是由一些更像爱好者的系统管理员推动的,他们在没有真正考虑业务需求的情况下以这种方式安装。它有趣,或者看起来很有印象,或者是他们的朋友这么做,所以他们也这么做。我很遗憾地说,这种说法在很大程度上是准确的。曾经有一段时期,许多软件以不必要的复杂和繁琐方式安装,而不考虑这一过程对业务的有效性。并不是说源代码编译没有其存在的价值,它确实有。但即使在二十年前或更久,这种方式也只是局限在一个小众的场景中,而不是大多数的部署情况。因此,从很多方面来看,这个坏名声是实至名归的,但并非完全如此。
然而,今天,源代码编译几乎被遗忘,几乎没有人知道如何使用标准流程来进行编译,并且相关工具的安装通常被禁止,或者这些工具并不容易获得,使得编译变得非常困难,甚至不可能。只有那些需要编译的强烈需求的软件才会以这种方式分发。因此,市场实际上几乎消除了这种做法。
但是,那些曾经进行编译的人仍然面临着恐惧和羞辱。说某人正在进行源代码安装,依然是一种贬低的说法。遗憾的是,为了进一步抹黑现今的软件,现在已经普遍将这个术语用于指代那些不需要通过源代码编译成二进制的脚本类软件。术语“源代码”暗示代码必须从源代码转化为二进制,而脚本在这个上下文中并不被认为是源代码。然而,从技术上来说,它们确实是原始代码、源代码,但不再有那个令人不悦的步骤。可是很少有人会进一步探讨这个问题,而这一小小的语言技巧很容易误导他人。所以,这成为了一种简单的手段,能够让一个仅仅寻求借口来做情绪决策的经理,被误导。这听起来很合理,而很少有人会真的去深思。
这个窍门实际上来自于语义简写,这是一个总是危险的东西,尤其是在 IT 领域。自编译软件的问题与源代码的可用性无关,而是与在使用之前需要编译它有关。如果没有这个步骤,源代码的存在对我们来说完全是积极的。人们随后错误地将编译过程称为源代码安装。这种语义错误为某些人打开了大门,他们将某个技术上确实是源代码安装的软件(没有编译)误解为安装源代码,而由于这个术语长时间被错误使用,它变成了一种负面的含义,应用到错误的事物上,最终没有人理解为什么这些东西是错的或反向的。
Linux 为我们提供了许多标准的企业级软件部署方法。尽管这些选项功能强大,但也使得标准化和长期支持的规划变得更加困难。
在所有生产环境中的 Linux 系统中,无论供应商如何,默认都会存在一个软件包管理系统。多年来,这些软件包管理系统已成为区分不同 Linux 操作系统的关键因素。存在多种软件打包格式,但其中两种,即 DEB 和 RPM,已经成为主流,其他格式则保持在非常小众的地位。
现在越来越多的 Linux 发行版要么有多个软件打包系统,要么在单一的软件包管理系统下使用多种格式。这种多样性是好的,因为它给我们提供了更多的选择来维护系统中的特定包,但也意味着更多的复杂性。
与所有软件部署一样,我们有一些对所有操作系统普遍适用的标准关注点。首先是软件是否自包含,或者是否需要访问其他包或库。传统上,大多数软件,尤其是在 Linux 和其他类 UNIX 操作系统上,都是通过利用扩展的系统和第三方库(统称为依赖关系)来减少其安装大小以及操作系统本身的大小。这意味着我们可以拥有尽可能小的软件,并且使用相同资源的其他软件可以共享它们在磁盘上的存储,从而最小化(有时显著地)我们需要存储和维护的内容。更新一个软件包或库时,所有使用该包的程序都会同步更新。另一种方式是让每个独立的软件包都携带自己的所有依赖项,并且这些依赖项仅在该软件包内可用。这会导致软件安装变得更大,并且可能会在系统中存在多次相同的数据。可能是很多次。这导致了臃肿,但也使得单个软件包更容易维护,因为不同软件组件之间的互动较少。
举个例子,数十个或更多的软件包可能都需要使用 OpenSSL 库。如果每二十个包中都有 OpenSSL,我们将把相同的代码存储在磁盘上二十次。此外,如果 OpenSSL 发布了更新,或者更重要的是,如果发现了漏洞需要修补,我们就必须修补二十次,而不是一次。相比之下,如果我们使用一个共享的 OpenSSL 库,无论我们有一个应用依赖它还是一百个应用,我们只需修补这个库,确保所有的漏洞或更新都已解决。
这两种方法都是完全有效的。过去,由于系统存储空间较小,共享库是一种“必要的恶魔”,因为共享资源不仅能减少磁盘使用,还能更好地优化内存,因为共享库有可能被加载到内存中,并且能被多个软件共享。如今,我们通常拥有更多的存储和内存,远超实际需求,这种小规模的效率优化已经不再必要,尽管它可能仍然有些许好处。非共享方法则将这种效率转化为每个软件包拥有自己的依赖项,从而避免了依赖冲突或共享资源不可用时带来的问题。
共享资源方法的最大优势可能在于,修补已知漏洞可能会更简单。举个例子,如果我们假设 OpenSSL(一个广泛共享的库)发现了一个关键漏洞并发布了更新。如果我们的系统使用共享资源,我们只需要找到安装了 OpenSSL 的系统并更新该包。所有依赖该包的系统都会自动一起修补。如果 OpenSSL 被单独打包并与数十个不同的应用程序一起使用,我们就需要找到这些应用程序中的每一个,确认它们都在使用 OpenSSL,并且要单独修补它们。这将是一个可能令人生畏的任务。我们依赖每个软件的包维护者进行适当的审查,快速修补依赖项,并立即提供更新的包给我们,但这并不是常有的事。
系统通常会使用一种包管理和软件仓库系统,如 DEB,当存在共享系统组件和需要处理许多依赖项时。它们会在将所有依赖项包含在最终包中时使用另一种包管理系统,如 SNAP。但这远比听起来复杂,例如,制作一个包含所有依赖项的 DEB 包,或者一个期望依赖项由外部提供并共享的包。DEB 通常作为软件包的共享库只是一种约定。在 Linux 中,我们还面临着一组完全不同的关注点,如果你来自 Windows 或 macOS 背景,可能并不习惯:一个与操作系统本身紧密相连的软件生态系统。在 Linux 中,我们期望操作系统(例如 RHEL、Ubuntu、Fedora、SUSE Tumbleweed 等)不仅包含基本的操作系统功能和一些极为基础的实用工具,还包括几乎所有可能描述的软件,包括核心库、编程语言、数据库、Web 服务器、终端用户应用程序等等。在很多情况下,你可能永远不会使用任何没有与你的 Linux 发行版一起打包的软件,当你添加第三方软件时,它通常是一个关键应用程序,代表着战略性业务应用,或者显而易见,是内部定制开发的软件。
因此,在 Linux 上处理软件时,我们必须考虑是使用内置操作系统的软件,独立获取并安装的软件(这包括定制软件),还是两者的混合,其中软件的许多组件来自操作系统,但一些组件由其他方式提供。
深入了解不同打包系统的具体细节没有太大意义,特别是因为它们在一般使用上往往有很大的重叠,但在实际使用中又非常独特。现在我们已经知道了它们存在的选择。软件包管理系统在 Linux 中比在其他操作系统中更为重要,如 Windows 或 macOS,因为在 Linux 运行的大型服务器系统中,通常存在更多的复杂性,而安装的软件通常使用更广泛的依赖集,从许多不同项目中拉取组件或支持库。Linux 打包系统维护在线软件、库、组件等的仓库,使这一切成为可能。
大型 Linux 软件包管理系统及其相关软件仓库最重要的方面可能是它们允许分发商在其精确的内核和组件选择与配置下,组装并测试大量的组合软件,从而提供一个庞大、可靠的平台来部署解决方案。
在这里,最佳实践是困难的。事实上,我们只能依赖经验法则,但这些法则非常强大。经验法则是尽可能使用供应商的仓库进行软件部署。这个方法看似简单和显而易见,但出乎意料的是,仍然有很多人会通过手动方式获取软件并安装,而没有供应商的测试和依赖管理的支持。
真正的最佳实践,正如你可能预期的那样,是深入了解你所选发行版的包管理生态系统,以便你能够充分利用其特性。这些特性通常包括日志记录、版本控制、回滚、补丁和系统更新自动化、校验和、自动配置等。
软件组件越常见和基础,越有可能由供应商作为分发的一部分提供。越是小众且接近业务核心,越有可能通过手动安装或非标准过程来安装它,因为最终用户产品不太可能被包含在供应商的软件仓库中,更有可能需要仔细管理版本和更新计划,而不仅仅是关注与系统其他部分的稳定性和测试。
软件供应商通常会为那些不包含在分发仓库中的产品创建和维护自己的仓库,允许你配置其仓库,仍然通过标准工具管理所有安装和补丁任务。
软件部署包含了许多特殊情况。人们很容易想要提供标准、明确的总是这样做的指导,但软件的工作方式并非如此。学习你系统的工具,能用时使用它们,为每个需要部署的工作负载准备做一些独特的工作或学习某些东西。有些,比如 WordPress,可能会变得非常标准,以至于你只需要使用发行版自带的软件包即可。其他软件可能会非常独特,你可能只需要部署一个基本的操作系统,下载供应商的安装程序,它会安装所需的所有软件,甚至可能会编译它!这一切都取决于情况,最重要的是,它取决于软件供应商如何构建和打包软件,以及你的发行版是否决定将该软件包包含在操作系统中,或是否需要单独安装。
现在我们已经了解了软件安装过程和相关注意事项,我们可以深入探讨关于补丁和更新的核心问题。
补丁理论和策略
有人可能认为打补丁是非常直接的事情,不会有太多可讨论的内容。但实际上并非如此。如果你与几个系统管理员交谈,你肯定会得到一些相当不同的看法。有些人每天打补丁,有些人每周打补丁,有些人会尽量等到最后才打补丁,还有些人则是随机进行补丁操作,甚至有些人认为根本不应该打补丁(嘿,如果它没坏,为什么要修呢!)
我们应该首先明确为什么要给软件打补丁。打补丁不同于更新或升级,它意味着我们对软件进行小范围的修复,以解决已知问题或漏洞,而不是实施新功能或特性。添加新功能通常被视为一次更新。
大多数软件供应商和操作系统供应商遵循这一系统,并维持仅在版本之间解决安全性或稳定性问题的补丁系统。在 Linux 生态系统中,这主要与操作系统的发布版本相关。例如,如果你使用的是 Ubuntu 22.04,并且通过其自身的补丁机制来修补随发行版一起提供的软件,那么你将仅获得现有软件版本的安全性和稳定性修复,而不会得到新版本、特性或功能。其逻辑在于,升级到新版本可能会导致软件出现问题、改变可用性,或使依赖该软件的其他产品失败。
升级到新版本通常只在操作系统本身发布新版本时发生,这时操作系统和所有其中的包可以同时升级。这样,操作系统供应商理论上可以将软件作为一个整体进行测试,以便让客户(你)确信,即使在将所有软件升级到新版本之后,所有的软件组件仍然能够协同工作。
因此,我们假设如果补丁已经提供给我们,这意味着供应商(很可能与我们的分发供应商合作)已经发现了需要修复的问题,已经创建了修复方案,进行了测试,现在正在分发补丁。然而,即使经过测试,众多目光监督错误,并且目标只是修复已知漏洞,事情仍然可能出错。补丁本身可能有问题,打补丁的过程也可能遇到意外的麻烦。这意味着,无论提供补丁的人有多么良好的意图,我们都必须对打补丁保持谨慎。
在打补丁时,我们面临着两个相互对立的担忧。一方面,如果系统当前对我们来说是正常工作的,为什么在没有必要的情况下还要引入补丁过程的风险(和工作量)呢?另一方面,既然补丁已经提供给我们,为什么还要继续运行一个存在已知漏洞的系统?我们必须权衡这些问题,选择一个合理的行动方案。
风险规避并不是这里的关键问题,我们并不是在权衡成本与风险,而是在面对两种几乎相等的行动方案(从努力和成本的角度来看),但它们会带来截然不同的结果。我们需要选择一个能够最大限度降低业务风险的方案,仅此而已。最重要的不是我们有多么规避风险,而是我们的风险特征是什么。如果我们的业务非常容易受到小规模停机事件的影响,那么可能会优先考虑推迟修补。如果我们公司拥有高度敏感的数据,这些数据可能成为攻击目标,或者我们非常关注在发生数据泄露时的公关危机,那么我们可能会采取非常积极的修补策略。为了做出明智的决定,我们必须了解每种方案是如何产生和缓解不同风险的,以及这些风险如何影响我们特定的组织。
推迟修补的风险
单纯推迟修补并不能消除某些类型的风险。虽然这可能带来一定的好处,但也可能根据情况引入更多的风险。通常情况下,新的修补程序会频繁发布,可能一天发布多次,至少也会每月发布几次。
如果我们经常修补,比如每周一次,那么理论上我们通常只需处理极少的修补程序,在任何给定时刻,任何故障或不兼容问题都相对容易识别和回滚,因为需要处理的修补程序很少。
如果我们在一段时间内积累修补程序,并且只在比如说一年一次时修补,那么我们会面临一些问题。首先,修补过程可能需要相当长的时间,因为可能需要许多修补程序。其次,如果出现故障,可能很难找出导致问题的修补程序,因为它可能会被一大堆需要部署的修补程序所掩盖。第三,一次性进行的大量更改以及与任何经过测试的场景的偏离(几乎没有供应商会针对像你这样具体过时的系统进行测试,并与大量突如其来的更改进行对比)意味着修补过程引发故障的几率更大。
因此,推迟修补在许多情况下会成为一种自我实现的预言,那些因为修补会破坏东西而避免修补的人,往往会看到这一点发生,因为他们创造了一个更容易发生的局面。
没有一刀切的方案。每个组织都必须根据自身需求定制修补流程。有些组织会通过构建无状态系统并简单地部署已经修补过的新系统,销毁旧的未修补实例,从而完全避免修补问题。但并不是每个工作负载都可以采用这种方式,也不是每个组织都有能力进行这种基础设施的跃迁,以支持这种流程。
一些组织会进行持续的补丁测试,查看补丁在其环境中的表现。一些组织完全避免打补丁,抱着侥幸心理,期望最好。一些则盲目地打补丁。我们将讨论这些不同的选择。
因为 Windows 而避免打补丁
最近几年,系统管理员中出现了一种避免打补丁的文化。考虑到打补丁在一般情况下的重要性,以及它对我们职业生涯的核心作用,这似乎有些反直觉。没有人比系统管理员更支持快速、定期打补丁。
在 Windows 世界中,打补丁的过程与 Linux 或其他操作系统截然不同。它通常是延迟的、保密的、缓慢的、不可靠的,最糟糕的是,常常存在漏洞和错误。Windows 的打补丁问题一直存在,但在 2010 年代变得如此严重,以至于它不再是确定性的,远远比直接部署新系统要花更长时间,而且经常失败。
Windows 打补丁失败可能意味着几乎任何情况,从补丁安装失败,需要投入资源使其正常运行,到导致软件故障,无法再继续使用。一些补丁可能需要耗费数小时来运行,但最终失败,然后又需要花费数小时回滚!
正因为如此,Windows 领域的系统管理员通常对补丁保持谨慎态度,甚至完全避免打补丁,几乎成为了一种普遍现象。这种现象不仅限于补丁,还扩展到系统版本更新。因此,现在发现许多 Windows 系统已经多年甚至十年未更新,已成为常态,导致整个生态系统中越来越多的安全漏洞。
微软的回应不是修复打补丁的问题,而是试图强行进行未经授权的打补丁,并且通过模糊补丁过程,制造了更多的可靠性问题,甚至在许多情况下,打补丁管理系统发生了严重故障,以至于即使是那些希望保持完全更新的管理员,常常也不确定如何操作,或者根本无法做到这一点。
这些问题今天是微软特有的,并且大多数是现代时代微软所独有的。我们不能让对这种独特糟糕情况的情绪反应影响我们在 Linux 或其他领域的实践,这些领域并未受到微软的影响。在微软孤立的行业领域之外,没有其他生态系统经历过类似的问题。无论是在 Ubuntu、Red Hat、Fedora、SUSE、IBM AIX、Oracle Solaris、FreeBSD、NetBSD、DragonFly BSD、macOS、Apple iOS、Android、Chromebook 等,都没有出现过这种情况。打补丁总是存在风险,我们应该意识到这一点,但微软的问题是独一无二的,与我们在其他行业的实践无关。
补丁可以是自动化的,也可以是手动的。两种方法都完全可以接受。自动化需要更少的努力,并且可以防止忘记补丁或降低其优先级。在大组织中,要求手动干预的正式补丁程序可能很简单,以确保一致性,但在只有几个服务器的小型组织中,补丁可能很容易被忽视,甚至几个月都没有进行。当考虑手动与自动化补丁时,只需要考虑流程的潜在可靠性和涉及的人力成本(通常是时间)。
手动补丁的好处在于,你可以让人类在每个补丁安装时检查每个包,并在补丁进行时实时测试系统。如果出现问题,补丁过程中的每个细节都会历历在目,因为他们刚刚执行过,而且他们知道在出现问题时应该测试什么,回滚或处理什么。
自动化的好处在于它可以自动发生,可能在非常可预测的时间内,并且即使没有人类在场工作,它也能发生。将自动化补丁安排在晚上、过夜、周末或节假日进行,可以最大限度地减少对人类的影响,同时加速补丁过程。自动化补丁不太可能被遗漏,而且在补丁发生时或出现问题时,容易发送警报。
在大多数情况下,自动化补丁比手动补丁更受欢迎,因为它成本更低,几乎所有手动的好处都可以以某种形式自动化,比如通过让人类待命,以便在出现问题时接收警报。
测试补丁很少是可行的
每个人都在谈论测试补丁的重要性。系统管理员常常要求这样做,并且尝试拒绝应用补丁,直到能够完成测试(这是避免完全补丁系统的一个方便方式)。如果补丁出现问题,管理层几乎总是要求了解为什么之前没有进行补丁测试。
这里有一个残酷的现实:没有任何实际可行的手段可以在任何规模上测试补丁。说到这,我说出来了。大声说出来,去告诉你的老板们。测试补丁的成本,无论是时间还是金钱,都远远大于任何人所认为的。为了彻底测试补丁,我们需要一个复制的环境,这样才能给我们提供一个与生产环境相同的镜像,以便我们能够对要部署的补丁进行测试,涉及的软件、硬件和配置。如果试图简化这一过程,是行不通的,因为正是所有这些部分的相互作用使得测试变得重要。如果你改变了任何东西,可能会完全抵消这一非常昂贵过程的好处(或者更糟糕的是,产生一种虚假的安全感)。
在真实的环境中,每个系统基本上都是独一无二的。虽然有例外,但通常情况下,这是真的。有许多可能的变量,包括硬件制造日期、不同的零部件、固件版本,以及更高层次的基础设施堆栈(即,接近最终应用的代码和组件)。今天的计算机系统如此复杂,可能有数百万种变量,导致补丁中的某个 bug 被触发。
这就是虚拟化如此重要的原因之一,它创造了一个标准化的中间层,使得系统中一些更复杂的部分能够标准化。这样,至少有一部分,涉及许多驱动程序的复杂部分,可以简化复杂性。
很少有组织会进行真正的补丁测试。这样做的成本很高。通常,这涉及到仔细复制整个生产环境,包括匹配硬件版本、固件修订、补丁历史等。每个可能的方面都应该是相同的。补丁必须通过一系列快速的测试,以测试公司范围内的各种场景中的给定补丁。
在实际操作中,这意味着要复制所有硬件和软件,并且需要有一个专门的团队进行补丁测试。很少有公司能承担这样的费用,能证明这种做法带来的一点点潜在保护的公司就更少了。
补丁的及时性
补丁工作是一项通常需要非常迅速完成的活动,随着行业的成熟,快速补丁的重要性持续增加。我们这些在 1990 年代及之前接受过训练的人,通常记得那个时候补丁几乎没有时间敏感性,因为大多数计算机都是离线的,补丁几乎完全是为了稳定性问题,如果你没有遇到过问题,那就不太可能遇到。所以,等待几个月或几年再给系统打补丁(如果你做了的话),通常并不是一件大事。
哦,时代变化多么迅速。今天,软件变得更加庞大和动态,层级之间的相互关联也更多,而且除了最罕见的计算机系统,几乎所有系统都连接到互联网,并且始终可能面临活跃的安全威胁和动态变化的环境。关于补丁的所有事宜,在过去二十年中发生了翻天覆地的变化,尽管大部分重大变化在 2001 年左右就已经发生了。
今天,修补工作往往主要集中在弥补最近发现的安全漏洞,每一步都在急忙将补丁推向市场,以防坏人发现漏洞并加以利用。恶意行为者知道,对于任何漏洞,补丁都会很快发布,因此漏洞利用完全是关于速度。在某些情况下,正是补丁的发布本身提醒了更广泛的社区漏洞的存在,因此发布补丁的行为触发了每个人都必须应用该补丁的紧迫需求,而这在几个小时前是完全不必要的。
因此,快速修补漏洞极为重要。基于漏洞修补的攻击很可能已经在发生,并且会在即将消失的漏洞最后一刻加剧,或者会在一个之前未知的漏洞成为公开知识后迅速开始。对许多人来说,这意味着我们希望将修补工作以小时而非天数来考虑。我们仍然需要考虑在生产时间内可能发生的潜在稳定性风险或影响,因此立即修补通常不是一种选择,但在合理的情况下,当然是可能的。
在 Linux 中,由于修补一般既快速又简便,且几乎总是可靠的,因此在某些情况下,可以考虑在生产日内进行修补,在大多数其他情况下进行每日修补。可能的智能方法包括使用内置的随机生成器,每四到八小时随机修补(为了减轻系统负载),或者每天晚上十点或其他合适的时间进行计划性修补。
在极端环境下,按周进行修补是可行的,这在一到二十年前的企业中很流行。如今,等待长达六天来修补已知漏洞几乎是鲁莽的,应该小心进行。六天在暴露系统漏洞的世界里是非常长的一段时间。
时间框架的选择通常基于工作负载模式。一些工作负载,如电子邮件或库存控制系统,可能对短暂的中断不太敏感,可以快速回滚或切换。因此,在一天中午间进行修补可能是合理的。大多数公司都有一天内周期性的工作负载模式,可以预测某个应用程序在凌晨一到两点使用非常少,或者也许到晚上七点每个用户都已注销,甚至十小时的停机也不会被人察觉。
无论是否存在日内模式,我们几乎总是会看到按周计算的日间模式。某些工作负载可能在周末较轻,而在工作日较重,反之亦然。有时,尤其是在金融应用程序中,模式更加偏向月度,通常月初的负载较重,而月中较轻。
每个工作负载通常需要评估,以了解何时进行补丁是合理且可行的。有时我们必须在时间安排上富有创意,以便在工作负载允许时进行补丁。如果工作负载无法中断进行补丁,那么它们也不能经历其他更不计划的停机事件,我们应该有一个连续性计划,允许我们在发生任何问题时进行补丁、修复或故障切换。在大多数情况下,我们可以通过这些方法进行零影响的补丁操作。
过去那种认为补丁可以作为一个特殊的每月活动来保存,或者只有在识别到组织的特定需求时才进行补丁的想法,已经不再现实。等待这么长时间会使系统处于危险暴露之中,任何声称每月只有一次补丁机会的工作负载都应该质疑,怎么会有既重要又无法进行补丁的工作负载。从概念上讲,这两者是无法并存的。工作负载越重要,及时进行补丁就越重要。
一个常见的缓慢补丁流程的借口是,补丁发布前需要进行测试。表面上看,这有道理,听起来也合情合理。你可能能将这个想法卖给非技术管理层。想要测试补丁本身没有问题。但我们必须考虑到,我们已经在支付(或免费获得)分发供应商来测试补丁,等我们收到补丁时。那些企业级操作系统供应商(如 Canonical、IBM、SUSE 等)拥有比任何但最大规模的组织更多的技能、经验和资源来测试补丁。如果我们的测试没有为我们已经依赖的广泛测试增加什么重要的内容,那么我们自己的内部测试过程应该避免,以免浪费资源并让组织面临不必要的风险,延误可能至关重要的补丁部署。
如果保持足够轻量并且绝不作为推迟及时补丁更新的借口,快速而轻量的测试是合理的。一种常见的有用补丁测试方法是,选取几个代表你组织中典型工作负载环境的系统,运行演示工作负载,在补丁发布之前先对每个补丁进行测试,以便观察安装成功并在最高级别进行测试。这可以在小型组织中仅仅是一台虚拟机。考虑是否有任何测试是有价值的,如果有的话,尽量保持测试轻量化,以确保生产环境中的补丁更新尽可能迅速地完成,前提是满足工作负载的需求。
标准的补丁策略通常会建议你先从高风险的工作负载开始,或者从低优先级的工作负载开始,专注于修复漏洞,或者使用低优先级工作负载作为测试对象,为更关键的工作负载做准备。如果你的环境中有一百台虚拟机需要补丁,你大概可以安排一个时间表,首先补丁那些不那么关键的系统,随着对补丁流程信心的逐步建立,慢慢接触更多关键或脆弱的工作负载。
把补丁管理看作是系统管理员最重要且简单的任务之一。不要让情绪或那些不了解补丁管理(或受 Windows 管理员影响)的企业或系统管理员的非理性建议将你引偏。补丁管理是至关重要的,任何不支持补丁管理流程的组织管理层都不了解该过程的风险与回报,我们需要准备好向他们解释这一点。
找到一个满足你所在组织需求的补丁管理流程。你不需要按照固定的时间表进行补丁更新,也不需要按照其他组织的方式进行补丁管理。找到适合你的测试方法以及手动或自动补丁流程,以确保你的系统在不对组织造成过度影响的情况下保持更新。
到现在为止,我们应该对补丁的概念有一个相当扎实的理解,你可能甚至已经感到一种紧迫感,想去检查一下你当前的服务器,看看它们最近是否有更新。这是可以理解的,如果你现在想查看一下它们,在继续之前,我愿意等你。安全总比后悔好。等你回来后,我们将讨论软件编译,并将该过程与补丁管理联系起来。
管理员的编译工作
还不久前,主要的系统管理员指南中包括了一项要求,即任何中级或高级管理员都必须熟悉标准软件编译过程的细节。当然,所有的知识都是有价值的,我们绝不会说不应该学习这些内容。然而,即使在当时,这也显得像是一种奇怪的幕后开发知识以及关于单个软件解决方案打包的知识,居然被期望由一个非开发角色的人来掌握。
这就像是从你最喜欢的汽车公司订购一辆新车时,要求它以零件的形式交付,并且每个潜在的新车主都需要在驾驶之前自己组装汽车一样。值得注意的是,这一过程仅在开源世界中才可能实现,而且除了 Linux 领域,大多数软件甚至 Linux 领域中的一部分软件根本无法由系统管理员进行编译。因此,整个这一要求的概念几乎只适用于一种非常特定的情况,并且在系统管理的广泛意义上并不适用,仅这一点就应当成为那些将其作为教育和认证标准的组织的一个严重警示。
作为系统管理员,要求我们从开发者那里获取源代码并进行定制编译,使用我们提供的编译器在我们自己的环境中进行编译,这几乎是荒谬的。在 Windows 环境中,这几乎是不可能的,谁会有权限访问合适的编译器或任何必要的工具呢?在 Linux 和 BSD 系统中,这通常是可行的,因为编译器或多个编译器可能已经包含在基础操作系统中。
曾经,目标系统上的编译有其价值。通常,通用编译的软件由于需要支持几乎任何潜在的硬件,效率往往较低,而通过在目标上编译,我们可以充分发挥非常特定硬件组合的每一点性能。然而,这也是一个由于 CPU 性能有限而导致编译时间很长的时代,这意味着系统的安装可能需要几天,而不是几分钟。软件部署是一个漫长、复杂且容易出错的任务。在现代世界,浪费时间和资源来编译大部分软件几乎是不可想象的。当我们可以在短短几分钟内部署整个服务器群,并且使用极少的系统资源时,仅仅为了完成相同任务而占用大量 CPU 周期并花费几个小时,从资源角度来看,这完全没有意义。
然而,编译带来的风险远不止浪费时间和系统资源。它还意味着,我们可能会在不同的系统上得到略有不同的结果,或者在不同的部署时间、我们测试过的系统上,甚至更重要的是,在供应商已经测试过的系统上。正如之前所讨论的,面对补丁测试场景的挑战时,编译使得测试变得更加困难。同样,补丁也变得更加难以应用。
一些软件今天需要进行编译以便部署,通常是那些依赖特定硬件驱动的桌面软件。这类软件通常出现在桌面端,而不是服务器上。并不意味着我们永远不会遇到它,但它应该是相当罕见的。从技术上讲,自行编译软件并不错误,但只有在绝对必要并且具有非常必要的目的时才应该这么做。它不应当是随意进行的,今天的系统管理员没有必要了解编译过程。
现在有一些新的额外因素出现,使得将编译作为一个标准过程变得不太可能。二十年前,Linux 生态系统中只有一个主要的编译器,大家都假设所有以代码形式部署的软件都会用 C 语言编写,并且由开发团队针对那个编译器进行测试。当时有一个非常标准的工具链,大家普遍认为它就是所需的工具链,而且几乎总是正确的。如今,不仅有多个标准编译器在不同的项目中使用,且各项目为了测试使用不同的编译器,还有一些常用的编译语言,它们也有自己独立的编译器和工具链。
编译从来都不是一个单一的标准过程,尽管曾经有这种暗示。然而,传统上它几乎就是一个标准过程。如今,正如之前提到的原因,编译已经变成了一个分散的过程。除此之外,许多需要最终用户进行编译的项目现在已经内建了一个编译过程,使得它更像是一个独立的部署工具,而不需要系统管理员了解编译过程,甚至不需要意识到所部署的软件正在进行编译!这个世界几乎在每个方面都发生了变化。
在现实世界中,我曾在成千上万台服务器上工作,跨越数千个客户,并且已经有超过十七年没有见过任何组织使用假定的标准编译过程了。即使在十七年前,编译过程也极为罕见,可以忽略不计,而且通常在系统管理员将业务视为个人爱好而非严肃事业时,才会在可疑的情况下使用。
编译时代
在 Linux 的早期,能够自己编译软件通常是一个重要特性,相比于封闭源代码系统,如 Windows 和 Netware,这些系统的编译器并不是免费的,且操作系统代码也无法获取。这意味着可以在不同的架构之间轻松迁移,而当时系统资源是宝贵的,因此通过定制编译获得的微小性能优势,有时意味着软件性能的真正差异。系统管理员曾经非常热衷于编译器标志和版本。
这种趋势非常显著,以至于整个操作系统的发布都围绕这一概念进行。最著名的例子是 Gentoo Linux,它每次部署时都要重新定制编译整个操作系统。这常常导致人们讨论安装完整操作系统需要多少天。初始安装的投资非常庞大。
在 1990 年代,操作系统的安装常常需要花费多天时间。我们很少使用虚拟化技术,因此安装通常是从物理介质到独特硬件的安装,即使一切顺利,这个过程也非常耗时,而且经常会遇到安装故障,导致需要多次尝试安装。在那个环境下,花时间编译软件,甚至是整个操作系统,也不像今天这样疯狂。但是放心,这样做也并不是完全理智的。
与由于资源限制而使编译有意义的那个时代相重合的,是互联网前的办公室世界和初步的互联网世界,那时环境威胁,特别是试图利用未打补丁的计算机的威胁,还是比较罕见的。当然,计算机病毒是存在的,且广为人知,但通过不在系统之间共享物理介质来避免它们,能在良好管理的情况下大大减少感染的可能性。因此,大多数时候,定制编译软件的打补丁问题并不构成困扰。这是设置并忘记软件的时代。编译过的软件更可能被遗忘,而不是被维护。安装过程的努力使得打补丁的潜在工作量巨大且风险极高。当你自己编译代码时,很多事情可能出错,最终导致你没有一个可用的系统。
过去,CPU 和 RAM 资源在大多数系统上都非常紧张,通常情况下,能够多等几天才能将系统投入生产是值得的,即使只是为了获得额外的百分之一的性能提升。往往被忽视的是,若编译初始安装需要消耗那么多时间和资源,那么未来编译补丁或更新时,可能需要相同甚至更多的资源。这带来了巨大的风险,通常会导致完全没有补丁更新,因为一旦系统部署完成,几乎没有办法停机几个小时或几天进行编译步骤,希望能更新系统。
在信息技术领域,常常有一种强烈的愿望,想要建立一座纸牌屋,并希望当它倒塌时,足够远的时间可以让它变成别人的问题。遗憾的是,这种做法逐渐成为一种可行的策略,因为公司很少将失败与造成失败的人联系起来,而是常常随机地责怪身边的任何人。正因为如此,创造风险情况通常是有利的,因为任何收益都会归功于实施者,而任何灾难则会在稍后随机归咎于某人。
现代的系统管理员仍然应该学习传统的软件编译方法,哪怕只是为了理解历史背景,并为可能出现的任何异常情况做好准备。但今天(以及多年来),将编译自己的软件作为标准流程应当避免,作为经验法则,这根本不是一种资源的好利用方式,而且会引入太多风险而没有实际的好处。
现在进行编译时,不能再像过去那样盲目地遵循通用过程了。过去那种保护了许多仅仅凭运气的管理员的惯例,如今已经不再适用。今天要进行软件编译,我们需要开发者的指导和指引,才能有任何希望了解需要哪些工具、配置、库、语言和外部包,以及如何使编译过程正常工作。这里有太多潜在的可变因素,所有这些知识都是开发者的知识,而不是 IT 知识,更不用说系统管理员的知识了。系统管理员需要掌握并深入理解的信息非常庞大,是技术领域中最广泛、最具挑战性的领域之一。让系统管理员深入学习一个完全不同领域的知识和技能,从来没有任何意义。如果所有的系统管理员都能同时完成这些工作,那开发者为什么还要存在呢?软件工程是一个庞大的领域,需要深厚的知识才能做得好;暗示一个完全不同的学科能轻松地担任开发者角色,而不需要同样的多年训练和全职投入,这不仅荒谬,而且对开发者极为侮辱。
工程部门编译
我们应该提到一个中间方法,它是合理的。那就是有一个工程小组,从开发者(通常是内部定制团队或开源项目)那里获取源代码,并进行内部编译,可能是为了额外的安全步骤,或者极端的性能调优,亦或是因为该软件需要特殊的编译方式,比如与内核版本或驱动程序相关联时。
通过设立一个中心小组,负责将源代码内部编译并打包成最终的二进制文件供系统管理员团队使用,可以让系统管理过程专注于标准化、可重复且快速部署的二进制机制,同时组织还可以享受定制化编译的优势。
这种方法通常只适用于能够维持快速软件打包工作流的大型组织,以便补丁、测试和定制化几乎能像由软件供应商直接完成一样迅速。在大规模环境下,这种方法可以带来好处。
这一过程之所以有效,是因为它避免将软件编译和打包交给管理员处理,而管理员在这方面会遇到很多麻烦和问题。
最佳实践是在需要时才编译软件,而不是随意进行编译,除非你有一个能够快速可靠地处理已编译软件打包的部门,且其速度足以满足适当的补丁管理需求,同时执行这项工作所产生的开销能通过规模效益得到弥补。
编译是有用的知识,但仅仅因为你能编译软件,并不意味着你应该。将这个技能保留在你的后备知识中,只有在真正需要时,或者当软件供应商指示你这么做时再使用。接下来,我们将讨论如何部署我们的 Linux 发行版本身,甚至更重要的是,在灾难发生后,如何重新部署一个发行版。
Linux 部署和重新部署
如今,我们有许多潜在的方法来部署,甚至更重要的是,重新部署我们的服务器(或者工作站)。在我看来,这个话题在过去相对不重要,因为大多数公司依赖于缓慢的部署方法,它们的灾难恢复模型依赖于恢复,而不是重新部署系统。但今天有了更多现代化的灾难恢复方法,这些方法依赖于能够快速部署服务器,因此我们必须以全新的眼光来看待这个话题。
借助现代部署技术和方法,能够在几秒钟内部署一个新的基础操作系统已不再罕见,而过去,即使是高度自动化的系统,往往也需要花费许多分钟甚至小时(更不用说定制编译系统可能带来的复杂性了!)。当然,今天的计算机速度更快,这在加速部署过程中起了作用。供应商也改进了安装程序。这不仅仅是 Linux 的特色,几乎所有操作系统都如此。
即便是做最传统的基于 ISO 的安装,我们通过 DVD 镜像进行安装,或者从 USB 媒体或虚拟媒体中安装,通常也能在几分钟内从头开始手动完成操作系统的完整安装。在正常硬件上,可能需要十到十五分钟。这与近二十年前的安装方式相比,已经算是非常快速了。
在较大的环境中,传统上会使用类似响应文件的方式来加速这些安装过程,使其更加高效且可重复。这个过程通常意味着将你的安装 ISO 文件存储在网络的某个地方,存储一套安装指令文件,并在其他地方定义系统,通常会列出 MAC 地址来分配适当的配置文件。基本上就是在执行传统安装时自动化人类的响应。有效,但略显笨重。
如今,任何形式的 ISO 或类似介质的安装通常仅用于真正的手动安装,这些安装一般由非常小的公司进行(这些公司通常只构建几个服务器,而且每个服务器可能都是独一无二的)或特殊情况。旧的响应自动化方法没有错,但如今有这么多更新的选项,它已逐渐被淘汰,并继续失去作为流行安装方法的吸引力。在虚拟化之前,它在安装自动化选项很少的时代确实最为有效,且安装通常是每个物理设备一个操作系统,这使得基于 MAC 地址的管理非常有效。今天,这种方法对于平台(虚拟化管理程序)安装仍然有效,但对于操作系统安装就不那么适用了。
虚拟化的出现意味着两个大变化。首先,安装到物理服务器裸机上的虚拟化管理程序很少会进行定制,除了最基本的选项,这减少了对自动化的需求(整个安装过程也变得更小)。其次,操作系统安装现在是在非物理空间中进行的,这为更多以前无法获得的特殊安装技术打开了大门。
在虚拟空间中,我们可以继续手动安装系统,许多人仍然这样做。我们可以继续使用响应文件,尽管我知道现在没有人继续这样做,但我相信这仍然是广泛实践的,特别是因为已经有许多大规模半自动化部署系统可供使用。然而,现在我们可以轻松地使用预构建的系统镜像,从库中调用它们来实现更快的安装。采用这种方法,已经构建好的系统只是被复制或克隆来创建新系统。初始镜像可以预先配置最新的补丁和自定义包,通常可以在一分钟内完成安装;有时甚至只需要几秒钟。如果使用某些类型的存储,它的执行速度可以快到几乎瞬间完成。通过容器,我们有时可以看到新系统被初始化得如此迅速,以至于几乎察觉不到有构建过程的存在(因为从实际操作来看,根本没有)。
你选择用于部署服务器的方法并不是最重要的因素。所有这些部署方法,包括更多的选项,都有其适用的地方。我们需要考虑的是,通过你选择的过程,如何更快速且可靠地构建新的系统。当需要新的工作负载时,知道我们可以在一定的时间内构建一个新的服务器,并对其最终配置充满信心,是一件很好的事情。如果一个文档齐全的手动过程能够达到可接受的结果,那也没问题。
对于许多企业来说,快速部署的能力并不是非常重要。真正重要的是重新部署的能力。当然,对于某些类型的应用程序,例如那些非常适合云计算的应用程序,快速的初始部署是至关重要的,但这仍然是一个小众的做法,而不是常态,并且在可预见的未来仍将如此。但重新部署通常意味着某种程度的灾难已经发生,系统需要恢复功能,而在这种情况下,我们几乎总是面临着尽快将系统恢复到生产环境的压力。
因此,在我们的环境中,通常是重新部署速度,而非部署速度,才是更为重要的。然而,由于灾难恢复很少以这种方式来考虑,这一点在唯一能够现实地影响的时刻——也就是说,我们只能在初始设计和实施阶段真正解决这个问题,但通常直到为时已晚才会注意到——往往被忽视。此外,重新部署需要有信心地进行,以确保我们快速构建的内容按预期构建并按预期运行。在这些匆忙和压力下,很容易遗漏步骤、忽视过程、走捷径并犯错。
我们的系统越快、越自动化,我们就越有可能在高压环境下反复交付相同的系统。在我们制定初始部署计划时,我们应该为这种情况做准备。能够重新创建系统,而无需依赖备份和恢复机制,对于许多公司来说可能是一个游戏规则改变者,尤其是当他们常常感到被迫依赖单一方法来将系统重新上线时,而在许多情况下,可能存在更优的替代方案。我们将在未来章节中深入讨论备份时详细讲解这一点。
允许我们快速恢复的过程还可以为我们的工作流带来更大的灵活性。测试补丁、部署、配置、构建临时系统等的能力,灵活性关乎于应对未知的风险。
最佳部署实践是评估时间,以设计最适合你环境的可靠部署方法,并根据实际情况简化这个过程,以便能够在适合你环境的时间内恢复基准操作系统。
一些环境能够如此快速地构建新服务器,并为其必要的工作负载进行配置,以至于它们实际上选择在执行诸如修补、更新,甚至可能是重启等活动时,直接选择这样做!相反,它们会迅速构建并部署一个全新的虚拟机或容器,并销毁旧的虚拟机。这是一个非常有效的做法,前提是你能让这个过程为你服务。
在接下来的部分,我们将讨论在常规、频繁和计划性的条件下重启和测试环境的重要性。
重启服务器
向普通的系统管理员,甚至是对技术感兴趣的非技术人员询问,他们会告诉你服务器长时间正常运行的重要性,以及他们希望看到这些超高的重启后的时间。这似乎很自然,几乎每个人都会为此自豪。我的服务器三年都不需要重启!
然而,这背后有两个关键问题。
第一个问题是,重启后的时间本身没有商业价值,而商业价值决定了 IT 价值。那么,为什么我们要在乎,甚至吹嘘某件没有价值的事情呢?知道一个系统在线多久或许很有趣,但投资者并不会因为计算机系统在长时间内没有重启而获得回报。我们为的是业务的好处,如果我们开始关注除了最终业务价值之外的事情,那我们就迷失了方向。这种情况发生在我们关注手段而非目的时,服务器的正常运行时间容易携带情感价值,看起来好像它可能带来好结果,因此,我们作为人类,常常喜欢在心中设置代理来简化评估结果,而正常运行时间常常被视为稳定性的代理,而稳定性又被视为商业价值的代理。所有这一切都是错误的,这些代理并不准确,甚至更糟,它们可能被颠倒了。
第二个问题是最大的——高正常运行时间本身代表了一种风险。这是未知的风险。随着时间的推移,我们的系统会发生变化,从硬件的磨损到补丁、更新以及软件的常规变动。可能会出现数据损坏或无法恢复的读取错误。也许会有配置更改不按预期工作。无论是否有人做出过系统更改,都会有许多不可预知的事情发生。而且,距离上次重启越久,我们对系统的反应就越没有信心。
我们必须在合理的范围内始终对重启的效果充满信心。我们并不总是能控制重启的时机。我们可以尝试使用冗余电源和冗余组件,但每个系统都有可能重新启动,当它们重启时,我们希望能够高度自信地确保它们能顺利重启。
重启过程会给服务器带来许多风险。它需要重新加载大量从磁盘或其他存储位置读取的数据,这些数据可能自上次重启以来没有被完全读取,因此潜在的损坏或其他存储问题的风险会增加。它对物理系统造成压力,尤其是当物理重启与软件重启结合时。此时你可能会发现某个文件丢失、文件损坏,或者内存条终于开始出现故障。
乍一看,我们可能会认为故意重启系统似乎很疯狂,为什么要故意促成故障的发生呢?但这正是我们想要的。我们故意诱发潜在的故障,以期在其他时候避免它的发生。
这里的逻辑是我们在一个方便或安全的时间进行重启,即一个绿色区间。如果在我们重启的时刻发生了硬件故障,或者发现了一个未知的软件问题,那时我们知道是什么触发了问题(计划重启),上次重启是什么时候(希望不是很久前),中间发生了什么变化(如果是软件或配置问题),或者重启就是硬件故障暴露的时机。这应该发生在我们为修复潜在问题而预定的时间段。
找到你的绿色区间
你的维护窗口或绿色区间是一个特定的时间段,在这个时间段内,工作负载被认为是不可用的,以便进行常规管理任务。典型的任务可能包括重启、软件安装、打补丁、数据库重新索引、磁盘碎片整理或其他需要高负载的任务。每个行业、公司,甚至每个单独的工作负载都会有不同的时间段适合分配绿色区间。不要期望一个公司正确的绿色区间能适用于另一个公司,甚至是同一公司内部的不同业务单元。
一个常见的绿色区间是周末。对于许多公司来说,一些甚至所有的工作负载可以安全地在从周五晚上到周一早上期间不可用,而不会对业务产生任何影响。通常,除非是 IT 部门,否则其他人甚至不会知道这个情况。如果情况确实如此,一个好的策略是,在周五晚上绿色区间开始时几乎立即进行任何打补丁或类似任务,接着立刻进行重启。如果重启导致任何故障,你将有超过两天半的时间来恢复系统,直到有人进来抱怨系统崩溃。两天的无影响时间可以让你进行更好的修复,而不是在压力巨大、资金损失、业务急需答案的情况下强行修复系统,而这时你还要集中精力解决问题。
根据我个人的经验,我曾管理过一个应用程序,在这个程序中,我们测量了数据库记录,发现这些记录每周至少有一分钟的时间内不会被使用,这个规律在所有系统客户中都存在。这使得我们可以有效利用仅仅 60 秒的时间窗口,但如果我们进行仔细规划,就能够在这个时间内进行系统重启、软件更新、打补丁等操作。虽然这样做并不特别方便,但相比于要求客户提供一个通用的维护窗口,或者为这一分钟运行额外的系统来进行覆盖,这种方式是非常具备成本效益的。
绿色区间可能具有创意性,且可能在你意想不到的时候出现。它们可能像长周末那样简单,或者可能发生在每周例行的周二午餐会议期间。与工作负载的客户合作,了解何时工作负载未被使用或不面临风险。
这实际上完全是关于规划的。只有在我们实际可以恢复系统时才触发问题。这样,我们就不太可能在我们无法提供支持或工作负载正在重度使用时,遇到相同的问题。绝不让任何业务说工作负载太重要而不能有计划的停机时间,这种说法是自相矛盾的。我们之所以有计划的停机时间,正是因为工作负载至关重要。如果某个工作负载不重要,那么直到出现故障才进行维护并不成问题。工作负载越关键,计划停机时间就越重要。事实上,任何没有停机时间(至少在系统层面上)的工作负载,都可以被认为是不关键的或非生产级别的,仅仅因为没有计划的维护。
相比汽车,你越重视一辆车,就越可能将其停用进行定期维护,比如换油和检查刹车。你这么做是因为计划性维护是微不足道的,而非计划性故障的发动机则不然。我们自然知道,维护汽车总比让它们发生故障要好。我们的服务器也不例外。
避免计划停机时间就等于为非计划停机时间做准备。
如果某个工作负载没有合理的停机时间容忍度,那么就需要采取额外的策略。例如,如果你是亚马逊经营全球在线商店,即使是一分钟的停机时间,也可能导致大量销售损失。如果你是一家投资银行,停机一分钟可能意味着订单未能正确完成,从而造成数百万美元的损失。如果你是一家医院,停机一分钟可能意味着危急生命支持系统失效,导致死亡。如果你是军队,停机一分钟可能意味着失去一场战争,因此有些类型的工作负载中断我们真的希望避免,这是毫无争议的。显然,在某些时候,我们需要采取极端措施,确保停机时间不会发生。
在这些情况下,我们需要一个高可用性水平,允许我们将基础设施中的任意组件下线。这可能是存储、网络,或任何数量的平台和计算资源。这意味着在应用层面也需要一定的高可用性,以便我们能够适当修补从硬盘固件到应用库的所有内容,甚至包括其中的每一环节。
关键工作负载需要平稳运行且高度安全的基础设施来确保其持续运行。一个良好的维护计划是确保工作负载可靠性的核心所在。
关于重启频率没有硬性规定。但一个好的起点是每周重启,并从中评估什么是适合你环境的。我们往往选择每周或每月重启,因为我们通常知道重启是必要的,但我们仍然认为应该避免重启。但在少数情况下,这种想法并不成立。我们真正想要做的是在被认为安全和明智的情况下,尽可能频繁地重启。
在当前的补丁管理制度下,每月重启大约是你可以考虑等待标准计划的最长时间。记住,任何计划都需要考虑到系统被错过的情况,必须等待额外的周期。所以,如果你计划每月重启,你需要接受有些系统偶尔会因为技术或物流问题而两个月没有维护。
每周重启通常是最实用的计划。大多数工作负载都有每周的使用模式,这使得分配维护窗口变得容易,或者至少是可行的。每周重启计划对用户也很有利,因为它们很容易记住。例如,如果一个系统每周六早上九点重启,用户就会习惯于此,即使他们当时想工作,也不会在此时使用系统。这会变成一种习惯。每周重启足够频繁,这样重启过程增加的风险很可能会暴露出即将在接下来的六天内发生的硬件或软件故障。这通常是方便性与可靠性之间的最佳平衡。
我们应该始终评估更频繁重启的机会。如果我们的工作负载安排允许,举例来说,每天重启是非常合适的。这也是我们通常处理终端用户工作负载的方式,鼓励系统在一天结束时重启,这样员工到达工作地点时(无论是虚拟的还是实际的都无所谓),系统已经焕然一新,准备好迎接新的一天。对服务器做同样的处理可能也是有意义的。
你的重启计划应该考虑到你的应用程序更新计划。如果你运行的软件更新很少,那么每月重启可能更为合理。如果你有几乎每天都在更新的工作负载,那么将系统重启与应用程序更新结合起来可能更有意义。
系统重启在软件更新和主要工作负载(通常假设不由操作系统供应商管理)之后尤为重要,因为有很多可能性会导致服务无法按预期启动,需要额外的配置,或者仅仅是在重启时遇到故障。如果你在进行软件更新时不重启,你就无法完全确认安装时重启是否成功。如果稍后出现问题,知道在上次系统更改时重启是成功的,这有助于加快恢复过程。
如果定期重启系统的遗忘是一个常见问题,那么忘记进行重启监控几乎是无处不在的。即便是那些认真对待重启计划的 IT 部门,通常也从未想到将正常运行时间监控添加到环境中的监控传感器列表中。重启监控通常非常简单,并且一般可以相对宽松地执行。例如,在我管理的许多环境中,我们希望服务器每周重启一次,我们会添加一个监控项,监测正常运行时间超过九天。如果我们的监控系统发现服务器的正常运行时间超过九天,它将发送警报邮件。错过一次重启事件并不是一个大问题,这样就有足够的时间避免误报,并有足够的时间规划手动干预,查找导致计划重启失败的原因,并在下次计划重启之前将问题修复。
这里的最佳实践是尽可能频繁地重启系统,除了有充分的业务需求外,不要避免重启,系统无法宕机的错误需求不能作为理由。争取每周重启,甚至是每日重启,如果只能做到每月重启,也要接受,并确保添加监控,因为没有重启的系统是难以通过日常检查发现的。
总结
系统的修补、更新和重启可能会让人觉得非常教条。在某些方面,我想它们确实是。但是,有时候真的很重要的事情也可能有些枯燥。实际上,修补和基本的系统维护应该是枯燥的,它应该是可预测的、可靠的和按计划进行的。如果可能的话,它应该是自动化的。
修补不应成为一个挑战或可怕的提议。通过适当的规划、备份、测试等,通常很容易拥有一个可靠的修补甚至更新流程,这样的流程极少会遇到任何重大问题。如果我们未能让我们的修补和更新变得定期和可靠,我们将开始害怕这一过程,而这几乎肯定会导致我们避免修补和更新,进而加剧问题。
在现代计算世界中,总有人试图利用我们的系统,虽然没有任何东西可以防御所有可能的攻击,但我们可以通过快速、定期和可靠的修补大大减少我们的暴露面。
现在,你应该能够自信地评估你的工作负载,确保它们都更新到最新,并开始在你的服务器群体中实施一个正式的修补、更新和重启计划。
在我们的下一章中,我们将讨论数据库以及它们应如何从系统管理的角度进行管理。
第六章:数据库
技术上,数据库系统是运行在操作系统之上的应用程序,对于我们作为系统管理员来说不应直接关注。这是一个很好的理论。然而在现实世界中,数据库与操作系统密切相关,往往是通用的知识项目,需要深入的技术知识,而总体上需要的时间相对较少。因此,普遍来说数据库管理的责任落在系统管理员身上;特别是在当今的 Linux 发行版上,因为我们可能使用的大多数数据库已经与操作系统捆绑在一起。
在本章中,我们将学习以下内容:
-
将数据库与 DBMS 分离
-
比较关系型数据库和 NoSQL 数据库
-
在 Linux 上发现常见的数据库
-
理解数据库复制和数据保护概念
在旧日的好时光,系统管理和数据库管理几乎总是两个独立的任务。系统管理员(SA)和数据库管理员(DBA)角色会密切合作,但是由于各自角色的专业技能和大量时间需求,它们通常是独立的、专门的工作人员。通常情况下,每五到二十名系统管理员只需要一个数据库管理员,因此团队规模较小,职业领域也总是较小,因为即使在没有数据库需要管理的公司中,系统管理员角色仍然存在。
随着操作系统和数据库管理系统变得更简单、更健壮,需要对数据库平台进行大量调整的需求已经减少到几乎可以忽略的程度,因此 DBA 职业道路几乎已经消失。今天已经不存在建立在单一数据库平台周围的职业需要。管理数据库的人通常会管理各种不同的数据库,可能在多个操作系统上。
随着时间的推移,大多数关键工作负载变得商品化。我们的意思是,它们从专门知识转变为通用知识。这些的典型例子包括电子邮件服务器(MTA)和网页服务器。二十年前(大约在 2001 年),运行这些服务器是高度专业化的知识,只有非常少的系统管理员才会理解其中的工作原理。通常你会有一个专门的操作系统管理员,然后有一个专门的电子邮件管理员或网页管理员,专门管理他们所擅长的单一应用程序。那时不会是所有电子邮件服务器之类的情况。管理一个单一的邮件服务器,比如 Postfix 或 Exchange,往往是一项专业技能。你的知识将完全集中在这个单一产品及其独特的特点和需求上。这种情况非常极端,以至于像 Postfix、Exchange、Apache、MS SQL Server、Oracle 数据库、IBM DB2 等产品,都有专门的认证和职业发展路径。如今,我们只是默认任何有经验的系统管理员都能够管理任何电子邮件、网页或数据库服务器。
由于数据库非常复杂,并且在过去几十年中已经发展成为远超其过去的形态,因此作为系统管理员,我们应该普遍理解其中的许多概念。数据库是高度状态化的,代表着文件系统和一般存储子系统的二级存储层。它们并不代表特殊情况,而是需要我们深入理解的通用情况的广泛应用。网页服务器、电子邮件服务器和其他应用程序仍然很重要,但它们代表的是应用设计中的标准预期情境,因此在这种情况下不需要特别的考虑。直白地说,数据库用于存储数据,并且极其脆弱。其他应用程序使用数据库或文件系统来存储数据,因此从管理的角度来看,它们比较简单。正因为数据库代表了第二层数据存储层,它才被视为特殊。
为了以系统管理员的方式处理这一问题,我们将从深入了解数据库是什么、它是如何工作的以及为什么它成为一种存储形式开始。然后,我们可以研究常见的数据库类型及其在 Linux 发行版中的具体情况。最后,我们将通过探讨数据库的最重要方面——如何保护它们,来结束本篇内容。
让我们开始吧,弄清楚数据库究竟是什么,以及为什么我们如此关心它们。
将数据库与数据库管理系统(DBMS)分开
就像生活中大多数事情一样,关于数据库的术语往往不准确,许多高度技术化且具体的术语被用来主要指代与其原本含义不同的东西。但通过深入了解数据库到底是什么,以及它们如何几乎普遍地工作,并在这个话题上建立正确的语义,我们将从系统管理员的角度,建立起对数据库需求的几乎内在理解。通常来说,找到准确的描述方式本身就能帮助我们理解。数据库并非魔法,但往往被当作魔法来看待。
数据库
我们必须首先问一下,什么是数据库?《牛津词典》对数据库的定义是在计算机中保存的一组结构化数据,特别是可以通过多种方式访问的数据。嗯,这样的定义并没有告诉我们太多。不过,从某种程度上说,它其实说了些东西。数据库不能是无结构的;这是最重要的一点,计算机存储的东西,比如文件,也都是结构化的。所以,数据库是计算机中存储的结构化数据,可以是存储在磁盘上的文件或文件集,或者它们存在于计算机内存中,永远不写入磁盘。在后一种情况下,数据库是短暂的,对系统管理员来说并不重要。但在前一种情况下,代表了百分之九十九以上的使用案例,这个问题就非常重要了。让我们给出一个作为系统管理员可以有效使用的定义:数据库是包含结构化数据的文件或文件集。
你可能会立刻跳出来说,但是我运行的是一个数据库,它是一个服务,而不是文件——我可以与它互动! 我们会很快解决这个问题。跟我走,数据库其实就是文件。
我们应该从一些例子开始,因为这有助于快速理解我们的意思。假设我们有一个标准的文本文件,也许是我们写下的一些笔记。这是一个文件,但它是数据库吗?不是的,它不是。没错,文件是用某种 ANSI 字符标准编码的,但数据是临时的,没有结构。我们可以手动给文件添加结构,这样做是可以的,但文件和读取该文件的工具并不知道这些结构。任何结构对于使用它的人来说是可访问或可见的,但对系统本身不可见。这是无结构的。
好吧,那么文本文件不是数据库。那么 Word 文件呢?一样的道理。它可能有比文本文件更强的格式,但 Word 文件中存储的内容完全没有结构。我们可以在文件中随意放入任何内容,放在任何地方。它是无结构的。
那么,电子表格文件呢?就像我们用 Excel 或 CSV 时得到的那样?这是一个棘手的问题。我们进入了一个灰色区域。在正常情况下,这些文件并不被视为数据库,但名义上它们是。我会把它们称为半结构化的。它们包含一些结构(你可以看到的是单元格),并且有一种方法来指定该结构中包含的内容,以及某些数据组(即表现为列或行的数据),这些数据被期望相互关联。但单元格内或单元格之间的任何结构都没有被建议或强制执行。因此,虽然有结构,但我们通常认为它没有数据库所需的结构那么多。我们称之为“也许”。不要在下一个 IT 鸡尾酒会上拿出CSV文件,并试图为它辩护是新的数据库格式,因为这是站不住脚的。它仅仅是作为一个思维实验有意义。但我们可以看到,电子表格格式很容易有潜力像数据库一样发挥作用。
通过稍微增加一些结构化,我们开始看到真正的轻量级数据库文件的出现。XML 就是一个很好的例子。XML 比 CSV 这样的电子表格格式更有结构,可以作为一个完整的数据库使用。有些数据库格式就是基于 XML 的。XML 仍然只是 ANSI 文本,但具有足够的特定结构,可以让我们走向非常简单的数据库。XML 可能不是最强大的数据库,也不是使用最快的数据库,但它非常简单,并且在合适的用途下可以非常有效。
专门构建的数据库通常避免使用 ANSI 或类似的文本格式的多余膨胀,因为这会在软件使用时减慢系统速度,而且数据库本身通常并不是为了让人类直接阅读的。通常,会使用某种形式的二进制格式或甚至压缩来减少存储的读写时间,并尽量减少今天所需的存储空间。一个很好的例子是SQLite,这是一个免费的开源数据库,它使用高度优化、但公开的格式,如果有兴趣,你可以研究它。它仍然只是一个文件,就像其他任何文件一样,但比 XML 提供的结构更加丰富。
所有这些示例使用的都是每个数据库一个文件。但数据库使用多个文件并不是没有理由的。这样做的一个常见目的可能只是将数据拆分开来,以避免将所有数据存储在一个过大、无法轻松操作的单一文件中,或者数据可以按用途拆分。想象一下一个存储用户地址和用户电话号码的数据库。一个只包含地址的文件和一个只包含电话号码的文件会是一个合理的磁盘存储设计。
数据库引擎
现在我们知道什么是数据库。它其实就是我们存储的一个文件(或者多个文件),这些文件包含我们的结构化数据。我们假设在生产环境中,我们将使用一种高效的数据库格式,这种格式不是为了让人类直接打开和读取,这样做显然是不明智的。所以,计算机会读取、写入并操作这个文件或这些文件。
那么,计算机如何知道如何处理那个格式如此具体的数据库文件呢?在回答这个问题之前,我们应该先来比较一下存储。
在存储中,我们有一个标准的原始格式,称为块存储。在此基础上,我们实现了文件系统。这些文件系统通过提供操作系统可以用来存储和检索数据的标准文件访问格式,与操作系统进行交互。每个文件系统可以以不同的方式执行此操作。为了让操作系统能够与文件系统交互,它必须有一个文件系统驱动程序。
数据库的工作方式相同,但通常是在更高一层的堆栈中进行的。对数据库来说,文件系统是通用存储。高度结构化的数据位于文件系统之上,包含在一个文件或多个文件中。但就像我们需要操作系统驱动程序来知道如何与文件系统进行交互一样,我们也需要一个驱动程序来让应用程序知道如何与数据库进行交互!我们可以将其称为数据库驱动程序,但它通常被称为数据库引擎或数据库库。
文件系统实际上是数据库
这就是那些我们在 IT 领域工作的人应该理解的奇怪事情,而你永远不能在那个所谓的鸡尾酒派对上提出来,因为你永远无法说服任何人相信这是真的,但它确实如此。文件系统本身实际上是一种数据库形式。它们是磁盘上的高结构化数据格式,可以包含其他特定格式的数据,以文件的形式存储,包含关于这些文件的结构化数据,并且通常包含复杂的机制来搜索数据结构。文件系统在各个方面都是数据库。甚至包括它通常的使用方式。它们只是具有独特但极为常见的目的的数据库,这个目的重要到我们已经忘记了它在背后究竟是什么。
这与网络服务器实际上是文件服务器的情况类似,但它们是如此特殊的案例,以至于没人谈论它们本质上就是这样。理解它们是如何工作的非常有用,因为这有助于我们更好地理解它们,并且避免大脑在意识到它们之间有重叠时感到困惑,进而搞不清楚它们是如何分开的——因为它们根本就不是分开的。
这一点非常正确,过去有些高性能数据库甚至会放弃使用文件来存储数据,而直接存储在块设备上,这样它们的位置和文件系统通常一样。但因为没有文件,它们实际上并不是文件系统。但在所有实际用途上,它们却是。
这种替代文件系统的过程曾经很流行,是为了提升系统性能,因为文件系统曾经会给服务器带来显著的开销。今天,文件系统的开销已经微不足道,而试图替代文件系统带来的复杂性和问题已经变得如此庞大,以至于几乎被完全避免。
一旦你将数据库看作是数据的某种文件系统,一切就都变得更有意义了。
数据库引擎才是真正的魔法所在。数据库本身仅仅是存放在磁盘上(或内存中的)数据。没错,它有结构,但这个结构已经存在。数据库并不创建、强制或以任何方式维护这个结构——所有这些工作都由数据库引擎完成。数据库引擎是数据库栈的主力军。这里是处理能力的来源,这就是我们需要安装的地方,也是魔法酱料被应用的地方。
在某些情况下,我们会大量讨论数据库引擎。在一些情况下,我们直接使用它们,比如SQLite或Berkeley DB,我们只需安装库(数据库引擎),然后使用它访问一个文件,哇,系统就能工作了,可以用作数据库。或者在其他情况下,比如使用MongoDB或MariaDB产品时,我们常常会讨论在背后选择的数据库引擎(WiredTiger、InnoDB、MyISAM等),它们是影响数据库特性和性能的关键因素。
数据库引擎在许多情况下得不到应有的关注,大多数人完全忽视了这一数据库服务栈中至关重要的一层,因为它很难理解,而且通常是隐藏在背后的。眼不见,心不烦,这里完全适用。
在某些情况下,比如我之前提到的 BDB 和 SQLite,我们作为系统管理员,需要负责将这些库安装到服务器上,以便软件可以访问它们。当然,这些库通常仅作为依赖列出,并由我们服务器上的包管理系统自动安装和维护,这些包管理系统来自我们的 Linux 发行版,使得这一过程变得简单,甚至对我们来说可能是透明的。正因为如此,系统管理员往往几乎对他们所维护的系统上部署或使用的数据库引擎一无所知。
这可能看起来显而易见,但值得注意的是,数据库引擎是代码库(即驱动程序),而不是运行的程序或服务。因此,在系统上检测特定的数据库引擎可能会相当困难。当然,如果通过 APT 或 DNF 安装了 SQLite,我们可以查询系统并轻松找到它。它是一个存储在磁盘上的库,拥有一个目录,并且在包配置日志中有所记录。我们无法在进程列表中看到它的运行,也找不到它在服务目录中,但我们总能以某种方式找到它。
但完全有可能,数据库引擎库的代码会被包含到并编译到某个软件项目中,使其几乎不可能被检测到,因为它只是某个应用程序内部磁盘上的二进制数据。当然,块级工具可以扫描磁盘上的每一部分数据,查找磁盘上的模式,但这属于极端级别,更适用于取证或执法,而在系统管理中并不太有用。从实际角度来看,一个编译进软件中的数据库引擎对使用该系统的任何人来说都是完全不可见的。
当我们讨论某个数据库的性能或特性时,几乎总是这些特性或性能特征来自正在使用的数据库引擎。在大多数情况下,数据库引擎还会实现查询语言或应用程序编程接口(API),用于查询磁盘上的数据。
对于那些跟随学习的人,你可能已经注意到,由于数据库引擎本身并不运行,因此你无法远程访问它。为了与数据库引擎进行交互,你必须在程序中使用驱动程序与数据库进行交互。
数据库管理系统
数据库技术栈中最显眼的组件,也是唯一完全可选的部分,是数据库管理系统,通常缩写为 DBMS。对于大多数人来说,甚至是那些具有丰富数据库经验的技术人员,唯一了解的数据库系统部分就是数据库管理系统。
在我们深入了解数据库管理系统究竟是什么之前,我们应该先举一些实际的 DBMS 例子:MySQL、MariaDB、PostgreSQL、Oracle DB、Microsoft SQL Server、IBM DB2、MongoDB、Redis、Firebase,以及更多其他的。这些名字对你们中的大多数人来说,比数据库引擎的名字更为熟悉。
DBMS 本身做的事情其实非常有限。DBMS 是一个程序,它使用一个或多个数据库引擎与磁盘上的物理数据库进行交互,然后提供对该数据库的访问控制。DBMS 可能有一个始终与之关联的单一数据库引擎,或者像 MySQL 一样,提供对一系列数据库引擎的访问,并为它们提供一个通用接口,使开发人员能够方便地使用它们。熟悉 MySQL 的人会知道,在 MySQL 中创建一个新数据库时,你必须告诉它你希望使用哪种引擎。确实,如果你不选择,它会有一个默认选项,但在这种情况下,不选择实际上也是一种选择。
在使用数据库引擎时,你必须指定你正在操作的文件或文件集。因此,任何与数据库引擎的交互都仅限于单一的数据库,不管那个文件中存储的是哪个数据库。DBMS 通常不是这样工作的。标准的 DBMS 会连接到多个数据库,这些数据库可能连接到多个实例的数据库引擎,这些引擎可能是相同的库被多次实例化,或者可能是不同的引擎用于不同的数据库,所有这些都可以同时访问。因此,我们所设想的数据库大部分来自 DBMS。
正是 DBMS 提供了(当然是可选的)通过网络或甚至通过互联网连接数据库的方式。任何网络功能都来自 DBMS。此外,DBMS运行,通常作为服务,在你的计算机上运行。这就是你看到内存消耗、CPU 使用情况以及其他数据库使用详情的地方。DBMS 通常提供一些引擎本身无法提供的扩展功能,例如内存缓存。
显然,在纯数据库引擎的场景中,数据库中数据的访问控制完全来自于文件系统的权限。这就像用 Microsoft Word 打开一个 Word 文件一样。如果你对文件有读写权限,并且能够运行读取文件的应用程序,那么你就可以读取文件并将更改写回文件。对于像 SQLite 这样的数据库引擎,也可以尝试同样的方式。要允许用户使用数据库,你只需给他们相应的文件系统权限即可。这非常简单,但也非常有限。
使用 DBMS 我们有更多的选择。大多数 DBMS 添加了网络功能,通过这些功能我们可以使用数据库自身的工具在粒度级别上控制访问权限,同时我们还可以使用操作系统和网络工具进一步控制访问。这变得更加复杂,但正是从这种复杂性中,我们获得了强大和灵活性。DBMS 通常会提供用户级别的控制和机器级别的控制,并且通常在其管理的数据库集合中提供非常精细的控制,例如行、表或文档级别的控制,具体取决于使用的数据库引擎类型。
数据库管理系统(DBMS)为数据库生态系统增加了强大的功能和灵活性,在大多数情况下也提高了易用性。在生产环境中,完全可以直接使用数据库引擎,很多人也确实这样做。但总体来说,DBMS 主导着企业的数据存储。当人们使用数据库服务器这一术语时,按照定义,他们指的是包含 DBMS 的主机。正是 DBMS 的网络能力使得数据库能够存储在专用服务器(或服务器集群)上并从中提供服务,而不需要数据库始终与使用它的应用程序本地化。这种灵活性在应用程序增长并需要更多资源时非常重要。对于小型应用程序,在资源充足的情况下,可以将整个应用程序及其数据库托管在单个服务器上,通常直接使用数据库引擎能获得最佳性能。但一旦超出这种规模,DBMS 则是支持数据库变得更大的关键。
数据库引擎本身并不严格是一个单连接受限的系统,但它实际上是这样。虽然多个用户可以同时连接到文件系统中的同一个文件,但这会带来明显的问题。如果两个人试图在差不多相同的时间进行修改,是否会互相覆盖?如何通知其他人正在进行的更改?等等。这些问题与在 SAN 中连接多个服务器到同一文件系统时遇到的问题类似。它通过数据库文件内部使用相同的集群文件系统机制来解决这些问题。(看吧,我告诉过你,数据库就像文件系统!)
文件级锁定和访问控制可以应对轻量级使用,最多支持大约五个用户,之后会开始出现明显的性能问题。对于重度使用,即便是两个连接也会变得有问题。微软 Access 以鼓励使用 JetDB 数据库引擎(通常称为 Access 数据库)而著称,且其文件锁定性能极差,导致系统无法承载超过少量用户的使用。相同的系统可以切换到使用MS SQL Server DBMS,并且能够处理数千个用户,毫无问题。
因此,对于任何真正需要多重连接的情况(这可能由单个用户或多个运行中的服务实例引起,它们需要从数据库中拉取数据),都需要使用 DBMS。DBMS 提供了更多的缓存、锁定和权限控制机制。
识别共享数据库引擎与 DBMS 的区别
如果你是数据库新手,可能不了解常见的识别方法来判断使用的是哪种方式。有些情况非常简单,比如如果你必须配置数据库的网络连接详细信息,包括主机名和端口,那么你就知道必须涉及 DBMS。但并非所有情况都那么明显。
很多应用程序处理自己的连接细节,而你可能很难了解它们在背后是如何工作的。所以,除了寻找开放端口或类似的东西外,你可能会一无所知。
然而,一个常见的机制是要求共享映射驱动器访问文件或文件。这在除了极少数情况下的数据库管理系统(DBMS)中是不需要的,如果确实需要,那么你就遇到了严重的性能问题。将数据库文件直接共享给用户或应用程序进行访问是直接使用数据库引擎的标志。这种情况常见于许多遗留或构建不当的应用程序,因此你可能已经遇到过,或者将来会遇到,并且了解数据库引擎的工作方式有助于解释这些部署中访问、锁定、性能或甚至是数据损坏的问题。
作为系统管理员,甚至可能作为数据库管理员,假设是除了安装数据库引擎库之外,我们与运行中的数据库的互动将全部通过数据库管理系统(DBMS)进行。在这里,我们需要管理和监控服务、资源利用、安 全、补丁、访问控制等。
现在我们已经了解了数据库是什么、它们是如何工作的,以及它们的组成部分,这样我们就可以批判性地思考安全性和性能的影响。缺乏对数据库的理解,会使得解决更复杂的问题,如性能调优或有效的备份措施变得非常困难。在下一节中,我们将非常高层次地讨论数据库的类型,给我们一些关于系统管理员如何处理这些不同数据存储形式的见解。
比较关系型和 NoSQL 数据库
数据库分为两大类:关系型 和 NoSQL。这些分类非常糟糕,但不幸的是,它们就是世界上看待数据库的方式。这些术语非常糟糕,原因有几个。首先,NoSQL 是指 非关系型。这意味着数据库要么是关系型,要么是非关系型。这本身就是一个很糟糕的分类法。更糟糕的是,SQL 是与关系型数据库常关联的 结构化查询语言;它是为查询关系型数据库而编写的语言。因此,NoSQL 这个术语指的是非关系型数据库,但这就像试图通过称人们为非英语使用者来指代那些不是来自英格兰的人。两者有时会重叠,但通常不会。
SQL 不是关系的内在语言;它只是用于查询关系的常见约定。你可以创建一个不能使用 SQL 查询的关系型数据库,同样,你也可以创建一个可以使用 SQL 的非关系型数据库!不仅可以,事实上,这非常常见。所以,为了明确一点,你可以在 NoSQL 数据库中使用 SQL,而且人们经常这么做!这是什么疯狂的事情?
在 NoSQL 世界中,通常每个数据库都会使用一种或多种查询语言。这些查询语言通常是特定于每个数据库的,但没有某种查询语言,就几乎不可能将数据导入或导出数据库。正是这些语言构成了数据库与应用程序之间通信的基础。例如,MongoDB 实现了他们自己的 MongoDB 查询语言。
所以我们必须接受这些术语从一开始就很荒谬,并意识到我们所讨论的,一方面是关系型数据库,另一方面是所有其他非关系型数据库,这是一种包含许多不同数据库技术的集合。这种奇怪的情况之所以存在,仅仅是因为大多数流行且知名的数据库都是关系型的,且很多年里人们一直认为只有关系型数据库才是足够好的,适合生产使用。事实证明这一观点完全不正确,但它在行业中仍然产生着影响。
因此,NoSQL 本身就让人感到望而生畏,因为它包含了这么多的内容和数据结构类型。话虽如此,我们并不需要了解所有的内容。我们真正需要理解的只是,NoSQL 数据库可以使用任何类型的磁盘上的数据结构(当然,除了关系型数据库),并且可能会使用 SQL 或其他查询语言,也可能不使用。这就留下了更多的问题而不是答案。作为系统管理员,我们通常只是被要求学习应用程序所需要的数据库。这可能是一些非常常见的数据库,关于它有大量的知识,或者它可能是一些非常冷门的数据库。
第一代数据库按今天的标准来看,实际上是 NoSQL 的。这就让人觉得很奇怪,为什么早期的数据库现在被认为与后来的数据库不同。早期的数据库功能非常有限。在 1970 年代,关系型理论出现,随之而来的是第一批真正的现代数据库。关系型数据库诞生了,并且证明它们既安全又高效,以至于其他类型的数据库几乎在短时间内都被淘汰了。关系型数据库成为了王者,且永远存在。
几十年来,关系型数据库几乎代表了所有商业级数据库,其他类型的数据库几乎只存在于历史注脚中。当它们应用于实际系统时,通常是由应用程序独立实现的,而不是由大型数据库供应商提供。因此,即使它们被使用,它们也相对不为人知。一个嵌入在应用程序中的数据库引擎对系统管理员来说基本是不可见的,因此即使这些数据库引擎被定期部署,只有原始开发者才会知道。事实上,我的职业生涯开始于 20 世纪 80 年代末期,当时我为一个 NoSQL 数据库引擎编写了代码,并为其开发了一个图形化数据检索系统。我亲眼见证了开发者使用 NoSQL 数据库,而信息技术部门对其毫无了解的现象,这正是在关系型数据库占主导地位的时期。
关系型数据库的优势来自于其存储数据的高效性,这在数据库早期几十年尤其重要,那时找到足够大的存储系统来容纳数据一直是一个挑战;同时,它还能很好地处理诸如事务和数据完整性等问题。这使得关系型数据库非常适合任何处理金融或其他关键事务的系统,这些系统需要高水平的保证,确保事务要么完全完成,要么根本不发生。早期的数据库自然非常注重金融事务,因为这些数据存储操作极为关键,足以证明使用昂贵计算机来确保数据准确无误的必要性。当数据库的实现成本达到几百万美元时,可以轻松理解为什么银行会使用它,但要为其运行一个博客就显得非常难以合理化了。
关系型数据库得名于它们用于指定数据之间实际关系的方式。例如,如果你创建了一个用户数据,你可能会创建一个电话号码数据,并在它们之间建立关系。接着你可能会创建更多数据,比如地址。这个地址也会与用户有关联。关系型数据库背后的基本理念是数据库引擎会主动控制这些关系。比如,如果删除用户,它可能会自动删除电话和地址;它可能会确保一个电话号码只能属于一个人,或者可以显示多个人住在同一个地址。它甚至可以阻止你创建不符合某种格式的电话号码,或者阻止你填写不完整的字段。
关系型数据库听起来可能简单且表面化,但当它们被精心设计并加以应用时,能够为数据完整性提供强大的保护。它们大大减轻了软件开发人员的负担,并且将数据完整性置于一个能确保保护数据的约束条件下,即使使用这些数据的应用程序被绕过了。关系型数据库是一种强大的机制,但这种强大是以复杂性为代价的。
NoSQL 数据库由于不受关系型数据库规则的约束,也不必使用 SQL 方言,因此可以探索各种数据存储和完整性方法。一些方法以一种享乐主义的随意态度处理数据,这对传统的数据库管理员来说简直是震惊。数据可以随意存储在任何地方,几乎没有任何控制。虽然可能存在某种结构,但这种结构更像是一种建议,而不是强制要求。从关系型理论的严格规则出发,例如,文档数据库就像是“荒野西部”:数据随意乱丢。一个文档的结构可能根本与下一个文档不匹配。这简直是数据逻辑的混乱。
NoSQL 的真正优势来自于这种灵活性。我们不再需要在一个强预定义的、严格约束的模式下工作,而是可以根据特定需求自由使用数据,选择最合适的方式。我们可以用博客作为一个极好的例子,它与财务数据在关注点上几乎是完全相反的。
对于财务数据,我们通常非常关注准确性、一致性和事务完整性。而对于博客,我们更多关注的是速度,其他的则不太重要。如果我们有一个受欢迎的网站,并希望让我们的博客在全球范围内快速访问,我们很可能会希望通过全球各地的节点来提供该内容,从而让大多数人能够从相对本地的副本中获取博客内容,而不是使用一个可能托管在其他大陆上的远程集中式博客。
一个通过复制到多个地区来提供内容的数据库,并且将速度作为首要优先级,可能会错过最新的更新,或在数据更新过程中短暂地出现顺序错乱,而这正是关系型数据库设计时会避免的情况。能够在时间允许的情况下复制数据,同时仍然提供本地可用的数据,可以带来显著的性能提升。对于许多工作负载而言,这种性能权衡是理想的选择。
随着越来越多的系统被计算机化,越来越多的工作负载使用数据库,这意味着数据库的使用方式正在变得更加广泛。如今,数据库的实现往往免费或成本极低,这意味着几乎所有事情都将在某个阶段使用数据库。如今,数据库不再是仅仅为高需求工作负载所专用的工具。
仅提供非常简单的查找、会话缓存等功能的数据库并不常见。或者是替代文本文件用于日志记录的数据库,能够更快速地访问日志数据,并且更重要的是,可以对这些日志进行强大的搜索,现在几乎随处可见。NoSQL 正在让数据库世界变得更加强大和灵活。
作为系统管理员,我们很少,甚至几乎不可能,有机会选择在任务中使用哪种数据库类型。即使了解哪些数据库类型在不同情况下最为有用,这通常也是不必要的,尽管这可能非常有趣。更重要的是,我们需要理解,数据库现在呈现出丰富的多样性,尽管它们之间有许多共同的系统管理特点,但不再有诸如 SQL 是通用语言的内建假设,而我们的应用程序将决定我们需要学习和支持哪些数据库类型和产品。
理解关系型和 NoSQL 数据库代表着我们两大阵营的数据库产品后,我们将简要概述目前在你的 Linux 生态系统中最有可能出现的实际产品。
在 Linux 上发现常见的数据库
大多数操作系统都有一两个非常流行的关键数据库产品与之相关。例如,Windows 上的数据库产品是 Microsoft SQL Server。Linux 在这方面则完全不同。Linux 不仅没有一个特定的数据库产品与操作系统紧密地在意识形态上相关,而且通常有大量的数据库选项已经包含在几乎每个 Linux 发行版中。这使得成为一名 Linux 系统管理员变得更加具有挑战性,因为人们期望你不仅要了解各种不同的数据库产品,还要能够管理它们。与此相对的 Windows 系统管理员通常只需要了解一个非常固定的产品,就可以声称自己具备了该领域的基础知识。尽管许多数据库可以运行在 Windows 上,但除了 MS SQL Server 之外的其他任何数据库都被视为特例和专业知识,通常不会期望你有任何相关经验或知识。
在 Linux 上,大多数情况下不会期望你对每个可能的数据库选项都具备非常深入的知识,但期望你了解其中的许多并能够准备好管理几乎任何数据库系统是相当普遍的。单个服务器上部署多个数据库管理系统是很常见的,因为它们是内建的,并且相比 MS SQL Server 更加针对特定目的,因此一个数据库管理系统负责某一特定任务,另一个负责处理数据存储需求截然不同的任务是常见的,并且非常有效。
我们将保持数据库类别的自然划分,考察常见的关系型数据库产品以及非关系型或 NoSQL 数据库产品。
Linux 上常见的关系型数据库
可能在 Linux 上最著名的四个数据库,甚至可能是全球最著名的数据库,是关系型数据库。这四个大牌是MySQL、MariaDB、PostgreSQL 和 SQLite。排名第五和第六的数据库(不分先后)是 Firebird 和 MS SQL Server。没错,你没看错,那个 Windows 生态系统中的关键数据库产品也可以在 Linux 上使用。
MySQL
与任何其他数据库相比,MySQL 与 Linux 系统几乎是同义词。MySQL 可能在 Linux 上最为人知,但它也正式提供 Windows 版本,并在 Windows 上有一定的使用量。MySQL 功能强大、速度极快且极其知名。几乎每个 Linux 系统管理员都曾经使用过它。MySQL 是一个完整的数据库管理系统,包含多个数据库引擎。
MySQL 首次真正流行是作为早期动态网站的数据库。它免费、速度快,且缺乏更高级的金融交易所需的功能对于内容管理引擎(如博客和类似的动态生成内容的站点)来说并不重要。MySQL 被称为首选产品,用于网站需求,但由于这种刻板印象,它常常被其他需求排除在外。
今天的 MySQL 已经成熟、先进,具备几乎所有你可能需要的功能,适用于任何类型的工作负载。如果你只打算学习一个数据库管理系统,MySQL 肯定是最好的选择(或者是 MariaDB,我稍后会解释)。MySQL 拥有最广泛的用户基础,几乎所有具备 Linux 经验的系统管理员,以及很多没有 Linux 经验的管理员,都能自信地管理它。针对它也有大量标准工具,比如 phpMyAdmin,当你想避免或超越命令行时,它能让你更轻松地使用 MySQL。几乎所有为 Linux 开发的主要应用项目都在某种程度上使用 MySQL,尽管它可能不是最常部署的数据库,但与 MariaDB 结合使用时,它是最常被有意部署的数据库,不仅在 Linux 上,在所有操作系统上都是如此。
MariaDB
真的很难谈论 MySQL 而不提到 MariaDB。MySQL 的社区和方向在多年前分裂,许多原 MySQL 团队成员离开了这个项目,将开源基础带走,创建了 MariaDB,旨在成为他们认为的 MySQL 的精神继任者。对许多人来说,MariaDB 才是真正的 MySQL,因为它在理念上与原始产品一致,完全基于相同的代码库构建,而且由原始团队开发。许多 Linux 发行版,可能大多数,放弃了 MySQL,改用 MariaDB。甚至现在,大多数声称使用 MySQL 的人实际上是在使用 MariaDB——往往连他们自己都不知道。
即插即用替代品
MariaDB 的真正亮点是它是 MySQL 的完整 即插即用替代品。这意味着它被设计成能够完全透明地在任何使用 MySQL 的地方使用。它使用完全相同的协议、接口、工具、名称、端口、约定等。理论上,所有的东西都是一样的。
MariaDB 做得如此出色,以至于许多人在说自己使用 MySQL 时,实际上他们使用的是 MariaDB。有些人说这有点像是一种代码;还有人说是因为管理层期望这样做,而解释为什么使用 MariaDB 而非 MySQL 是不值得的;还有一些人根本不知道自己安装的不是 MySQL。管理 MariaDB 最常用的工具是 mysql 命令行工具,这也是许多人接触系统时最接近实际系统的工具。一个数据库设计师或开发人员只需要知道该系统与 MySQL 兼容。没有真正的迹象让他们怀疑这到底是某个产品或另一个产品。它们看起来和运行起来的方式完全一样。
现在人们常常提到著名的 LAMP 堆栈,曾经是 Linux + Apache + MySQL + PHP,现在变成了 Linux + Apache + MariaDB + PHP。看起来 MariaDB 确实已经完全取代了 MySQL 在市场中的位置。但很难准确评估这一点,因为在 MariaDB 市场中,有一个不确定的大比例部分报告自己使用 MySQL,要么是因为他们没有意识到它们是不同的,要么是因为他们随意报告不准确,要么是他们根本不知道自己在使用什么。
即插即用的兼容性带来了额外的好处,即学习 MySQL 就意味着学习 MariaDB,反之亦然。你无需学习一个或另一个,因为你在一个系统上做的所有事情,在另一个系统上也完全一样。
PostgreSQL
无论看起来多么不相似,post gress 的发音使得 PostgreSQL 可以说是今天在 Linux 系统上最成熟和先进的数据库。PostgreSQL(最初写作 POSTGRES)始于 1980 年代,作为成功的 Ingress 数据库产品的继任者(Postgres 意味着 POST inGRESs)。
今天,PostgreSQL 常被认为是 Linux 系统上最快速、最稳定、功能最丰富的数据库产品,甚至可能是所有数据库中最优秀的。像这样的数据库区别通常更多的是个人意见,因为性能测量很少可以直接比较,并且功能差异往往比直接的查询性能更为重要,但 PostgreSQL 的声誉无疑是无可匹敌的卓越,代价是相比于其竞争对手,它更复杂且不太为人所知,而后者通常被认为是更简单的系统。
近年来,PostgreSQL 在流行度上经历了重大复兴。今天,你会发现越来越多的部署软件支持并甚至推荐它作为首选数据库,这是自十多年前 MySQL 的全盛时期以来,数据库界的一大变化。
作为一名 Linux 系统管理员,PostgreSQL 数据库生态系统是一个稳固的第二选择,甚至可能是首选,与 MySQL(以及与 MySQL 相同的 MariaDB)一起学习,因为大多数 Linux 系统管理员在某个时刻都需要管理 PostgreSQL。
SQLite
比大多数系统管理员意识到的更常用的是 sqlite 客户端工具,你可以用它来读取和修改 SQLite 数据库文件,但这与数据库服务器完全不同。
SQLite 的强大之处在于它的简单与微妙。除了安装其访问库外,系统管理员通常不需要了解系统中是否存在 SQLite。它不需要调优或配置。它就存在在那里。由于软件仓库和自动依赖管理的魔力,SQLite 通常会作为其他软件的依赖项被部署,我们甚至可能没有意识到它已被安装或可用。它自动出现并完成它的工作。甚至它可能被内建在使用它的应用程序中,且可能以我们无法在系统中搜索到的形式存在!
由于 SQLite 的存在和部署方式大多数时候是这样,普通用户对 SQLite 的部署情况一无所知。正常的安装并不会隐藏驱动程序:系统管理员如果想要发现它、修补它或仅仅是查找它在哪里,通常都不会遇到什么困难。但是除非你特别在寻找它,典型的服务器上可能会有数百甚至上千个类似的软件包,我们通常无法花时间去了解每个系统上存在哪些库,更不用说知道哪些软件依赖于哪些包了。这实在是不切实际的。
Firebird
相比 MySQL、PostgreSQL、SQLite 和 MariaDB,Firebird 的知名度要低得多。Firebird 是一个完整且成熟的数据库管理系统,基于 Interbase 6,但在 2000 年与该项目分离。尽管在 Linux 世界中被视为相对次要的软件,但 Firebird 依然是一个功能强大且成熟的数据库管理系统,其主要的特点是所需的系统资源非常少。
Firebird 在对话中出现的概率远高于实际部署到你的服务器上。它实在是不太常见。Linux 上有很多数据库选项,这使得即便像 Firebird 这样成熟且严肃的数据库选项也很难获得关注。
Microsoft SQL Server
这份榜单上的参与者总是让那些不了解其可用性的人感到震惊。长期以来,微软 SQL Server 被认为是市场上最好的数据库产品之一,但始终仅限于微软 Windows 操作系统。但近年来,微软试图在数据库许可空间(与操作系统许可相比更具吸引力)获得更多市场份额,开始将 MS SQL Server 发布到 Linux 以及 Windows 上。如今,MS SQL Server 对 Linux 系统管理员来说已经是一个完全合理且可行的选择。
像这份榜单上大多数传统选项一样,MS SQL Server 是一个完整的数据库管理系统,其内部有多个数据库引擎。它是一个功能强大的产品,具备许多高级功能和特性。
MS SQL Server 在 Linux 上仍然不常见,并且可能会在相当长的时间内保持这种状态。但它已经比例如 Firebird 要普遍得多。数据库部门通常非常专注于 Linux,或者至少是 UNIX 系统,因此如果应用程序需要 MS SQL Server,而团队通常不使用 Windows Server,则必须管理一个完全不同的平台,这是一个问题。
Linux 上常见的 NoSQL 数据库产品
如果关系数据库产品的列表看起来很长,那与我们可以讨论的 NoSQL 或非关系数据库产品的潜在列表相比根本不算什么。与关系数据库列表不同,其中所有产品都以类似的方式工作,并且适合由类似的软件任务使用,NoSQL 列表变化多端。对于一个任务来说是一个了不起的产品,对于另一个任务来说可能完全没用。
我们不可能详尽介绍这些数据库产品的所有细节,甚至只是涵盖这个类别的各种数据库类型。仅仅是 NoSQL 数据库的例子就可以轻松填满一本这样大小的书。我们将尽力快速概述并提供足够的亮点,让您了解存在哪些产品、为何重视以及如何开始自己的产品调研。
MongoDB
无疑,在 NoSQL 领域的头号领导者是 MongoDB。MongoDB 被称为文档数据库管理系统。像许多我们提到的数据库管理系统一样,MongoDB 可以使用多个数据库引擎,但如今几乎所有使用它的人都使用其WiredTiger数据库引擎。文档数据库是最接近关系数据库的 NoSQL 数据库类型之一,许多情况下两者都能胜任。文档数据库几乎就像我们把关系数据库和传统文件系统放在一起,它们在中间相遇。
文档数据库
文档数据库存储结构化文档。尽管每个文档数据库可以使用自己的格式和方法,但这一概念是通用的。一个好的例子是 XML。XML 可以是文档数据库中单个文档的格式。数据库可能会规定 XML 的结构,或者它可能是自由格式的。数据库可能包含数百万个这样的 XML 文档。
由于数据库知道其包含文档的预期用途,因此它能够使用文档中的共同字段生成索引和其他工件,使数据库能够执行更多操作,远超过你将这些 XML 文档简单保存到硬盘上所能做到的。
但只需要像这样的一个简单例子,你就会开始明显地意识到文件系统不仅仅是一个数据库,而是一个专门的文档数据库!
文档数据库通常易于使用,非常直观,使开发人员和系统管理员的工作变得轻松。它们已被证明是关系型数据库在许多常见工作负载中非常理想且有效的替代品。
MongoDB 在各种不同的场景中得到了广泛部署和使用。像我们最初提到的大多数关系型数据库示例一样,MongoDB 通常与第三方软件包一起使用,也会在 Linux 发行版供应商的软件包中出现,同时它也在内部软件团队进行定制开发时仍然很受欢迎。如果你打算在 Linux 上开始尝试 NoSQL 数据库,我通常会建议你从 MongoDB 开始,因为即使 MongoDB 最终没有成为你在生产环境中支持的数据库管理系统,它几乎肯定会提供最有价值的经验。
MongoDB 是探索许多替代数据库方法的绝佳途径,其中许多方法在 关系型之后 的世界中已经成为某种标准。
虽然文档数据库已被证明是关系型数据库在常见软件使用中的最常见替代方案,但并不是很多文档数据库都崭露头角。MongoDB 是唯一一个真正的大型、知名的例子。其他例子包括 Apache CouchDB 和 OrientDB 作为数据库管理系统,以及 NeDB,它是一个数据库引擎,数据结构几乎与 MongoDB 完全相同。
Redis
存储数据的另一种完全不同的方法是 Redis,它是一种所谓的键值存储数据库管理系统。这种类型的数据库作为辅助存储而非主要存储更加流行。键值存储的思想是,使用该数据库的应用程序提供一个键,数据库返回与该键关联的数据。与我们已经遇到的数据库类型相比,它是一种极其简单的机制,但却是非常有用的。
键值存储(有时称为字典查找)常用于高速在线缓存,是管理如会话数据等数据的一种极好方式。虽然应用程序仅使用键值数据库作为唯一数据存储机制的情况很少,但也不是不可能。几乎总是作为多部分数据库策略中的一部分。
Redis 为巨型在线应用提供了许多所需的高级功能,例如跨节点集群的能力和方便的访问方法,这使得它在大型应用中非常受欢迎。它的性能和简便性使其在网页托管领域广受青睐。
其他的键值存储仍然很受欢迎,例如memcached,它在 Linux 上用于网页托管非常流行,LevelDB,甚至是MS SQL Server下的一个键值数据库引擎。
Cassandra
一个与关系型数据库和文档数据库在通用应用领域的主要竞争对手是宽列数据库,最著名的就是 Cassandra。宽列数据库比我们在这里能涵盖的要更值得关注和描述,但无需多言,它们主要处理与关系型数据库相同的工作负载,并且在大多数情况下关注于更大的灵活性和可扩展性。
与 Cassandra 一起,Apache HBase和ScyllaDB是常见的 Linux 下的主要宽列数据库。你不会像看到键值和文档数据库那样频繁遇到这种类型的数据库,但它有一定的市场份额,且易于获取和实验,如果你希望扩展自己对数据库特性或类型的了解,它是个不错的选择。
更进一步:NoSQL 并不局限于定义,专用数据库和数据库类型不断涌现。我还建议你调查一下Amazon OpenSearch,这是一个搜索数据库,以及InfluxDB和Prometheus,它们是时间序列数据库。这三种数据库,以及这两类数据库,通常用于以高速和大容量存储日志或类似日志的数据。
不要害怕自己去搜索新的或有趣的数据库方法和产品。这个领域发展迅速,书本的内容很快就会过时。Linux 在数据库平台方面在市场份额、稳定性、性能和多样性等各个方面都是领先的。你应该对主要的产品有所了解,知道自己发行版中包含哪些内容,以及你的应用程序可能使用哪些数据库。同时要对你需要投入的工作有一个大致的了解。记住,一些组织会继续使用专职的数据库管理员来处理与系统管理团队分离的数据库任务,但几乎所有公司都会将这些角色合并,导致你需要理解多个数据库平台的情况通常会落在你身上。
我们现在对在 Linux 系统管理的实际环境中可能遇到的产品有了很好的理解。所有这些数据库概念都很有趣,并且很激动人心,能够接触到许多不同的产品总是令人兴奋,但真正重要的是我们如何保护这些系统,这也是我们在下一部分将要讨论的内容。
理解数据库复制和数据保护概念
从 Linux 系统管理员的角度来看,数据库保护将是最重要的事情,这包括,正如它对系统整体所做的那样,灾难避免和灾难恢复。因为数据库至关重要,而且非常普遍,此外它们的需求与我们通常在系统中遇到的需求截然不同,所以我们在这里单独讨论,以便能够处理与数据保护相关的数据库世界几乎独特的需求。
因为数据库存储的是结构化数据,所以它们面临着保护那些高频使用的存储系统的所有挑战,实际上它们就是这样的存储系统。由于数据库高度有状态,我们必须非常小心,以免在进行数据保护时破坏状态。
这些在最简单的术语中是什么意思?基本上,数据库就是用来存储数据的,为了有效地进行数据存储,它们需要同时保持代表其数据的文件在磁盘上打开,并且通常在任何给定的时间都要在内存中保持大量的数据。这给我们带来了在数据保护方面的几个挑战。
打开中的文件始终是备份的难题。没有好的方法来备份当前被应用程序打开的文件,因为我们无法知道文件写入时的状态。也许文件目前是完全正常的,或者可能它已经被部分修改,数据是乱码,直到更多的当前内存数据或可能尚未计算的数据被添加到文件中,或者文件的格式没有损坏,但文件中的数据已经不再准确。从使用该文件的应用程序外部,我们无法知道一个打开文件的实际状态,除了它无法被信任以外。
因此,大多数基于文件的备份将会忽略该文件,因为它们无法锁定文件进行备份。对于大多数文件来说,这并不是问题,因为文件只偶尔被锁定,如果你定期进行备份,通常会最终获得某个文件的有效备份。这可能不是确定性安全的,但它是统计学上安全的。如果你需要确定性,你可以使用日志查看关键文件是否已经安全备份。
基于块的备份,也就是从块设备层而不是文件层进行备份,并且不关注单个文件或文件系统的机制,能够轻松地备份打开的文件,但它们无法判断文件是否处于安全或准确的状态。所以,在第一种情况下,我们假设打开的文件会被简单跳过。在第二种情况下,我们假设会备份它,但该备份的准确性只能在恢复时确定。当然,这两种选择都不是理想的。两者都比什么都没有要好。
传统的将也许我们有一个好的备份或我们几乎总是有一个好的备份转变为完全知道备份是好的方法是使用一个代理,该代理通知应用程序完成事务,将所有数据写入磁盘并在备份操作期间关闭文件。有些应用程序具有执行此操作的机制,API 调用会通知它们准备进行备份,而对于其他应用程序,你需要通过暴力方式,在备份之前完全关闭应用程序,并在备份完成后重新启动它。这里的问题是,只有极少数应用程序支持这种通信方式,而任何备份软件代理必须分别支持每个独特的软件才能做到这一点。所以,这需要双方的合作,考虑到市场上应用程序和备份工具的数量,这种合作并不常见。因此,这种方法是不切实际的。
许多应用程序采取的做法是通过执行内部数据转储过程来获取它们自己的备份,并以安全的方式将数据保存到另一个存储位置。这些文件是应用程序中所有数据的完整副本,并且保持关闭状态,仅供备份软件读取和使用,而不是使用实时数据。这为绕过因打开文件导致的数据损坏问题提供了一种通用机制。它易于应用程序开发人员实现,并且与所有备份软件通用。
这种方法完全有效,但有一个重大警告:我们必须关闭应用程序才能使其工作。这意味着我们必须有一种方法,能够在正确的时间关闭应用程序,并在正确的时间重新启动它。这个部分通常是可行的,并且不需要太多工作,尽管除了少数常见的应用程序外,通常都是手动操作。但真正的问题是让组织同意定期关闭应用程序,以便进行备份操作。不同于系统重启,我们通常只希望每周或每月进行一次重启,我们通常至少希望每天进行备份,有时是每小时一次,甚至几乎是持续备份。这并不是我们总能做到的事情。
除了预定备份频率之外,通常我们还希望能够随时进行临时备份。如果临时备份会导致应用程序停机,这通常是不可接受的。因此,需要其他方法来处理。
所有这些因素共同作用,使得数据库备份成为一个严重的问题。数据库几乎总是你 IT 基础设施中最关键的幕后工作负载组件,最无法承受任何长时间或意外停机的影响,通常也是唯一需要无限期保持文件打开的组件,并且备份对它们来说至关重要。
这个挑战远远超出了备份问题。如果我们处理的是无状态的应用程序,而不是数据库,例如典型的网站,我们有许多复制选项,可以简单到仅仅是将应用程序目录在服务器之间复制。负载均衡选项可以简单到将部分流量引导到一个应用服务器或另一个应用服务器。在大多数情况下,非数据库应用程序的复制、备份甚至负载均衡都很简单。
对于数据库,我们没有简单地在系统之间复制文件的选项。为了确保数据一致性和更新,运行在每个主机上的数据库管理系统需要相互协调,确保诸如锁定、缓存和磁盘刷新等概念能够一致地执行,并在集群中进行通信。如果复制功能对你所使用的数据库管理系统来说是可选的,它通常相当复杂,并且有很多限制。没有简单的方法能够在不引入显著性能挑战的情况下实现数据库的复制或集群。
因此,既要保护数据库免受故障影响,又要确保在出现故障时能够轻松可靠地恢复,这是一个挑战。尽管实现这一目标的技术在最高层次上可能有些共性,但它每次都需要在特定工具层面上进行配置和应用。所以,了解一个生态系统如何处理这些问题,并不一定能反映到另一个生态系统中。
在所有情况下,备份、复制和集群将由数据库管理系统本身或专门为该数据库设计的工具来处理。系统的功能将是该数据库独有的。例如,一些数据库管理系统仅支持非常简单的集群,可能只是通过一对镜像服务器,或者仅支持单个节点能够进行磁盘修改,而集群中的其他节点则保持部分或全部数据的缓存副本,并负责提供读取请求。另一些系统具有巨大的可扩展性,可能允许数百个独立节点,每个节点都能完全读取和写入数据!
因此,由于这种复杂性,我们必须完全单独学习每个产品。NoSQL 数据库有一种强烈的tendency,即具备复制和冗余选项。这通常源于缺乏控制和约束。此外,大多数 NoSQL 数据库是在近年来构建的,而大多数关系型数据库则已有几十年历史,因此它们设计时的考虑因素截然不同。今天你所了解的大多数关系型数据库首先必须适应网络,然后是互联网,这一过程持续了许多年。几乎所有你将遇到的 NoSQL 数据库都是在互联网成为日常生活的一部分之后几十年才创建的。
在许多情况下,将数据库放入集群中时,会通过锁定数据库的某些文件、记录、文档、行或其他离散部分来工作,并向其他集群成员发出锁定信号。然后,原始系统等待所有成员以确认锁定的方式进行通信。一旦被锁定,系统就无法写入新数据到系统的至少某个部分,必须在解锁后才能继续执行数据存储请求。在某些情况下,这种锁定可能非常快速,或者可能对存储产生足够大的影响,从而影响应用程序的可用性。在单服务器数据库上执行此操作可能会产生显著影响。在集群中,由于集群节点需要相互等待以完成其锁定任务并相互报告,这种影响可能会放大很多倍。如果我们还需要在等待互联网延迟和可能发生的故障时进行相同的操作,锁定操作的潜在影响规模可能会再次放大很多倍。锁定可以确保一致性,但总是以性能和复杂性为代价。我们的数据库系统越大,即使是锁定系统的一部分,其潜在影响也越大。
传统上,尤其是在关系型数据库中,我们假设通过纵向扩展来提高性能——即增加更多的 CPU、更快的 CPU、更多的内存以及更多或更快的存储。这种方式在我们需要中心化地访问数据时非常有效,直到我们能够不断将更多、更快的 CPU 压入一个单一的盒子中为止。之后,我们就会遇到性能瓶颈,卡住了。
如今,我们越来越多地看到分布式设计,即向集群添加更多的较小节点,就像我们在早期章节中讨论的那样。关系型设计并不完全无法使用这种模型,但在期望写入和读取操作与系统扩展时,它们往往难以高效运行。NoSQL 已经采用了这种数据访问需求,并以非常高效的方式进行了处理。新的数据库从头开始设计,以此为基础,通过在顶层(例如通过 SQL 语言查询)提供通用关系接口,为旧设计增加了新的性能选项。
数据库集群引入了新的潜在数据保护计划复杂性。根据数据库和数据完整性设计,备份或复制操作可能需要一些戏剧性的措施,例如在备份过程中暂时冻结整个数据库集群。或者可能需要从各个节点收集数据,每个节点都包含独特的数据,以组装完整的备份数据,这些数据在备份操作之前在任何一个位置都不存在完整。这种方法通常称为分片数据库,从逻辑上讲很有挑战性,因为可能存在一定规模的数据,没有节点能够很好地处理,而且数据恢复也可能很复杂,因为数据必须重新输入到集群中并分发到节点上。重新组装数据可能是一项艰巨的任务。其他数据库可能只是随机应变,提供它们所拥有的备份,而不与其他集群节点进行检查。这一切取决于数据库及其设置。
当处理数据库集群时,有许多考虑因素。虽然我们可以在这里讨论高层次的方法,但在现实世界中,每个数据库甚至数据库部署都是独特的。我们需要查阅有关独特设置的文档,并注意确保整个收集和存储数据过程的一致性。
我们还必须考虑直接数据库引擎的情况,这些引擎不包括数据库管理系统。在这种情况下,没有数据库管理系统来创建一致的备份文件到磁盘或处理复制。任何数据保护功能都需要由使用数据库的应用程序处理,而不是由数据库产品来完成工作。对系统管理员来说,这种情况非常困难,因为每个应用程序都可能非常独特和具有挑战性。当然,我们可以随时通过关闭应用程序甚至整个服务器来进行备份,但这不是一个理想的过程。
使用数据库引擎时,如果我们希望在不关闭系统的情况下实现任何数据保护功能,我们需要依赖相关应用程序提供这些功能。这可能提供最佳的数据保护选项(当然,也包括在数据库管理系统上运行的应用程序提供类似功能),因为应用程序本身通常会拥有对数据库的独占访问权限,并且对整个应用栈的当前使用案例有全面了解。理论上,应用层凭借其对系统状态和预期使用案例的额外了解,可以在更有意义的时间进行备份,并以更动态的方式存储备份。
例如,应用层可以实时复制部分数据,只有那些被认为至关重要的数据,复制到一个任意的数据存储位置,可能是异地。也许它将数据记录在类似日志的结构中,以便重新创建。或者它知道何时会出现写操作的停机时间,并且可以锁定数据库,并用比数据库管理系统本身更智能的方式进行复制,或者应用层可以在将数据写入数据库存储之前,跨应用节点复制事务以确保一致性。应用层凭借其更深的洞察力和灵活性,可以使数据存储层变得更好。
应用层备份有可能做出一些有趣的事情,比如基于一天中的空闲时间进行备份,并能够自动化备份和恢复。如果应用程序允许,自动化新节点的设置将是一个巨大的好处。
正如在数据库集群的情况中所说,每种情况可能是独特的,并且需要了解应用程序,了解它为数据完整性提供的支持,并结合我们自己的知识,确保能够实现一致且完整的数据集。一个集群化的应用程序可能会呈现与集群化数据库相同的挑战和机会。
总结
数据库几乎是我们作为系统管理员需要处理的最重要的事情。无论是我们自己运行数据库,还是仅仅管理运行数据库的操作系统,它们都将需要我们更多的关注,并且比我们做的任何事情都更容易给我们带来压力。在处理数据库时,我们的技能和专业知识将变得尤为重要,且我们的技能范围在这里将会受到最严峻的考验。
无论数据库在哪里运行或使用,我们都需要评估数据如何存储在磁盘上,如何确保一致性,以及如何将这些一致的数据移动到备份位置,无论是磁带、在线存储还是其他。这可能是我们在系统管理中做的最重要的任务,无论是在 Linux 还是其他系统上。
我们关于数据库的最佳实践真正集中在数据保护上。我们很想讨论如何选择适合我们执行的任务的正确数据库类型,但除了最少数几种情况外,这些决策通常在任何事情到达系统管理团队之前就已经做出了。
数据库备份的最佳实践是确保使用完整、一致、完全安全的、封闭的数据集作为备份源,以确保数据保护是可预测的。无论是由数据库、使用数据库的应用程序,还是手动处理,都必须有一个机制,确保在数据获取时数据不会处于传输中。
在集群场景中,同样的逻辑适用。但现在我们必须确保,在整个集群的上下文中,节点可以访问的数据是准确且完整的。
在下一章中,我们将开始深入探讨那些不那么引人注目但极其重要的领域——文档、监控和日志记录。
第三章:有效系统管理的方法
第三章的目标是退一步,从业务背景出发,将其应用于我们对 Linux 管理的视角。通过这个背景,我们将以更好的方式考虑许多流程和设计决策,并展示传统思维如何常常未能适应现实世界的业务需求。
本书的这一部分包括以下章节:
-
第七章,文档编写、监控和日志记录技术
-
第八章,通过脚本和 DevOps 自动化提升管理成熟度
-
第九章,备份与灾难恢复方法
-
第十章,用户与访问管理策略
-
第十一章,故障排除
第七章:文档、监控和日志技术
现在我们进入了系统管理工作的真正核心部分,尽管我认为大多数人会觉得这只是基础。在本章中,我们将处理那些没人能在我们的服务器上看到的系统管理部分。这些是我们工作中几乎看不见的组成部分,虽然它们至关重要,但却能将初级人员与高级人员区分开来;当事情开始出错时,这些额外的步骤能带来决定性的差异。
在本章中,我们将学习以下内容:
-
现代文档:Wiki、实时文档、代码库
-
工具和影响
-
容量规划
-
日志管理和安全
-
警报和故障排除
现代文档:Wiki、实时文档、代码库
关于文档的一点是,大家都承认它很重要,大家都在谈论它,但几乎没有人去做,或者即使做了,也没有保持更新。文档无聊,往往比看起来更难做得好,而且由于几乎没有管理层会跟进并验证它,极其容易被忽视。因为优秀的文档没有人会因此晋升,没有人举办文档派对,也没有人会在简历上提到它。文档就是没有足够酷,人们不愿花时间讨论它。
尽管文档可能感觉不太酷,但它在许多方面都非常重要。它能够极大地帮助一个人从合格的系统管理员变成一个优秀的系统管理员。
文档具有一些有趣的功能。当然,它可以帮助我们回忆起系统如何运作以及需要执行哪些任务。它允许我们将任务交接给他人。如果我们度假、生病、跳槽甚至退休,它还能够保护公司。但除了这些显而易见的点外,文档实际上迫使我们以不同的方式思考我们所维护的系统。
在软件工程领域,编写测试用例再编写要测试的功能这一新技术已变得流行,并且证明它能够促使人们以不同的方式思考如何解决问题,从而提高效率。在系统管理中,我们也有类似的好处。更积极地进行文档编写能带来更快的流程、更好的规划、更少的时间浪费和更少的错误。采取“文档优先”的方法,即在系统构建或配置之前先编写文档,能帮助我们以不同的方式思考系统设计,并进行充分的文档记录:这是一个有意识的文档编写过程,目的是记录应该做的事情,而不是记录我们做过的事情。这提供了一种完全不同的思维方式,一种验证真实性的方式,以及一种促进文档完整性的实际过程。
如果我们强迫自己在将信息输入系统之前就进行文档记录,我们可以提高数据准确性和完整性的机会。避免回过头去试图记住在系统上所需的或已完成的所有内容是很重要的。使用文档优先的流程,我们有机会在实际使用文档时捕捉到遗漏的部分,这可能仅仅是在几分钟之后。如果我们先工作再进行文档化,就很容易忘记一些小细节,而且没有触发事件提醒我们验证文档中是否有遗漏。相反,如果我们先进行文档化,当需要将数据输入系统或配置时,就会有一个触发事件,提醒我们应该从文档中提取出相关内容。这并非万无一失,但比传统流程更为可靠。
没有人真正反对,至少在礼貌的场合中不会反对,文档是必要的,或者它是我们作为系统管理员,甚至在信息技术领域工作的过程中最重要的事情之一。它几乎成了我们反复提到的口头禅,然而很少有人真正将这个决定内化。相反,我们只是口头上承认文档化一切的重要性,却依旧将文档作为次要问题推迟到明天做,前提是如果在某个虚构的空闲时间感到无聊时再做。这正是问题所在。我们不能仅仅声称相信文档至关重要,我们必须真正相信并相应地采取行动。
我们可以整天讨论文档的重要性,但真正重要的是将这些知识付诸实践,无论对你和你的组织来说,这种实践的方式是什么。为了更有可能取得成功,我们需要使用好的文档工具。高门槛的文档要求会让我们回避它,或者认为它在正确的时间完成太过耗时。如果我们让文档变得快速且简单,我们更可能会去做,甚至可能在某种程度上享受这个过程。我个人知道,当我的文档完整且及时更新时,我感到非常满意——有那种随时可以把它展示给别人,并且对其中的内容感到自豪的满足感。
在选择文档平台时,我们需要考虑许多因素。文档将如何存储、备份、保护、安全、访问?将存储什么类型的数据:文本、音频、图像、视频还是代码?将有多少人使用它?你是否需要在办公室内部访问它?在多个办公室之间?全球范围内?是否需要第三方访问它?
维基
在过去的二十年里,维基已经成为文档的事实标准工具。维基的设计围绕快速和易于编辑展开,而在这方面它表现得尤为出色。维基传统上还使用简单的标记语言,例如 MarkDown 语言,这使得它能够在不被格式化系统篡改的情况下精确存储文本和技术数据。这会带来一个小小的学习曲线,但通过学习一些非常标准的技巧,能迅速制作出非常精确、格式良好的文档。
维基格式注重简单——尽可能简单的系统,仍然允许足够的格式化,足以用于几乎任何文档任务。这种简单的格式使得市场上有各种各样的维基产品,能够满足几乎任何特定需求。从小型、轻量级的免费开源产品,你可以自己运行,到大型的托管商业产品,你只需要注册并使用。它几乎涵盖了所有的需求。任何规模的组织都可以有效使用,并且几乎总是有与其他系统集成的维基选项可供选择。
维基通常会面临一定的组织需求,而这一点并不是平台的本地特性。维基的优势在于它既快速又灵活,但这也是它的一个重大弱点:数据过于容易被丢到不属于它的位置,并且没有留下任何能够再次找到该信息的痕迹。有些维基会超越基本功能,包含元数据标签选项或结构化数据组织选项。这些都是例外,而不是常态。
多年来,维基一直作为更大产品的组成部分,甚至是基础组件。一个很好的例子是微软的 SharePoint,它使用维基引擎作为核心渲染引擎,所有的界面细节实际上都是在维基之上渲染出来的高级组件。
维基的一个典型问题是,它们很少能够让多个用户同时修改相同的数据。它们的简化设计通常假设在编辑期间会有一个简单的使用场景——单一作者,唯一的读者。这使得维基在单用户环境中更加有用,或者在用户很少同时使用文档平台的环境中,或者在不同用户往往彼此隔离的组织中,这样他们就会在不同时间使用不同的文档页面。如果你的团队需要多个人同时进行实时编辑或查看更新的信息,那么其他文档选项可能会更适合。
实时文档
最新的文档处理方式看起来更像是倒退了一步:文字处理器文档。是的,你没看错。听我慢慢道来。
传统上,在 90 年代末和 2000 年代初,使用文字处理文档作为文档资料似乎是荒谬的,除非你是一个非常小的公司,只有一个人需要使用和访问这些文档,这种情况下,存储所有内容为文件相对容易。近年来,随着新技术的发展,几乎所有主流文字处理器已经变成了在线、基于 Web 的、多用户工具,这些工具在表面上仍然像早期的文字处理器,但在可用性或技术上大有不同。
这些下一代文档系统提供了一个令人惊讶的强大且稳健的机制,供文档用途使用。虽然没有统一的标准规定这些系统应如何运作,但一套合理的约定已经出现,并且被所有主要系统遵循,这些系统既有商业版,也有免费开源版本,并且可以在托管或自托管模式下使用。对我们来说,最重要的是这些实时文档能够被多个用户同时编辑、实时显示更改、拥有安全的访问控制、跟踪更改,并且使用可以轻松在线发布或在任何需要的地方发布的 Web 界面,同时能够将文档输出为易于携带或转移的多种格式。
现代文档处理系统,如此类系统,通常会在后台使用数据库,而不是依赖于一组单独的文档,只将单独的文档作为一个单一、大型数据集的视图,而不是完全独立的数据集。这些系统变得越来越强大,可以轻松融入其他文档管理或替代工作流程。今天几乎所有的组织都已经在处理其他业务部分对现代文档系统的需求,这些系统可以轻松地将系统文档加入其中,而不会产生任何额外的成本或努力。利用已有系统进行更多操作,是以低成本获得高价值的好方法。
由于这些现代文档系统允许多个用户同时在同一文档上进行编辑,它们在多个团队成员同时为单个客户或系统工作时尤其有用,而文档需要共享。在这种情况下,一个人所做的更改会保持所有人屏幕上的数据实时更新。文档系统本身变成了团队协作的机制,而不是因为某个人没有刷新视图而使用过时数据的风险。
类似数据的替代界面
随着这类工具越来越受欢迎,针对类似数据库驱动文档数据的替代界面开始出现。像记事本应用这样的流行替代格式开始变得更加流行。这些格式比传统的文字处理和电子表格工具知名度低,但对系统文档非常有用。
由于多媒体和经常变化的临时性质的文档,期刊风格的应用可能是理想的选择。随着时间的推移,我预计会看到更多围绕灵活文档设计的应用成为主流。
就我个人而言,我已经成为这些系统的忠实粉丝。它们利用几乎所有员工都已经熟悉的标准工具,这些工具很可能已经被用于许多其他用途,并重新调整它们的方式,非常适合它们。少量的再培训,更少的特例工具管理,以及易于访问和团队使用频率较低的易用性。
仓库
文档化的新标准是使用在线代码仓库系统。这些系统通常从一组松散格式的文本文件开始,但它们会集中进行更新和版本控制。这与之前给出的示例方法非常不同。这个系统并不解决团队成员之间的实时协作,但确实很容易使用标准开发空间中使用的工具进行离线使用。
文档领域对版本控制代码仓库的使用成为关注点的真正原因是,它已经在开发和 DevOps 领域被广泛使用,因此是一个自然的系统,适合用于 IT 文档化。使用本地阅读和写作工具轻松使用文档离线,并且还能够在线拷贝,使其非常灵活。
现在开始有办法甚至使用这种类型的文档在一些较新的编辑工具中以实时共享的方式使用。随着更多关注于扩展这一过程的鲁棒性,我们可能会看到这方面的显著进展。
票务系统
正如我们讨论的传统文档,实际上是状态文档:记录系统是或至少应该是的方式。还有更多需要记录的内容。我们应该使用的另一个系统是一个票务系统,或者换个角度考虑,变更文档。
票务系统是一种文档化工具,类似于你的 wiki。与 wiki 不同,票务系统专注于记录事件发生的时间点。它们记录错误、问题、请求、观察、反应、变化、决策等等。与传统文档不同,后者是最终的文档,展示了所有决策和变更的结果,直到当前时间;而你的票务系统应该反映你的系统和工作负载的历史,从而理论上可以回放事件的发生,不仅知道系统做了哪些更改,还能知道是谁做的、是谁请求的、谁批准的,以及为什么要做这些更改。
当票务系统使用得当时,它在系统管理员的工作中扮演着重要角色。虽然没有一个好的票务系统也能运作,但这样会增加很多不必要的工作。使用票务系统追踪分配的任务、完成工作的过程以及最终的处理结果,提供了文档化中缺失的一部分。
如果你的公司没有票务系统或不支持票务系统,考虑为自己实施一个私人票务系统。票务软件有很多种形式和种类,如果无法花费资金升级产品或增加更多功能,也有免费的软件和服务可以使用,效果相当不错。如果你觉得更合适,可以把你的票务系统当作一种个人工作日志工具。
如果无法获得高层的支持,或者它与公司运营的方式不符,你不必过度尝试将票务系统融入到公司更大的工作流程中,但很难想象任何一个 IT 部门不会从能够追踪 IT 变更事件中受益,包括被拒绝的事件,这能帮助展示部门的历史和活动,追踪由系统变更引发的潜在问题。
就像传统文档一样,票务系统有各种不同的形式和大小。试试看几个不同的系统,给它们一个机会,不要害怕切换到其他系统。找到一个适合你的系统,使你能够有效地记录你所做的更改,何时做的,更改花费了多少时间,为什么要做这些更改;所有这些都尽可能地减少工作量。
如何处理文档
很可能你今天的工作中有一些文档。更有可能的是,这些文档是不完整的、过时的,基本上没有用。没关系,几乎所有公司都面临着文档管理不善的问题。但这也是一个巨大的改进机会。
如果你像大多数企业一样拥有文档,最好的做法往往是从头开始。审视你的选项,思考公司如何需要处理文档和协作,并选择一个方法。这个方法甚至不需要是正确的。任何文档处理流程都是好的,即使你可能需要重新做一遍。选择一个系统并试试。看看它是否适合你需要存储的数据风格,使用起来是否方便,并且是否能支持你的企业所需的协作方式(如果有的话)。
不要试图立刻记录所有的内容。从一个系统或工作负载开始,尝试以非常好的方式记录这个项目。将它格式化得好看一些。组织数据,使得你需要的数据可以快速、清晰地在顶部显示,以便在解决问题时,别人不需要到处找才能找到需要的信息。去除冗余,确保数据只出现一次,且出现在单一、可预测的位置。把文档当作一个需要一定规范化的关系型数据库,第一个主要步骤是组织,第二个步骤是去除冗余。文档始终难以维护,数据的冗余几乎让维护变得不可能。试图更改同一信息的未知出现位置,无法提供找到所有信息和需要更新内容的线索。
当你找到适合自己的系统和流程时,就坚持下去。开始记录所有内容。把它作为一项重要任务,做任何事情之前都要有文档。增加工单,并开始让一切都被跟踪。
也许你在一家文档已经做得很好的公司工作。然而,通常情况下,你并不是。即便如此,如果你现在在一个这样的公司工作,可能将来再也不会遇到这样的地方了。良好的文档是稀有的,尤其是在我们还没有考虑到工单在整个文档体系中重要性之前。
对于使用哪些工具以及以什么格式记录文档,没有最佳实践,但有一些高层次的最佳实践需要考虑:
-
使用状态和变更文档系统来跟踪你系统的各个方面。
-
避免在状态文档系统中出现数据冗余(在变更系统中可以出现冗余)。
-
保持所有文档的更新和安全。
-
不要记录那些可以从其他数据中可靠重建的数据。
我们常常说需要对文档保持“宗教式”态度,大家都同意文档至关重要。然而,实际上从说到做是非常困难的。管理层很少在我们工作时验证文档,但他们会奖励完成其他工作的员工,并且对拖延表示不满。遗憾的是,通常我们职业生涯中最重要的方面,外界的人并不认为它们重要或足够有趣,因此它们往往被没有了解这些内容如何影响我们工作的人所忽视。
在下一节中,我们将从纯粹的手动系统跟踪转向开始使用工具来测量和跟踪系统,以便以更自动化的方式进行。
工具和影响
物理学的一个基本性质,以及工业工程中立刻学到的一条规则,是你不能在不以某种方式影响它们的情况下观察或测量事件。在计算中,我们面临着同样的问题。如果有的话,我们面临这一问题的程度比许多其他领域还要严重。
我们对系统进行更多的测量、记录或设置度量标准时,所需的系统资源会更多地被测量过程所占用。随着计算机的速度不断提升,能够进行测量而不会完全拖慢工作负载的能力变得更加普遍,现在我们甚至经常在操作系统度量之外,在应用程序内部追踪检查点。但我们始终需要保持对这种影响的意识。
有时,让我们拥有的系统尽可能快速地运行,而不是试图通过测量它们来判断它们的速度,可能更有价值。全速奔跑的短跑运动员比一边跑一边携带测量设备来检测速度的运动员更快。测量过程反而对他们造成阻碍。然而,获取更多反馈的短跑运动员可能会随着额外的知识不断改进。但你永远不会看到有人在试图跑过一只正在追逐的河马时(它们是最快且最危险的陆地哺乳动物之一,你知道的)先停下来开启测量设备。他们只会尽全力跑。知道如何跑得更快只有在它提供了潜在有用的数据,并且通过这些数据你能够实施改进时才有意义。而如果饥饿的河马追上你,那么所有的测量数据都将毫无意义。
不同的工具会产生截然不同的影响。有些我们在系统中使用的简单日常工具几乎不会产生任何影响,但一般只能给我们提供系统活动的极其高层次的概览。而其他工具,比如日志收集,可能需要大量资源,甚至可能对网络和存储资源造成显著的压力。
从系统中收集数据并不是唯一占用系统资源的活动。整理这些数据并以对人类有用的形式呈现它也需要资源,向外部系统传输这些数据同样如此。过程的每个步骤都需要我们使用越来越多的资源。在我们考虑检查数据所涉及的人工时间之前,这一切都已经需要大量的资源了。尽管我们总是很容易选择尽可能多地深入观察和监控系统,但除非我们能从这一过程中获得真正的价值,否则这样做实际上是有负面影响的。
一般来说,我们会在系统上使用各种工具来提供一定程度的常规度量。包括像 sysstat SAR 工具这样的数据收集工具,以及 top、htop 和 glances 等即时的、现场观察工具,它们让我们能够实时监控系统的行为。这两类工具都提供了巨大的价值。
当然,市场上有大量的免费和付费软件及服务工具,可以将你的监控工作提升到另一个层次。研究这些工具会非常有帮助,因为即便是开源工具,也已经变得异常强大和健壮。性能工具通常在本地处理,因为它们很少用于告警或安全考虑,且用来进行事后调查往往徒劳无功,因此为了性能数据的中央数据收集而产生的成本通常是不值得的。尽管如此,中央化工具仍然存在,并且在某些情况下非常有用。使用这些工具时,通常是为了便于人类操作,而非为了解决特定的技术需求。去中心化的工具能够选择性地利用“单一视图”界面,显示来自多个位置的数据,这些工具在这个特定需求上非常受欢迎。
Netdata
我通常不想深入探讨具体产品,但我觉得Netdata是一个非常出色的案例,能够展示当今市场上为 Linux 系统管理员提供的各种强大工具。
首先,Netdata 是免费的且开源的。因此,作为一个系统管理员,可能需要为任何软件购买提供合理解释,而这款工具可以免费下载并实施,从而增强我们的监控能力,而无需任何审批或通知。安装也非常迅速且简单。
第二,Netdata 提供了开箱即用的极具美感的仪表板。这些仪表板让我们的工作变得更加有趣。比如,当我们需要向管理层展示数据或在会议中展示时,几乎没有什么比 Netdata 的仪表板更能令人印象深刻和精美的了。这是一个让我们更容易向业务推销我们所做工作的工具。
第三,Netdata 使用的资源非常少。对于它所生成的惊人图形输出,你永远不会想到这样一个轻量级的工具能够做到这一点。
第四,Netdata 是去中心化的。它在每个服务器上本地运行,而不会将数据发送到中央位置进行收集。你可以将多个系统的数据汇总成一个视图,但这个过程完全在查看者的网页浏览器中进行,浏览器会主动从每个系统中拉取单独的仪表板并直接显示不同的系统。没有使用中央服务器来聚合数据后再显示。
我喜欢以 Netdata 为例,作为真正有用的、免费的、开源的、开创性的工具,它让我们在系统管理中的日常体验变得更加高效。它展示了一种模式,可能适用于许多其他产品和产品类型,从而使去中心化比初看起来更具可行性。
作为系统管理员,你要做的一件更为重要的事情就是学习如何选择工具、何时使用以及如何读取它们。我多年来发现的最有价值的事情之一,就是变得熟悉健康系统的表现,无论是在历史记录中还是实时状态中,并且能够通过查看各种工具,直观地感知系统的行为。除了谈论观察空闲系统、标准负载下系统表现的价值之外,很难有其他方法来教会这一点;当然,你对系统组件和软件工作原理的理解越深入,你就越能以有意义的方式解读你所看到的内容。
通过足够的练习和理解,基本上可以感知一个系统的行为,并对系统为何这样表现有一定的信心。这不是一本书能够教会的内容,而是需要投入大量时间与系统打交道,仔细关注你从监控工具中观察到的内容,并结合系统的性能观察,再加上对物理组件交互的深刻理解。
我发现一些短期工具,比如默认几乎所有系统都包含的top,是观察运行中的系统执行任务的完美方式,帮助我们习惯于如何在适当负载下,CPU 的使用率如何波动,进程如何变化,负载如何变化。有时,最复杂的系统故障排查仅需通过不断观察进程列表的变化(并适时截图)来完成。
这是一个能够显著区分初级和高级系统管理员的领域。它与了解基础知识的关系远不如将这些知识真正内化,并且能够在系统表现不佳时,或者仅凭别人描述问题的情况下,迅速直觉地运用这些知识!例如,硬盘在不同条件下的表现,CPU 在不同负载下的行为,缓存的命中情况,内存的调优,分页何时有利或不利等等。
理解所有这些因素是一个不断变化的目标。每个系统都是独一无二的,新一代 CPU 调度器、NUMA 技术、硬盘技术等常常会改变系统的表现,以及我们应对它们的预期。经验无可替代,获得经验的唯一途径就是实践。
选择工具可能很困难。除非我有非常具体的工作需求,否则我倾向于保持工具的简洁性。你应该尝试使用许多不同的测量工具,以便对可用的工具有一个良好的了解,并随时准备在需要时为自己和当前任务选择合适的工具。对我来说,许多情况下,像free、top和sysstat 工具集这样最简单的工具足以应对我所做的几乎所有事情,而且这些工具在我遇到的每个系统中都有超过十年的使用历史。但在我自己管理的系统环境中,你通常会发现我也会使用一些更具图形化和趣味性的工具,比如 Netdata。
最佳实践:
-
在你需要它之前学习测量工具,并学会迅速高效地使用它。
-
将测量工具的使用限制在真正有用的工具上。没有充分的理由,不要影响性能。
现在我们已经讨论了如何衡量我们的系统在做什么,接下来的部分将开始使用这些工具来规划未来。
容量规划
当我们将系统资源使用的知识从眼前的状态中抽离出来,并开始将其应用于系统的长期方面时,我们便开始思考容量规划。容量规划应该至少在理论上是系统管理中的一个相当重要的方面。然而,许多组织会将容量规划视为一种非技术性活动,将其从系统管理员手中剥离。让我感到吃惊的是,系统管理员常常告诉我,他们收到了自己没有指定的硬件,现在必须使其正常工作,尽管该硬件是由一个完全不了解其用途的人设计的!在系统管理中如此多的系统设计知识和培训被忽视,重要的采购也在没有任何道理的情况下进行。
购买时已经设计好
我经常遇到的最奇怪的问题之一是系统管理员问我,应该如何设置他们已经指定、订购并收到的硬件。最关键的是,他们问如何配置 RAID 和逻辑磁盘的划分或拆分物理阵列。我总是对此感到惊讶。
显然,服务器的不同配置会改变其在硬件层面的配置需求。服务器运行的软件、软件的数量、软件所需的性能、所需的存储量、备份如何工作以及几乎所有与服务器在预期生命周期内使用相关的内容,都必须被充分理解,才能开始指定购买硬件的过程。你是如何知道要购买多少 RAM、多少核心、CPU 应该有多快、应该选择哪些 CPU 型号,甚至是哪些品牌适用的?在许多情况下,人们会因为过度购买而浪费大量资金,结果看似一切正常,因为这些错误表现为没人去调查的金钱损失。给定了服务器预算后,没有人跟进确定所购买的服务器是否物有所值,只关心是否在预算内。因此,过度购买往往是一种弥补未进行容量规划的方式,而这种方式可能会给公司带来巨额损失。
最显著的变化是 RAID 配置。当有人问我如果为这个项目专门购买了新的硬件,推荐哪种 RAID 级别和配置时,我不知道该如何回答。关于 RAID 配置的所有决策肯定是在购买服务器之前就已经做出。只有了解每个 RAID 级别的性能、可靠性和容量特征,并结合可用的物理驱动器和控制器选项,才能开始考虑购买服务器存储部分。
为了决定存储需求,首先必须了解自己的需求。然后,必须知道你指定的硬件如何满足这些需求。当有人说他们已经购买了硬件,但还没有指定任何设计时,以下是我脑海中浮现的一些问题:
你是如何知道该购买哪个硬件 RAID 卡?或者甚至是你是否需要硬件控制器?
你是如何确定购买多少缓存的?
你是如何知道哪些类型的驱动器最有用的?
你是如何知道需要什么速度的驱动器以满足吞吐量和/或 IOPS 需求的?
你是如何知道该购买多大尺寸的驱动器的?
你是如何知道该购买多少个驱动器的?
你是如何确定缓存容量的?
你是如何确定分层存储容量的?
你是如何确定热备份需求的?
做出这些决策所需的前提是必须先做出所有其他决策。最终的结果是整体的产物,例如,RAID 级别的任何改变都会极大地影响可用容量、系统性能和整体可靠性。每一个小的变化都会引发其他所有事情的变化。没有任何一项是可以单独决定的,更别提改变了。哪怕是最不起眼的变化,也可能导致系统容量不足,或者处理工作负载的速度不够;更危险的是,存储系统的可靠性可能在极端安全和极端危险之间剧烈波动。
很难形容这个过程有多疯狂;更疯狂的是意识到,这可能已经成为人们购买服务器的常态!我能想到的最好比喻是,就像为一辆 1978 年的法拉利买一个变速箱,却期望它能正常工作,而你甚至还不知道自己是买到一辆车、一艘船还是一架小飞机,更别提是什么年份和型号的法拉利了!
容量规划不仅仅是为了省钱,至少间接上是如此。它关乎确保我们购买的系统能够在合理的时间范围内满足我们业务的所有预期需求。显然,这是一个非常难以确定的数字,因为什么是合适的预期,未来可能会发生什么变化,以及为系统设定合理的时间框架,都是相当灵活的概念。
在商业中,使用空中楼阁式的数字作为硬件投资基础,并利用硬件的最大合理使用寿命进行计算,从而展现天文数字般的增长,已经成为一种常见趋势。虽然我们无法控制驱动企业运作的政治过程,除非在极少数情况下,但我们可以控制的是我们向决策者提供的数字质量。
晚些时候购买
好的商业逻辑告诉我们,除非极少数例外,否则 IT 中的所有成本随着时间推移都会下降。它下降得非常多。与几年前相比,今天内存、计算周期或存储的成本微不足道,这一趋势实际上从未停止过,也不太可能逆转。由于制造或物流危机带来的短期稀缺问题确实可能发生,但这些事件非常罕见且持续时间极短。只要有时间去做购买,几个月后的系统成本肯定会比今天更低。无论是我们花的钱变少了,还是我们为这笔钱得到的东西更多了,结果都是我们通过推迟投资来获得利益。
我们可以使用一个常见的例子:假设我们今天购买一台服务器,计划使用它八年,并且我们预期会有增长,因此我们购买一台满足八年需求的服务器。为了获得这样一台强大的服务器,我们今天可能需要花费$20,000,或者,如果我们只预期服务器能用四年,可能今天花费$8,000 就能买到。差距很大。当然,这是一个假设的例子,但在现实世界中,这类成本在许多常见场景中是非常典型的。
在这个例子中,我们假设在四年后我们可以再花$8000 购买一台新的服务器,满足接下来的四年需求。虽然这个例子有点牵强,但通常是成立的。成本通常会按这种方式计算。
购买更少、更短时间内使用的设备的优点是无法过分强调的。首先,由于服务器定价的特点,购买更少的设备、更加频繁地更换往往能节省硬性成本,因为现代服务器的运营生命周期内,会发生一些价格上的优惠。接着是货币的时间价值理论,这意味着如果你花费相同金额的钱,但推迟了支出,你就可以在此期间用这笔钱赚取更多的钱,而且未来你所花的钱,其价值比今天的钱要少。最后,还有更新的技术——如果我们等几年再购买新的服务器,我们可能会得到更多更新的技术,不仅能提升容量,还能带来更低的能耗、更好的耐用性等优势。
然后是拥有两台服务器的优势。我们假设第二台服务器将替代第一台,或许会是这样。但我们也可能只是用这次购买来扩展容量,第一台仍然可以继续投入生产服务。如果我们是替换第一台服务器,它可能会在组织内的其他角色中重新部署,或者作为新服务器的备份。几乎总是可以找到一种高效的方式来利用最初的投资。
最大的优势很可能在于延迟决策。通过推迟几年的开支,我们获得了在任何时候投资这笔钱的灵活性,甚至可以选择永远不投资。与其做一个八年的预测,这种预测极其不准确,甚至毫无用处,不如做两个四年的预测,虽然仍然相当不准确,但其准确性提高的幅度却是显而易见的。在第一个四年检查点时,我们可以评估上一个预测的质量,并根据新的数据和新的起点做出新的预测。我们不仅能根据四年的新见解重新评估自己的组织,还能获得四年内行业的变化和新技术的洞察。很少有公司会在四年后做出与今天相同的决策。在商业中,这种延迟决策的方式可能带来天文数字般的好处。
可悲的是,对于大多数企业来说,预测变成了一种情感上的练习,因为这样做有政治上的好处,能让人们感到愉快,并表现出对企业或领导层的信任;而且,想象自己必定会取得的成功也让我们感觉很好。而更好的预测通常意味着更大的影响力、更大的预算、更多的资源可以使用。这些资源会持续多年。几乎没有企业会回过头来评估过去的预测,看看人们是否做得好,所以过于乐观的预测会带来奖励,而且如果这些预测被为了个人利益(无论是情感、财务还是政治上的)伪造,几乎没有惩罚的风险。这种系统使得预测变得非常危险,因此,我们做任何能够减少对预测依赖的事情都很重要。
最终,推迟购买服务器资源直到真正需要时,是我们在技术采购中可以采取的最佳实践策略之一。从纯粹的财务角度来看,这种方法是最好的,从决策和规划的角度来看,也是最优的,最能让技术和制造进步为我们所用。
在这一过程中,系统管理将提供三个关键数字。第一个问题是 我们目前使用了多少资源? 第二个问题是 我们过去使用了多少资源? 第三个问题是 我们认为未来会使用多少资源?
事实上,回答这些问题中的任何一个都出乎意料地困难。仅仅统计我们今天所购买和拥有的资源并没有提供任何有用的信息。我们需要真正理解我们的 CPU、RAM 以及存储的各个方面是如何被使用的,它们如何影响工作负载。
例如,如果我们正在运行一个大型数据库实例,数据库可能会非常乐意将大量存储缓存到内存中,以提高数据库性能或减少存储磨损。但是,减少可用内存可能对数据库性能没有影响。正因为如此,仅仅测量内存利用率可能会非常复杂。我们使用了多少有效内存?存储比较容易测量,但也存在类似的挑战。CPU 是最简单的,但没有什么事是完全直观的。仅仅因为我们在某个水平上使用系统资源,并不意味着我们知道它们的实际需求程度。
在使用 CPU 时,我们可能会遇到一个系统平均 CPU 利用率为 50% 的情况。对于某个公司或一组工作负载,这可能意味着我们可以在该系统上放置两倍的工作负载,使其利用率接近 100%。而对于另一个公司或一组工作负载,这可能意味着我们已经超载了系统,系统出现了足够的上下文切换和等待时间,导致一些应用程序注意到延迟。许多公司通常以 90% 的利用率作为宽松的平均目标,但对于其他公司,可能需要将目标设定为仅 10%。
在这种情况下,权衡的关键是等待吞吐量还是延迟。可用的 CPU 周期意味着 CPU 可以执行更多的任务,但如果 CPU 始终忙于处理任务,那么当新任务突然到来时,它可能并不完全可用。如果你正在处理低延迟系统,确保系统资源随时可用以处理刚出现的任务可能是一个必要条件。为了评估系统的容量使用情况和需求,我们不仅需要深入了解系统被使用了多少,还要理解这些使用对工作负载的最终影响。
与系统管理的许多方面一样,关键是要全面了解我们的工作负载。我们必须知道它们是如何工作的、如何消耗资源、以及它们如何响应更多或更少的资源。我们在容量规划中的一切操作都取决于此。
当然,我们有一些前面提到的工具,能够帮助我们判断系统的性能表现,通过应用测量工具和/或人工观察,我们可以合理地确定当前工作负载所需的资源。
我们使用的许多工具也可以用来收集系统性能的历史记录。如果我们总是这样做,可能会产生大量的数据,而我们永远也无法准备好去利用这些数据。有些组织会一直收集这些数据,但这是例外,而非常规。更实际的做法是在大多数情况下随着时间的推移开发并跟踪基准。这通常意味着进行某种活动,记录测量数据,并记录系统的最终用户应用性能,以便你可以回顾并了解系统的利用情况。这些数据应该在长时间内收集。至少几周或几个月,以便找到热点和冷点。常见的冷点可能是在星期天的晚上,当许多应用程序根本不被使用时。常见的热点则是月末的财务处理时间。每个组织的利用模式都不同,你需要了解自己的模式。
有了这些收集的数据,我们可以分析系统利用率如何随时间变化。变化通常来源于应用层利用率的增加或减少。但这远不是唯一可能发生变化的方面。需要意识到的是,应用更新、操作系统补丁、系统配置变化等应当被记录并与数据记录一起标注,以使得这些数据在评估时更有意义。
长期的数据收集必须考虑到努力成本。收集数据并整理这些数据,无论规模多大,都可能非常耗时并且可能会消耗大量资源。收集了所有这些数据后,它可能不会提供有用的见解,或者分析它的技能可能缺乏。如果一个系统管理员在处理持续使用的系统时,能够凭记忆追踪系统性能数据,这是完全合理的。在某些情况下,这种做法会更为实际。
过多的数据开销的风险
在进行容量规划时,我们有可能创造一个情况,即我们为自己制造了更多的开销,这通常意味着更高的成本,甚至可能比如果一开始就没有收集数据的情况还要高。我们需要找到一个适当的平衡点。
大型组织通常会在大量数据收集中找到巨大的价值,从而在大规模上节省资金。在大规模的情况下,自动化数据收集和分析通常相对简单。小型企业则往往会觉得这种做法不切实际。收集单个服务器的任何合理全面的系统数据,可能会导致支出大到与系统本身的成本相当。显然,这是行不通的。常识必须占上风。
许多小型组织可能只有一个主要的工作负载,并且可能永远无法充分利用最小的服务器,从容量的角度来看,通常会过度配置,直到他们放弃使用自有硬件,若那时变得切实可行的话。大组织则是在运营大规模的服务器集群,他们有许多途径可以通过尝试不同的软件选项、使用更多小型服务器或更少的大型服务器、使用不同的处理器型号甚至架构等来改善整体成本。
节省开支的努力必须与数据收集的潜在价值保持平衡。这对于所有决策过程都是如此。要小心,数据收集是决策高成本的组成部分,你必须时刻记得保持这一成本远低于该决策的预期价值水平。
在评估数据收集的成本时,我们需要考虑收集数据的时间、存储成本和分析这些数据的成本。我们不能忘记,还得考虑考虑这些的成本!
有些供应商专门提供工具来解决这些难题,它们可能非常有效。戴尔(Dell)便是其中之一,著名的戴尔为客户提供可以长时间运行并生成非常详细报告的工具,报告内容包括系统如何使用,当然,工具也提供建议,但这些建议实际上是推销,目的是为了卖给你更多的产品。如果使用得当,这些工具可以非常有价值。
当然,自然的问题也会是*“那么云计算呢?难道这不会改变一切吗?”* 是的,考虑到云计算非常重要,它确实会影响这一过程。
随着云计算进入到组织的规划中,从某种程度上来说,我们需要考虑的复杂性增加了。从另一个角度看,云计算能够让容量规划过程变得更加简单,甚至可以说不再重要。
在云计算中,或者至少在几乎所有的云计算中,我们按需或几乎按需购买容量。这就是云计算的魅力。只使用你所需要的,让系统实时决定需要什么。这在理论上是很棒的。但仅仅让系统自行决定仍然需要我们预测这种方法的成本,以便在财务上与其他替代方案进行比较,并且预测成本以便正确预算。
如果你的组织目前正在使用云计算,这将大大简化我们的过程。通常,你的云平台本身能够告诉你大量的系统使用率信息。即使没有传统的报告形式,云计算的账单也常常能提供你所需要了解的关于许多类型规划的信息。
我们的容量规划最佳实践纯粹是数学性的。利用我们对系统和工作负载的合理测量和理解,以及对商业预期和来自其他团队的输入,来规划明天及未来的容量需求。研究并理解不确定性锥,结合对未来越来越难以预见的感觉以及对时间价值等金融概念的良好理解,使用这些来为你组织的未来容量投资需求提供最佳努力评估。
容量规划通常是枯燥的,且比技术性更具政治性,但这一角色很少有人能胜任,除非是系统管理员,因此,在专业生活中,它注定要让我们与系统硬件采购预测紧密相关。它本质上是我们企业内部的小规模计算未来市场。在下一部分,我们将从容量和性能需求转到安全和故障排除工具,首先是系统和应用日志。
日志管理与安全
如果你在酒吧和系统管理员闲聊,你可能会认为,系统管理员的主要任务之一是收集所有系统日志,并每天花费几个小时,手动且熟练地逐行查看日志,寻找系统错误和恶意行为者。现实情况大不相同。没有人在做这件事,也没有公司愿意为此支付费用。日志阅读是一项严肃的技能,且是一项极其无聊的活动。人类在这类任务上的表现非常差。
如果你试图让人类在没有已知系统问题的情况下实际读取日志来进行日志管理,你会遇到一些问题。首先,现实情况是,没有人类能以足够快的速度读取日志来真正有效地工作。系统记录了大量数据,试图跟上这种无意义信息的流动会使人类容易出错。然后是成本问题。任何足够熟练以处理这种日志阅读的人都会处于薪资的高端,且由于这一工作非常痛苦,它必须是一个高薪职位,而由于服务器通常是全天候运行的,你可能需要为每台服务器配备四到五个全职员工才能勉强做到这一点。这种成本超出了任何人的想象,完全不切实际,甚至可以说是毫无用处。因此,没人会这样做。
这并不意味着日志没有价值。相反,事实恰恰相反。日志非常有价值,我们需要收集、保护并知道如何使用它们。
在处理日志时,我们需要知道如何读取它们。这看似微不足道,但当你遇到紧急情况,需要读取日志时,那可不是发现自己不理解日志内容或如何解读它的好时机。Linux 上的系统日志相当一致。真正的挑战开始于不同应用程序也在记录日志时。这些日志可能是独立的,也可能被合并到其他日志中。每个应用程序负责自己的日志记录,因此当我们开始运行多个不同的应用程序时,日志的多样性可能会带来相当大的潜力。此外,如果还有定制的内部应用程序进行日志记录,事情可能会变得相当复杂。
在这里没有必要教你如何读取日志。这是任何阅读本书的人都应该非常熟悉的活动。不过,你现在应该做的练习是,浏览你的日志并确定哪些日志的格式对你来说是陌生的,确保你随时准备好读取任何系统日志,而无需在读取前进行额外的研究。快速高效的日志读取将大大提升你成为一名更好的系统管理员的能力。
仅仅知道如何读取日志是不够的。你还应该足够熟悉你的日志,以便识别正常活动的表现。当你先知道正常的表现是什么样子时,你将更容易识别问题。许多公司在问题发生后聘请专家来处理这些问题,但这样做会带来更多的挑战,因为没有日志基准来与当前的情况进行比较。
如果没有一个可靠的基准,定期发生的错误可能会浪费大量时间,因为诊断时间将被花在研究它们上,以确定它们是正常的日志噪声、真正的问题,还是正在诊断的问题的组成部分。当出现问题时,我们希望更加高效。这正是我们最不希望花时间去弄清楚正常表现是什么样子的时刻。
准备好直接登录到服务器并使用传统工具,如 vi、view、cat、head、tail 和 grep 来查看日志,始终是一个好习惯。你永远不知道未来会遇到什么样的情况。
在今天的许多现代系统中,我们期望看到围绕日志的广泛工具支持,因为我们可以做的远不止仅仅将日志存储在本地服务器上,并在发生问题后进行查看。
今天,日志记录是服务器系统中发生巨大变化和进步的领域之一。相比二十年前,日志记录已经取得了飞跃性的进展。像高性能的图形化日志查看工具这样的简单进步,使得查看日志变得更快、更容易。同时,还有先进的集中日志管理,将日志从服务器本身转移出去,还有自动化的日志处理。
无论日志是本地的还是远程的,现代的日志查看工具在我们使用日志的效率上都带来了巨大的改变。无论是使用本地桌面 GUI、终端上的字符界面会话,还是现代的 Web 界面,日志查看工具都在不断改进,在过去十年甚至更长时间里,它们使得阅读日志变得既愉快又简单。令人惊讶的是,只有极少数的组织提供这些工具或支持其使用,因此,系统管理员使用这些工具的情况比应有的要少得多。如果你和系统管理员交谈,不要感到惊讶,如果发现很少有人真正有机会在拥有超出基本系统日志文本文件和操作系统自带的标准文本文件处理工具之外的环境中使用日志工具。
良好的日志查看工具是日志管理旅程中的重要起点。让日志能够快速查看,使其查看过程尽可能简单和愉快。当事情出错时,你肯定不想花费比绝对必要的更多时间去访问日志或深入挖掘日志。你更不想在系统出现问题时,还在忙着安装日志查看工具。
日志查看应用程序只是大多数组织的起点。日志管理的真正飞跃发生在引入集中日志收集时。这才是真正的日志革命发生的地方。当然,即使回顾几十年,基础日志聚合的潜力和工具也早已存在。这可以简单到使用网络复制命令或网络映射驱动器将老旧的文本文件存储到中央文件服务器上。所以,集中日志的基本思想并不新鲜。
最初,集中日志的限制是服务器没有网络连接。后来是性能和存储问题。集中日志需要大量的网络带宽和存储容量,在某些情况下,对于日志服务器来说,这也是一个性能噩梦。那些日子早已成为过去。今天,随着我们系统各方面容量和性能的自然提升,这些问题变得微不足道,而日志的大小和复杂性增长却远远小于过去。如今,日志的大小其实并没有比几十年前大多少。
早期的日志集中化系统非常基础,无法优雅地扩展。大量聚合的日志数据对大多数系统来说是一个巨大挑战,因为它们需要能够持续从多个来源摄取大量实时数据,同时还能回溯并展示这些数据。
现代的日志集中应用程序都使用了围绕数据流和存储需求设计的全新现代数据库。没有单一类型的数据库被用于此目的,但许多新型数据库在处理这些需求时表现出色,它们允许传统上作为大型、笨重的文本文件存储的数据被压缩成更小、更高效的数据库条目,带有元数据、缓存、整理等功能,这些特性使得可以处理比以往更多的数据量,同时仍然能够有效地展示数据。这一变化,加上系统性能的整体提升,使得集中式日志管理不仅在局域网中得以有效实施,在许多情况下,甚至适用于托管服务器、云服务器或其他不在传统局域网中的服务器。
使用这种系统有几个好处。一个是日志读取的速度和效率。一个(或至少较少的)地方来查看日志意味着系统管理员比以前更快地查看日志,而更快的日志读取意味着更快的解决方案。通过将来自多个服务器、系统、应用程序等的日志集中在一个地方,我们还可以在这些系统之间关联数据,而无需人工查看来自多个来源的日志并手动建立这些联系。
新工具,如流量图,也让我们能够看到以前可能未能察觉的模式。如果多台计算机的日志流量突然激增,可能是应用程序突然变得繁忙,或者也可能是出现了故障或正在发生攻击。集中式日志工具不仅让我们更容易理解单个系统的基准是什么,还能帮助我们理解所有系统结合起来的基准是什么!这为系统理解增添了更多层次。
一旦我们将这些现代工具集中化,下一步逻辑就是使用自动化工具来读取日志。安全信息与事件管理(SIEM)是通常用于自动化日志监控工具的术语。日志自动化并不新鲜,甚至美国政府早在 2005 年就已经制定了相关规定。但对于许多企业而言,日志自动化远远超出了他们当前的计划或能力。
当然,像任何自动化一样,我们使用它的程度可以有很大差异。简单的自动化可能仅仅在日志中发生某些触发事件时发送警报,或对不符合特征的活动模式进行警报。复杂的自动化可能使用人工智能或威胁模式数据库,跨多个系统同时扫描日志,寻找恶意活动。
为什么要进行日志集中?
鉴于集中式日志记录带来了如此大的网络开销,并且实施成本通常很高,很容易质疑将日志集中到单个服务器或一组服务器的价值,而不是将日志保留在各个主机上并寻找更好的方法来检查它们的日志。这是一个非常合理的问题。当然,集中式日志记录并不适合每个组织。但它确实适合许多组织。
虽然许多进展使得中央日志记录比以往更具能力,但也有许多进展使得去中心化的日志记录变得更好,包括带有报告、告警、吸引人的用户界面的设备端日志查看器,以及显示来自多个来源数据的聚合工具,尽管这些数据本身分散在不同地方。
然而,中央日志记录提供了独特的优势。最大的优势就是数据不与设备绑定。如果设备出现故障、离线,或者设备被攻破,我们的日志就可以实现隔离。经常会遇到需要重新启动一台服务器并让其恢复运行,只是为了查看该服务器的日志。
如果服务器完全崩溃,我们可能根本不想再费心让它恢复在线。或者如果日志告诉我们发生了灾难性故障,我们可能就知道我们不应该尝试恢复已失败的设备。又或者,我们可能希望一个人专注于恢复失败的服务器,同时另一个人则扫描日志以确定导致故障的原因,或者确定恢复服务所需的条件。
如果服务器或应用程序被攻破,存在日志机制或存储系统也被一起攻破的风险。实际上,这种情况通常是非常可能发生的。修改日志以掩盖入侵是高级攻击中非常常见的手段,而简单的攻击则通常通过删除日志来实现。大多数情况下,日志会被攻击,因为它们是最容易识别入侵发生或正在发生的地方,并且可以判断如何进行缓解。如果日志中从未显示出攻击的任何迹象,你可能永远不会发现入侵已经发生。
如果我们将日志(无论是全部还是至少复制一份)实时发送到远程日志服务器,那么我们就可以将日志存储在与应用程序和服务器存储隔离的地方,并且通过气隙(air gap)使得若要修改这些日志,必须攻破一个完全无关的系统,且不能被发现。这比直接修改日志要困难几个数量级,特别是当任何外部日志系统的存在及信息通常在入侵发生时才会被发现,这时可能已经太晚,无法避免被检测。
由于日志不仅仅是查找错误的方式,更是审计和追踪安全漏洞、恶意活动、渗透尝试等的关键安全记录系统,因此,必须确保这些数据免受意外丢失和故意破坏。
日志分离的一个可能最重要的目的,至少在那些足够大的组织中,足以拥有多个 IT 团队时,就是职责分离。如果日志完全由控制服务器的同一个系统管理员(假设是你)控制,那么对日志进行重大修改并隐藏这些修改的证据就变得非常简单。如果日志被发送到一个我们不是管理员的外部系统,那么我们就很难隐藏这些更改,因为我们必须在不让日志记录失败的情况下,防止它们被记录下来。
对于这种级别的安全性,严格的职责分离听起来可能是大公司特有的事情,但即使是非常小的公司,甚至那些没有足够大到拥有一个全职系统管理员的公司,也可以通过使用外部托管的日志平台来利用这种系统特性,而不是自己运行日志系统。这样,所有必要的系统管理和日志平台的安全性不仅与个别系统管理员隔离,而且也与 IT 团队以及整个公司本身隔离开来!
因为每个企业都有其独特性,所以根据你的需求,日志管理和日志管理的层次会有所不同。我们的 IT 座右铭必须是:一刀切并不适合所有情况。
所以,我们的日志最佳实践是一个具有挑战性的任务。我们需要评估日志需求。我们如何高效地利用日志来更快、更好地解决问题?我们如何提高安全性?是否存在使本地日志存储超过远程日志存储的优势因素?我们是应该托管自己的日志系统,还是使用第三方 SaaS 应用程序,让他们为我们管理?SIEM 或类似解决方案的安全性收益是否值得其成本和复杂性?
我们唯一真正的最佳实践是确保在需要之前就做好阅读日志的准备,并且不时查看日志,以了解对你而言一个健康系统的表现。
在日志管理方面,我们不得不更侧重于经验法则而非最佳实践。一般来说,中央日志收集对于几乎任何有多个关键工作负载的环境都是值得投资的。这可能意味着一个拥有多个工作负载的公司,或者较小的公司一般应当使用某种形式的外部支持供应商,而该供应商理论上会有多个客户,并且通常会受益于类似的方式,允许他们为客户集中日志。
最小的 IT 部门
这是一个超出系统管理职责范围的话题,但每个 IT 人员都应该真正理解它,因为几乎每个 IT 角色在某个时刻都会面临成为一个组织的一部分,而这个组织无疑过于小型的局面。
在大多数领域,我们可以谈论任何专业团队的最小规模。医生、律师、汽车修理工、兽医、软件工程师等等。在所有这些例子中,我们都可以讨论让某个职位成立所需的人员和团队。一个没有护士或任何助手的医生将非常低效,并且缺乏某些医疗训练的维度。兽医也是如此,如果你是一个独立的兽医,没有接待员、收银员、兽医技术员等等,那么你将被迫在自己价值的很小一部分上承担多个角色。软件工程也是如此,涉及到软件设计的广泛离散任务和角色,这些工作即使在一个小项目中,也不可能由一个人合理地完成。
IT 是其中一个最具戏剧性的领域,因为 IT 涉及的知识面如此广泛,涵盖了许多完全不同的领域。而且每个公司都需要一大范围的 IT 技能。一些技能是特定环境所独有的,但大量基础技能几乎适用于任何公司。
这其中最具挑战性的一方面是,几乎没有空间容纳未成熟的技能。因为信息技术(IT)是围绕核心业务功能、基础设施、支持、效率和安全进行决策和指导的,所以在任何时候,你都希望有专家和成熟的指导。一个看似简单的错误,几乎发生在整个基础设施中的任何地方,都可能成为一个突破口、一个过度支出的风险,或者一个从小错误开始却导致一系列连锁反应的决策,这些决策都将基于那个错误。
大多数企业不需要大多数技能,甚至几乎不需要任何个人技能,某些技能(如 CIO)可能一年只需要几个小时。显然,如果某项技能每年只需要几个小时,甚至每天只需要几个小时,那么全职支付这项技能的费用显然是没有意义的。
接着是覆盖的问题。许多企业只需要在每周工作四十小时内提供支持,并且严格的办公时间内,所有系统都可以在下班时离线。然而,这种情况并不常见。大多数企业需要每周运营六到七天,每天长时间工作,并且全天候运行是完全合理的。为了提供完全的支持,仅仅让某人回答支持票,甚至做出决策或解决实际问题,就需要至少五个人来轮班,忽略任何技能要求。
当你考虑到即使在最简单的 IT 环境中也存在的所有独立角色:系统、网络、CIO、帮助台、桌面支持、终端用户支持、应用程序支持,以及任何专业角色如云应用、备份、灾难恢复、项目管理等,你会发现很多公司试图寻找一个可以胜任所有这些角色的人,一个通才。这是一个很好的理论:有一个拥有众多技能的人,可以做每个角色的一点,合起来就是一个完整的人。
在现实世界中,这根本行不通。首先,因为真正具备所有这些技能、能保持技能更新并且在所有这些技能上都很出色的人,估计在全世界可能得用一只手就能数得过来。其次,任何具备良好 CIO 水平或系统管理技能的人,单凭这些技能就能有很高的按小时计费价值。一个员工的价值总是基于他们的最高技能的全职价值,而不是最低技能的价值。而拥有额外技能可以提高你的最大价值。所以一个具备所有这些技能的 CIO,从理论上讲,应该比只有 CIO 技能的人更有价值。所以即便你找到这样一个人,你要么得支付他们一笔巨额薪水,才能让他们做这个工作,要么他们得愿意以自己价值的极小一部分薪水做这份工作,而从雇佣角度来看,这毫无意义。
其次是覆盖问题。一个人能工作多少小时,通常意味着业务大部分时间没有得到支持。即使你有一家只在每天八小时内运营的公司,且愿意在这段时间内做所有支持和主动维护,仍然存在这样一个问题:一般来说,一个人被要求执行的许多角色需要同时进行。
令人惊讶的是,各种规模的公司都在尝试这种方法,并普遍得到了糟糕的结果,尽管很多公司从未衡量过他们的结果,甚至不了解 IT 部门应该呈现的良好表现是什么,或者该部门应该完成什么任务,因此往往忽视甚至赞扬这些领域的失败。
找到一个理论上有效的 IT 部门最低规模是很困难的。作为经验法则,如果你不至少需要三名全职 IT 员工,且他们从不做任何 IT 之外的事情,那么你就不应该尝试组建一个 IT 部门。
许多 IT 企业,如管理服务提供商和 IT 服务提供商,为只需少量各种资源的企业提供 IT 技能、管理、监督和工具。更小的公司不应该因为求助于这些公司而感到难过,这些公司为实现良好的 IT 运作所必需的规模和分工提供了必要的支持。话虽如此,正如雇员一样,普通公司的表现不会太好。因此,你希望确保你雇佣的不仅是好员工,也要雇佣一个好的服务提供商。服务提供商很像雇员,但更可能与你的业务需求保持一致,并且通常有更长的潜在服务期 - 一个良好的服务提供商关系可能比一个员工的职业生涯更长。
从两面重新审视不合适的 IT 部门可能会提升整个行业。许多雇主对基于他们施加的 IT 结构而预料到的不良 IT 结果感到不满。而许多 IT 从业者对他们的职业或至少是他们眼下的工作感到不满,因为他们觉得他们必须或被鼓励在根本没有任何意义的环境中工作。
将服务提供商视为内部 IT 团队的一部分,可以让你以实际可行的价格获得所需的 IT 团队。IT 实际上并不超出任何公司的预算。如果看起来 IT 费用将会太高,那肯定是出了问题。IT 的工作是为企业赚钱。
我看到的公司与服务提供商合作时最常见的错误之一是假设许多不正确的参与规则,比如假设当地资源更好或者服务提供商必须匹配你计划使用的技术 - 如果你这样做,你怎么会确定要雇佣哪家服务提供商,因为只有他们才有决定使用的技术的专业知识!这确实是一个进退两难的局面。另一个关键错误是将服务提供商(提供 IT 服务的公司)与增值再销售商(供应商销售代表)混淆。后者通常会自称为前者,但很容易区分。第一个公司的业务是提供 IT 作为服务。第二个公司的业务包括销售硬件、软件和第三方服务,可能还包括添加一些 IT 服务。
最佳实践:
避免运行过小以支持必要角色和分工的 IT 部门。
永远不要雇佣转售商来做 IT 服务提供商的工作。
决不允许你的 IT 员工(内部或外部)存在利益冲突,并且还销售他们推荐和选择的硬件、软件和服务。
现在我们大致了解了为什么日志记录对我们的组织至关重要。良好地使用和理解日志,并为日志建立一个适当、深思熟虑的基础设施,是我们真正看到 IT 部门在挣扎与卓越之间分水岭的领域之一。
目前并不涉及太多技术性的讨论。实际上,这完全是关于坐下来投入精力来制定和推出日志记录计划。让日志记录在您的组织中发生。无论是集中式的、去中心化的,还是自动化的,任何适合您组织的方式。开始着手,确保您的日志成为一个强大的工具,使您的工作更加轻松。
在接下来的部分,我们将从日志记录继续,探讨更一般的监控。两个高度相关的概念共同作用,真正将我们的管理提升到另一个层次。
警报与故障排除
在刚刚讨论过日志之后,我们现在需要考虑与之高度相关的系统警报的概念。我必须提到,当然,日志系统本身也可能是警报的来源。如果我们在日志系统中使用自动化,那么这些自动化通常会被期望直接发送警报,或将警报添加到警报系统中。
警报从根本上来说,是我们的监控系统与我们这些人类沟通的方式,告诉我们它们出现了问题,是时候让我们介入并发挥人类智能的魔力了。虽然我们希望系统能够自动化并修复许多问题,但现实是,在可预见的未来,几乎所有公司都必须在一个需要定期进行人工干预的系统管理环境中工作。无论是登录并清理已满的磁盘、停止一个损坏的进程、识别一个损坏的文件,甚至是触发故障转移到另一个应用程序,或通知业务部门预期的影响,人类在系统中仍然扮演着重要角色。
拥有良好的机制来发现严重问题并提醒人类是高质量支持的关键。为了理解良好的警报机制,我们必须讨论如何发现问题并如何接收到通知。
设备端和集中式警报系统
我们可以从设备端和集中式警报开始进行比较。传统上,回溯到几年前,系统通常会单独处理自己的警报。系统已经设置为将问题记录到中央日志中,因此让它们在检测到坏事时也发送电子邮件或类似的通知是一个自然的延伸。警报非常简单,每个系统都会单独处理自己的检测和警报。虽然集中式监控和警报已经存在很长时间,但外部监控的普及直到需要监控托管的互联网资源(如网站)时才变得非常主流,网站的停机通常首先由客户察觉,而不是由员工察觉。当停机首先被内部员工发现时,推迟发现的决策会更加灵活。
设备端警报的简单性很有吸引力,对于较小的组织或那些可以承受较慢错误检测的组织来说,它是非常适用的。设备端警报的关键问题在于,许多严重的故障或攻击可能会完全禁用警报,或者至少会延迟警报。例如,一个简单的例子是失去电力的服务器或其 CPU 融化的情况,系统下线是我们想要接收到警报的情况,但系统下线的突然发生排除了系统通知任何人发生了坏事的可能性。网络连接突然丢失时也会发生同样的情况。在系统被破坏的情况下,黑客可能会在被发现之前关闭警报功能,留下一个仍在运行的系统,但无法发出求助信号。
设备端警报通常便宜且简单。它通常是内置的,只需少量配置。如果使用简单的机制,如电子邮件发送警报,即使是简单的脚本也能增加很多警报功能。这种方法使用的系统资源非常少,对于小型企业或那些不必担心员工报告功能丧失的潜在停机情况的企业,它是足够的。
对于大多数企业或工作负载而言,设备端警报的局限性过大。无论系统是面向客户的,你希望最大化客户信任,还是系统是内部的,你希望将问题的发现从员工转移到 IT 部门以提高性能,或者系统几乎没有最终用户,可能永远也不会发现它无法正常工作,你都需要确保工作继续进行(例如扫描安全系统或过滤器),因此外部监控是必要的。
外部监控允许我们在系统完全失败时仍然能够传播报警。由于完全失败在报警事件中非常常见,这一点非常重要。完全失败可能意味着硬件故障、电源丢失、软件崩溃或网络断开等。这些都是常见的故障情况,所有这些情况都会导致设备内部报警失败。外部报警为我们提供了一种信心,使我们在发生故障时能够获得警报,而这种信心在没有外部报警时是缺失的。
当然,外部系统也可能发生故障,导致没有报警,但我们可以通过一些方法有效地对这种情况进行规避。一种选择当然是对外部报警系统进行外部报警。基本上是备份报警。并且,通过只使用单一的报警来源,我们可以简单地检查该来源是否正常工作。一个外部报警机制,如果与其监控的系统解耦,极不可能与另一个系统同时发生故障,虽然不是完美的,但这种方式可以轻松消除 99.99%以上的漏报,对于大多数组织而言,这已经足够了。
带外设备报警
在报警管理中,可以有一定的折中。如果我们把系统视为一个层次结构,那么每个层次较低的设备都能够以非常微小的方式监控其上方运行的服务。例如,应用程序可以告诉我们数据库连接是否正常,操作系统可以告诉我们应用程序是否仍在运行,虚拟机管理程序可以告诉我们操作系统是否仍在运行,而在堆栈的底部,带外管理硬件设备可以告诉我们核心系统组件是否已发生故障。
该系统并非万无一失,且通常相当基础。操作系统对应用程序进程的工作了解非常有限,通常只能告诉我们应用程序是否已完全崩溃并返回错误代码给操作系统,或者它可以告诉我们应用程序是否使用了过多的资源,例如突然增加内存请求或消耗大量的 CPU 周期,但操作系统无法判断应用程序是否仍在运行,但却向最终用户抛出错误或乱码。
对于不熟悉的人来说,带外管理实际上是一个外部计算机,它安装在机箱内,与服务器硬件同处一体,但它有自己的小型 CPU、RAM 和网络。由于它与服务器本身几乎是完全独立的计算机,因此带外(OOB)管理系统可以直接或通过某些监控系统报告服务器本身的关键硬件故障,例如主板、CPU、内存、存储或其他通常会导致服务器无法发送报警的组件故障。
然而,OOB 管理系统确实与服务器共享机箱、位置和电源。这意味着它仍然只能有限地监控系统中某些类型的常见故障。正如许多事情一样,对于许多企业来说,这可能足够了,但对于其他企业来说则可能不够。
推送和拉取警报
警报系统与我们之间也有两种基本的交互方式,作为被警报的接收方。我们通常想到的是推送警报。也就是说,警报是以吸引我们注意力为目的,在我们没有想到警报时发送给我们的。
通常,推送警报通过电子邮件、短信(SMS)、电话、WhatsApp、Telegram、Signal、RocketChat、Slack、Microsoft Teams、Zoho Cliq、MatterMost 或其他类似的实时通讯渠道发出。有些警报系统拥有自己的应用程序,用户可以将其安装到桌面或智能手机上,这样它们就能快速可靠地推送警报,而无需集成或依赖其他基础设施。你可以想象一个组织运行自己的电子邮件和消息平台,而这些平台又被我们的警报系统监控,并且也成为我们接收警报的路径。即便警报系统本身没有失败,但它可能无法告诉我们发生了故障,因为它监控的系统也是将警报送到我们这里的系统。这就是为什么有时会采取减少失败路径和减少警报传递依赖的做法。
警报系统实际上是一个令人惊讶的复杂系统。如果警报是由人工而非计算机处理的,我们会很快发现呼叫中心有复杂的多分支决策树,指引他们在无法告诉某人有问题时该怎么做。然而,依赖人工时,我们知道在极端紧急情况下,总会有人拿出个人手机,给某人发短信,叫某人打电话或敲门叫醒别人,或者做其他类似的事情。计算机也能做这一切,但它们需要访问这些工具、做出这些决策的算法,以及知道如何联系到人。这说起来容易,做起来难。
为了解决这个特定的问题,许多公司选择在通信路径中加入人工。虽然这是一种昂贵但有效的工具,有时候人类的决策和灵活性会占上风。总是有人值班的人工呼叫中心,代表技术团队和管理人员接收警报,并将联系路径管理到需要接收警报的人,是一个很好的选择。显然,混合选项也是可行的,其中计算机系统直接提醒最终接收者,但始终有人参与验证警报是否已发送、是否收到确认,或执行其他可行操作。
推送警报的替代方案是拉取警报。拉取警报指的是系统在最终用户登录查看时,显示任何已打开或记录的警报状态。这些系统要可靠得多,因为最终用户在查看系统时,能够知道是否存在无法查看警报状态的情况。如果系统出现故障,他们可以立即开始处理问题。如果没有故障,他们就能看到警报,并知道是否需要采取行动。
安静即成功
使用纯粹的推送警报所产生的基本问题是,我们依赖安静来告诉我们一切正常。我们并没有得到确认,表明一切都已检查且目前没有问题,而是依赖于没有被联系到来假设一切没有问题。这是一种危险的做法。
我们都知道那种感觉:醒来后,或长时间开车后,或者在派对上没有积极查看手机,心里大致觉得办公室没联系我,没有人打电话,应该没问题。然后几个小时后你看看手机,发现电池没电了,没信号,或者手机处于静音状态。然后 panic(恐慌)袭来。你插上手机,恢复信号,打开铃声,发现自己错过了一个又一个电话、语音邮件和短信,告诉你发生了大紧急,你离开办公室时更改了一个重要密码却没告诉任何人,系统崩溃了,除了你没人能登录,而你没有回应!
仅仅相信没人能引起我的注意,因此没有问题是行不通的。但一直盯着控制台、不离线也同样不可行。必须找到一个平衡点。显然,仅仅希望自己能被联系到,这是一场灾难的食谱。也许这是一个需要很多年才会发生的灾难,但几乎可以肯定,这种灾难最终会发生。毕竟,出错的变量太多了。
因此,拉取监控和警报系统非常重要,它们既能验证推送警报是否正常工作,也能用来绕过已知的断开问题,或者用于运行一个主动监控站点。
警报系统也在努力定义成功的警报。许多机制,如电子邮件和短信,只会确认消息是否已发送,或者可能已被接收方的基础设施供应商接收,但它们并未表明消息是否已传送到最终用户的设备,或最终用户是否已看到该消息。即使消息从头到尾都传送了,它是否被过滤到垃圾邮件文件夹并隐藏了?除非有人工确认警报,否则我们几乎无法有信心确认警报确实已被看到。
拉取警报系统,通常以仪表板的形式显示,通常我们将其想象为红绿灯系统。通常会以图形方式显示监控的系统或组件,并将被认为健康的系统显示为绿色,将遇到问题但尚未指示故障的系统显示为黄色,而将通过传感器测试失败的系统显示为红色。这不仅使人类能够快速浏览警报的范围,而且还使得系统能够轻松地将大量警报汇总为单个显示。只要显示为绿色,你就知道该组中的所有系统都健康。如果显示为红色,你可以深入查看具体问题所在。在最高层次上,理论上,你甚至可以有一个大的单一指示器,显示为绿色或红色。如果所有系统完全正常则为绿色,若有任何系统失败则为红色。简单来说:是否需要采取行动。如果大部分时间都能保持绿色,这可能正是你需要的,将可靠的监控与低验证开销相结合。
大多数警报系统都会提供仪表板来显示拉取的警报,同时也提供推送通知,以提高响应速度并联系那些没有主动检查警报的人。拉取警报系统通常用于呼叫中心的核心,在这里,值班的工作人员全天候监视拉取的警报,并将推送警报传达给相关方,或跟进确保自动警报的送达。很少有组织将拉取警报开放给许多员工,这可能是一个错误,因为这样会降低压力并提高警报的可靠性。
同样,监控系统与被监控端点之间的互动可以是双向的,也可以是单向的。监控系统可能拥有远程访问端点的能力,并主动请求端点的状态。或者,运行在端点上的代理程序可能主动联系监控服务器,将其状态推送过去。
内部和托管监控
监控和警报在某些方面是两个独立的部分,有些软件和服务仅执行其中之一,也有些同时执行两者。监控组件决定一系列传感器是否检测到我们的工作负载中存在问题。警报组件则基于监控结果,尝试通知相关方。过去,这两个组件总是合并成单一的产品,但近年来,随着越来越多的系统类型需要被监控(不仅仅是 IT 系统),以及警报需求的增加和需要变得更加稳健,某些供应商已开始分别独立构建这两个组件。
目前,监控解决方案有很多种包和风格。你可能很容易决定,使用多个解决方案对你有帮助。选择一个合适的解决方案可能是你监控工作中最困难的部分。监控软件有商业版和免费版,有封闭源代码和开源版本,并且可以在几乎任何平台上运行。
监控是一项功能,通常你会希望将其托管在你的主要基础设施之外,因为你希望它的响应速度较慢且更可靠,并且相比其他工作负载,它与其他系统的独立性更强。你可以在自己的设备上托管,选择第三方云或 VPS 托管的基础设施,或者从服务提供商处购买 SaaS 应用程序。你可以根据组织的需求选择任何合适的方式来处理这个问题。但很少有人希望将监控解决方案与其他工作负载共享同一硬件,更不用说共享同一个数据中心了,否则在你丧失其他系统时,也会失去监控功能。
是否自行运行和维护监控系统,或选择托管产品,通常是由成本和组织内部的政治因素决定的。即使是免费的开源监控解决方案,对于最苛刻的组织也足够强大。你需要判断构建、维护和监控一个监控解决方案的成本是否对你的组织合理,还是直接购买现成的功能更划算。在大多数情况下,这取决于规模。如果你监控的工作负载数量非常大,或者你的监控需求非常独特,可能会受益于内部培养专业知识,并有全职专家专注于这个项目。通常,要让这样的项目在内部保持成本效益,你需要有完全专职的员工,或者有大量专职员工,他们有足够的时间和资源深入学习产品,并妥善维护它们。通常,监控和日志记录会捆绑在一起,无论是作为单一产品,还是由一个人或一个团队负责,因为它们有很大的重叠,而日志记录可以视为监控的一个专业功能。两者可以独立操作,也可以结合使用。通过相同的警报渠道使用它们通常是合理的,因为它们可以共享相同的工作和基础设施。
就像本章中的大多数内容一样,最佳实践的真正难点在于找到我们能提炼出的最佳实践,因为这里的指导非常广泛且模糊。没有“一刀切”的方法。听起来像是作弊,但事实是,真正的最佳实践是根据成本、功能、支持、与生产环境的分离,评估你业务的需求,并确定适合你的监控和警报机制。
RMM 和监控
如果您在内部 IT 工作,可能从未听说过 RMM 这个术语,但如果您曾在服务提供商行业工作过,那么 RMM 就是客户支持中预期使用的核心工具。
RMM(远程监控和管理)是一类工具,专为服务提供商设计,服务提供商几乎总是需要远程工作到客户站点,并能够同时快速监控多个不同的客户系统。这与内部 IT 需求通常大不相同,内部 IT 通常不远程操作,即使是远程,系统也通常是集成的。
很少数非服务提供商仍然依赖 RMM 工具作为监控机制。通常 RMM 工具非常简洁且不灵活,但本质上,它们也是我们在这里讨论的那种监控系统。因此,您当然可以考虑使用购买的或自己运行的 RMM,或者如果您有服务提供商,这可能是您已经支付的服务的一部分。RMM 甚至有免费的开源产品。因此,任何规模的公司都不能说他们没有资源至少进行最基本的监控。
在某些情况下,专为内部 IT 团队设计的传统监控工具如此强大,以至于它们实际上取代了服务提供商中的 RMM。或者,这两者也可以并行使用。
经验法则是,监控越多越好,最好将托管放在外部环境中,确保警报有多个渠道,以便找到通向人工的方式,确保至少可以验证推送是否正常工作的拉取监控,并考虑让监控系统自动为支持团队创建可操作的工单,以便跟踪后续事项。
是否有最佳实践?是的,最佳实践简单而广泛:如果工作负载有一个明确的目的,那么它就应该被监控。监控由于不直接影响生产的运行,所以如果不存在监控,容易被忽视。几乎没有人因为做好监控而获得晋升,也几乎没有人因为缺乏监控而被解雇,但实施适当的监控能有效地将优秀的管理员与普通管理员区分开来。
去设置一些监控吧!
摘要
在这一章中,我们已经讨论了围绕系统本身的一系列关键非系统组件。文档编制、系统测量、数据收集与规划、日志收集与管理,以及最后的监控传感器和基于它们的警报。这些几乎可以视为系统管理领域的软技能。
在我接管的环境中,我们发现文档几乎不存在,测量系统几乎没有人提及,容量规划是一个没人讨论过的过程,监控通常最小且可靠性差,日志收集虽然被理解,但在实际实施中依然是一个空想。然而,一位几乎没有资源的系统管理员,只需要一些时间,就能通过一些免费的开源软件独立解决这些问题,且几乎没有预算限制,如果需要的话,还能将工作负载隐藏在系统中的某个地方。
本章并不是关于如何让你的系统运行得更好,而是关于其他方面。我们如何知道它们运行得更好?我们如何知道它们现在在运行?我们如何知道,如果中了大奖,我们能将工作交接给别人?我们如何自信地说,我们正在做需要做的事情,以最好方式应对恶意攻击?本章的主题让我们思考如何在我们所做的一切中变得更好,而不仅仅是最显眼的部分。
提升你的可见度
我们在 IT 中的工作常常对其他团队的人,甚至是我们汇报的管理层来说是完全不可见的。也许是因为根本没有可以展示的东西。或者可能我们做的事情太难、太复杂,外部的人无法真正理解。又或者我们之所以不可见,是因为我们选择接受这种隐形的状态。
本章中的大多数话题都为我们提供了完美的机会,走出 IT 的地下室或储藏室,走到管理层面前,做一点 IT 团队的自我宣传。从监控仪表板到漂亮的文档,再到容量图表、日志细节展示,几乎总有些东西我们可以打印出来或在大屏幕上展示,展示自己已实施的项目,给人留下深刻印象。
吸引管理层的注意,并展示我们是积极主动的,遵循最佳实践,这正是我们可以为自己赢得组织价值的机会。不要害怕做自我宣传,你应得的。制造一些声音,展示你如何为企业的最大成功做好准备。
去确保本章中提到的所有系统都已在你的环境中实施。刚开始时保持简单,但不要跳过任何系统。
在下一章,我们将进入脚本编写和系统自动化,包括 DevOps,我知道你一直在期待这一部分。
第八章:通过脚本编写和 DevOps 提升自动化以改进管理成熟度
我认为,对于我们大多数系统管理员来说,脚本编写和自动化是我们自然倾向于思考如何改善整体系统的最佳机会。这可能会被视为一种重要的工作方式,自动化毫无疑问非常重要,但它也并不是系统管理的终极目标。可以说,随着我们不断学习脚本编写和自动化,我们将拥有更多的自由时间,集中精力去处理只有人类才能完成的任务,同时也能更深入地理解开发人员的工作,这对于我们 IT 领域的从业者总是非常有帮助的。
系统自动化是一个领域,在这里我们更容易获得炫耀的资本,展示我们每天的任务清单。当我们坐在比喻的系统管理员鸡尾酒酒吧里,向同伴们讲述我们如何编写了一些非常清晰且易于阅读的文档时,我们并不会感到满足。但当我们解释如何编写一个复杂的脚本,将我们每周工作量中需要几小时的任务,转化为计算机调度器自动运行的任务时,我们会获得称赞、关注、彩带、报纸横幅游行、同事们为我们买来一杯杯最爱的饮品,如果非常幸运的话,还有一个打击乐器。
自动化通常是我们大多数人在系统管理中既感到兴奋又感到害怕的领域。与系统管理的其他领域相比,自动化涉及更多的构建模块和需要理解的概念。大部分情况下,系统管理很像上历史课,确实,了解更多历史片段有助于你在学习新内容时拥有更大的背景,但通常你可以单独学习任何特定事件,而不需要全面了解与之相关的所有事件和导致这些事件发生的背景,依然能够从中学到有价值的东西,并且本质上理解它。当你学习罗马历史时,即便你没有先学希腊历史,也不会感到迷失。然而,脚本编写和自动化更像数学课,如果你没有学会加法,那么学会如何求平方根将是完全不可能的。脚本编写是一项累积的技能,要真正发挥作用,你需要学一些基础内容。
我们将首先通过对比未编写脚本的命令行管理与使用图形用户界面(GUI)来作为基础,进一步学习如何进入自动化领域。
在本章中,我们将学习以下内容:
-
图形用户界面与命令行界面:管理最佳实践
-
自动化成熟度
-
基础设施即代码(IaC)
-
文档优先管理(DFA)
-
现代自动化工具
图形用户界面与命令行界面:管理最佳实践
如果你是从 Windows 环境转向 Linux,你可能没有意识到几乎所有操作都应该通过命令行完成,而不是图形用户界面。但实际上,即便在 Windows 上,微软早就明确表示,桌面体验主要是为最终用户设计的,而不是为系统管理员设计的,并且他们推荐在直接操作本地系统时,使用 PowerShell 作为首选管理工具,或者使用通过 API 连接的远程管理工具。微软强烈建议过去几代安装其操作系统的人,在安装操作系统和虚拟机管理程序时完全不使用图形用户界面。
图形用户界面,或者现在我们简称为 GUI,给系统管理员带来了许多问题。
GUI 的第一个问题是膨胀。在安装企业操作系统时,如果有 GUI 可用,它往往占据了系统中一半以上的代码。每增加一行代码,就意味着我们需要存储更多的数据,存储的数据越多,我们就需要备份更多;更多的代码意味着更多的 bug、缺陷或故意的后门要担心;更多的代码需要打补丁和维护,等等。
接下来是性能。GUI(图形用户界面)在运行时需要的计算能力和内存消耗要比非 GUI 系统大得多。GUI 通常需要额外 2GB 或更多的系统内存,这比系统工作负载所需的内存还要多。这听起来可能微不足道,但特别是在多个系统合并到一台硬件上时,这个问题可能会迅速加重。如果我们有二十台虚拟服务器运行在同一物理服务器上,那么在 Linux 环境下,平均工作负载可能仅为 2 到 4GB 的内存。每个系统再增加 2GB 内存,不仅意味着接近 50%的增长,而且在所有机器上将增加 40GB 的内存。
系统整合与压缩系统的时代
在 1990 年代和 2000 年代,虚拟化普及之前,我们处于一个服务器性能快速增长的时代,但每台系统只能运行一个操作系统,无论该系统的工作负载有多小。随着系统性能的增强,远远超过了软件使用资源的速度,系统膨胀的趋势越来越强烈,因为至少在硬件方面,膨胀并不那么重要。
CPU 和内存资源通常是以离散块的形式提供的,要拥有足够的资源,我们通常需要购买更多。过去,系统很少会接近其极限运行,因为那个时候扩展系统非常困难。因此,系统通常设计得有很多备用资源,以便留有大幅度的误差空间,当然也为将来的增长留有余地。由于这些原因,在服务器上运行 GUI 几乎是微不足道的。
自那时以来,许多因素发生了变化。我们或许可以写一本书,专门讨论为何在使用命令行数十年后,行业短暂地从命令行转向图形用户界面(GUI),尤其是从 1990 年代中期到 2000 年代初,GUI 似乎一度成为服务器管理的主流方式,直到 2005 年左右又重新回到命令行。忽略社会趋势推动的变化,我们在这里关注的是容量问题。
一旦虚拟化成为主流,尤其是随着云计算开始成为一个重大趋势,操作系统的空闲资源几乎在一夜之间变得不再常见。这看起来似乎与直觉相反,因为虚拟化本身为我们提供了更多的灵活性和计算能力。但它也赋予了我们非常有效地缩减规模的能力,这是我们之前所没有的。通过虚拟化,我们很少会处于拥有大量过剩系统资源的情况,特别是那些可以预测的过剩资源,因此保持每个虚拟机尽可能精简就显得尤为重要,这意味着不运行一个庞大且大多无用的 GUI 进程。仍然无法将工作负载合并到单一服务器的有效下限的小型企业是这一规则的例外,它们仍然有足够的开销来实现 GUI,除非它们是云计算的良好候选者。
在传统的企业环境中,多个服务器是常见的,虚拟化的一个主要优势是整合,避免安装 GUI 意味着可以在一台物理服务器上安装 50 或 60 个工作负载,而不是在相同硬件上安装 30 或 40 个。这相当于减少了购买服务器的需求,从而节省了成本,不仅降低了采购成本,还减少了电力消耗、制冷费用、数据中心房地产费用、软件许可费用,甚至 IT 人员成本。
如果我们以公共云计算为例,我们可以更容易地看到没有 GUI 的优势。小型工作负载,比如邮件服务器、Web 服务器、代理服务器、电话交换机等,每月运行成本可能仅为 5 到 10 美元。如果加上 GUI,云托管虚拟机的成本可能轻松翻倍,从 5 美元涨到 10 美元,或从 10 美元涨到 20 美元等等,因为 GUI 需要更多的 CPU、存储,最重要的是更多的内存。很容易看出,从每月 10 美元到 20 美元的工作负载成本上涨会迅速积累。由于大多数基于云的工作负载都非常小,给每个工作负载添加 GUI 可能会对容量产生巨大的影响,甚至可能使公司的基础设施计算成本翻倍!
GUI 不适用的程度如此之大,以至于许多供应商传统上甚至没有为云空间提供连接 GUI 的机制。亚马逊以其不允许在标准云实例上使用 GUI 而闻名,这实际上迫使组织学习命令行,甚至是更先进的管理技术,而不需要登录。但几乎所有云用户都会选择通过如 SSH 之类的技术进行远程登录。云计算比任何其他方式都更能证明 GUI 的风险和成本。
在虚拟化和云计算普及之前,系统管理员,尤其是那些在 Windows 环境中的管理员,会争辩说 GUI 根本不会增加太多开销,如果它们能让某人的工作变得更轻松,那它们就是值得的。这个神话已经被揭穿,今天没有人能诚实地再做这种声明。GUI 在任何广泛意义上都是不合逻辑的。
对于管理层来说,命令行管理的最大卖点通常是关于安全性的。GUI 为恶意攻击者提供了更大的攻击面,增加了突破系统的可能性。仅仅是多出的那些代码,就让潜在攻击者的工作变得更加容易。而且,当然,GUI 的功能本身就需要更多的访问手段,这自然形成了非常诱人的攻击面。更多的代码行、更多的访问方式、更多的管理路径、更低的性能等,都共同增加了整体的安全风险。综合来看,虽然这可能不是非常严重,但风险的增加是真实的,也是可以衡量的,或者至少可以估算的。
命令行管理成为事实上的标准的最终主要原因是效率。是的,正是许多人选择保持图形用户界面(GUI)的理由。现实是,系统管理不是一项轻松的任务,也不是你可以轻松地四处摸索并猜测应该使用什么设置的工作。要做好这项工作,甚至做到安全,你必须对大量的项目有相当扎实的理解,从操作细节到一般的计算和网络知识。
管理中的 GUI 传统上被宣传为一种工具,旨在帮助那些不习惯环境的人能够更快地高效工作,减少培训和知识要求。如果你谈论的是清洁工,这个概念是很不错的。在系统管理中,我们最不希望看到的就是没有深厚知识和经验的人能够表现得像是他们知道自己在做什么。这在多个层面上都是危险的。遗憾的是,GUI 实际上让许多组织更难评估哪些候选人至少符合技术职位的基本资格。
图形用户界面(GUI)不仅存在着未经授权的人员可能会随意操作的风险,对于那些知道自己在做什么的人来说,命令行的速度要快得多。它在执行简单任务、执行大多数复杂任务时更快,而且更容易编写脚本或自动化。命令行管理与脚本编写如此契合,以至于人们常常分不清两者的区别。如果你真正对比任务,你会发现命令行工作完成相同任务所需的时间通常不到使用 GUI 的百分之十!
命令行不仅对系统更高效,它还使多系统管理变得更加容易,因为命令可以在不同的系统间复制,这些是 GUI 操作所无法做到的。命令行管理还可以轻松录制、归档、搜索等等。虽然在 GUI 中做同样的事也是可能的,但需要长时间的视频录制,这会导致大量存储需求,而且没有简单的方法来解析或转化为文档等。
在现代时代,我们开始面临需要远程执行大部分或所有系统管理任务的问题。这无意中恰好迎合了命令行的优势。命令行需要传输的数据量和对网络延迟的敏感度远小于 GUI。远程 GUI 会话通常会消耗显著的网络流量。远程 GUI 会话是视频流,通常具有相当高的分辨率。在某些情况下,即使是一个用户也能引发网络问题,尤其是当服务器位于网络连接较差的地区时。远程命令行管理的标准方法是 SSH。
即使通过古老的拨号上网连接,SSH 远程会话也能正常工作。即使是最慢的现代互联网服务,也足以处理数十甚至数百个同时在线的 SSH 用户。这是一般远程 GUI 会话做不到的。命令行在全球另一端通过微弱的网络连接几乎同样有效,而 GUI 远程管理则容易受到网络波动、限制或距离的明显影响。
命令行将持续存在,但理解其存在的真正原因非常重要。我们容易忽视它远不止依赖于一两个小因素。实际上,有很多充分的理由说明为什么在可能的情况下你应该使用命令行。来回切换并不利于提高这两种方法的效率。从个人角度来看,理应尽可能避免使用 GUI,以便专注于学习命令行技能。持续使用命令行是提高效率的必要条件。
现在我们必须承认,Linux 有许多不同的命令行选项。我们可以使用BASH、Fish、zsh、tcsh、PowerShell 等。正如我们所知道的,Linux 是关于选项和灵活性的。这是一个“少即是多”的情况。有些 Shell 非常好用且有用,但我们必须记住,我们是系统管理员,我们需要确保对在紧急情况下可能接触到的工具非常熟悉。在 Shell 之间切换并不特别难,特别是在 Linux 环境下,但我们仍然应该警惕花时间学习像Fish或zsh这样的 Shell 中的便捷键、自动补全和其他特性,因为我们可能在下一个工作中无法使用这些技能,这始终是一个需要考虑的因素。而且,如果在紧急情况下你被叫去处理一个你之前没有机会设置的系统,你可能唯一的选择就是 BASH。对我来说,这意味着 BASH 是我唯一想学习的工具。
就是这样。所有的逻辑和推理都在这里,这样你就可以回到管理层,解释为什么你需要从命令行工作,为什么你需要那些能从命令行工作的员工,为什么你的系统应该很少安装任何 GUI 环境。在下一节中,我们将讨论系统自动化的成熟度等级。
自动化成熟度
虽然没有正式的系统来衡量自动化成熟度,但我们可以讨论一些自动化成熟度的基本概念。这里的观点是,组织在自动化程度上大致处于一个连续体中,从没有自动化到完全自动化,大多数组织处于中间位置,但更可能趋向于没有自动化,而不是完全自动化。
不是每个组织都需要,甚至应该,完全实现自动化。但一般来说,当自动化实施成本足够低时,更多的自动化是更好的。自动化并不是免费的,实际上,组织可能会发现,投入自动化一个流程的成本要高于手动执行这个任务的成本,尤其是在系统的生命周期内。我们不希望仅仅为了自动化而盲目自动化。
然而,通常情况下,我们发现组织几乎在所有情况下都会跳过自动化,而选择使用人工劳动,承受所有成本和风险。这是一种自然倾向,因为在当下,任何任务如果手动做都会更简单。如果我们不着眼未来并进行投资,我们根本就不会去自动化,而这也是许多公司看待 IT 需求的方式。如果一个任务手动完成需要一小时,自动化需要三小时,那就相当于三个任务的时间,忽略这个事实是很难证明合理的,因为同样的任务每个月都会发生,四个月后,自动化不仅会减少工作量,而且自动化还能让任务更可靠和一致。
几乎任何组织都将从比今天更多的自动化中受益。没有必要把自动化看作是非做不可的全有或全无的选择。可以做的就自动化,做不了的就跳过。要务实。首先做最容易实现的部分。你自动化的越多,未来你就能有更多的时间去自动化其他事情。随着实践的积累,你的自动化技能也会提升,使得每一次新的自动化都比上一次更容易。自动化正是一个典型的例子,第一次做起来确实很难,但随着时间的推移,它会变得越来越容易,直到它成为处理事情的显而易见的方法,并且变成第二天性。
自动化的成熟度并不完全是一个直接的连续体,每一步都比上一步更加成熟。例如,如果我们看看调度任务和脚本任务,这两者可以独立于对方执行。每个任务单独完成都有其用处。我们可以编写复杂的操作脚本并手动运行它们,或者可以调度简单的独立命令来触发事情的发生,无需人工干预。然后,我们可以将两者结合起来,自动启动执行多项任务的复杂脚本。我们首先考虑哪个,第二考虑哪个其实是随意的。
本地与远程自动化
如果这不够明显的话,我们有两个选择:要么在本地实现自动化,通过调度任务或触发任务在目标服务器上运行,要么我们可以从外部来源推动自动化,从而实现某种形式的自动化集中化。还有一种混合方法,本地调度器或代理向中央服务器请求自动化信息,虽然从技术上讲仍然是本地的,只不过是有一个集中存储来模拟控制。
常常被忽视的是本地自动化的优势,即即使远程系统不可用,甚至本地系统完全失去网络连接,本地任务仍然能够运行。我最喜欢保留为本地自动化的任务之一就是系统重启。虽然将重启集中管理会更方便,且我见过一些组织选择这么做,但我非常欣赏有一个本地的、强制性的重启任务,它每周至少会执行一次,有时甚至是每天。这让我非常安心,即使服务器出现完全崩溃的情况,只要它以任何形式仍能运行,最终重启过程都会尝试重新启动机器,并希望能够让它重新上线。这是一个非常小众的需求,可能对你来说永远不重要,但我见过有些系统即使远程管理无法访问,仍能继续提供工作负载,而一个自动化、本地调度的重启任务将它们重新带回线上,并使其再次可访问。
一种越来越流行的中庸之道是拥有一个中央控制库,包含所有所需的自动化内容,然后由终端的代理拉取进行自动化。这些库既包含自动化本身,如脚本,也包含调度信息或触发器。然后,信息通过本地脚本得以实现,即使远程库出现故障或不可用,本地脚本仍能独立运行。通过这种方式,你真正面临的风险只是无法更新调度任务列表、对它们或调度进行更改。只要不需要发布新的自动化更新,就不必担心库会离线。
命令行
这不仅仅是一个合法的成熟度级别,更像是一个基本的起点,因此我们可以把它看作是零级,指的是进入命令行并使用一个适当的 Shell 环境进行交互式操作(即:非自动化)。正如我们刚刚讨论的,处于命令行并学习命令行语法和工具是所有后续自动化构建的基础。理解如何在命令行上执行任务、如何操作文本文件、如何过滤日志以及其他常见的命令行任务,会迅速发展成显而易见的自动化能力。
定时任务
开始自动化的最佳且最简单的地方就是任务调度。这听起来可能是最简单、最显而易见的一步,但令人惊讶的是,许多组织甚至没有做到这一点。Linux 长期以来一直是可靠且易于管理的本地调度的堡垒,cron不仅内建于 Linux 中,几乎所有的 UNIX 系统都可以使用它,已经有近半个世纪历史(自 1975 年发布以来)。Cron 快速高效、无处不在且广为人知。任何有经验的 UNIX 管理员都应该能够在需要时至少调度一个基本任务。Cron 甚至能处理启动时的任务。
各种简单任务都可以通过 cron 执行。在大多数环境中,常见的任务可能包括系统更新、数据收集、重启、文件清理、系统复制和备份。你当然可以安排任何任务,但这些对于第一次进行自动化的用户来说,都是一些非常适合的建议,特别是对于那些显然是周期性系统需求的任务。
另一个常见的简单计划任务领域是通过像 git 这样的代码库进行代码更新。当我们拉取新代码时,代码更新及随后的数据库迁移都可以轻松地安排定时执行。
脚本编写
当我们谈到自动化时,每个人总是立刻想到脚本编写。归根结底,自动化中几乎所有的内容都或直接,或在幕后以某种方式是脚本编写。脚本编写提供了动力,当我们想要超越最简单的任务或只是调用别人写的脚本时,脚本编写就显得至关重要。
我们不可能在这里教授脚本编写本身,因为那是一个完整的主题。脚本编写是 IT 与软件开发领域交集的最接近的地方。将 IT 命令行任务结合起来在哪一点变成了编程呢?从技术上讲,这一切都是编程,但它是以纯粹专注于系统管理任务的极简编程形式出现的。
通常在 Linux 上,我们会使用 BASH shell 编写脚本。BASH 是一种非常简单的语言,设计上主要用于交互式操作作为一个实时 shell,BASH 是我们假定所有 Linux 命令行交互都会通过的方式。BASH 相对强大且功能丰富,几乎可以用它编写任何脚本。至少在开始时,大多数 Linux 管理员会使用他们在命令行环境中已经在用的 BASH shell,并有机地将脚本元素添加进来,从单一命令、一组基本命令串联到逐步进入完整的脚本编写。
任何 shell,如 tcsh、ksh、fish 和 zsh,都允许你进行脚本编写,并且在许多情况下,比 BASH 提供了更多的功能和灵活性。传统的 shell,如 tcsh、ksh 和 BASH,可能非常有限且笨拙,尝试用它们进行高级脚本编写可能会有困难。Apple 在其 macOS UNIX 操作系统上最近转向使用 zsh,以便与其他 UNIX 系统相比进行现代化。通常情况下,Linux 系统默认不会安装更现代、更先进的 shell,尽管它们几乎可以在任何基于 Linux 的操作系统上轻松获得。
你可能在一个始终提供或提供了其他 shell 的环境中工作,或者你可能有机会自己添加它。如果是这样,尤其是在你需要进行跨平台脚本编写时,特别是与 macOS 一起工作时,你可以考虑使用 zsh 而不是 BASH;或者如果你做了大量 Windows 脚本编写,PowerShell 作为 Windows 的本地 shell 也可以在 Linux 上使用。
Linux 上的 PowerShell
你可能遇到的最奇怪的事情之一,就是在 Linux 上运行微软的 PowerShell。很多人感到困惑,认为它根本无法运行。实际上,PowerShell 在 Linux 上运行得很好。PowerShell 在 Linux 上的问题在于,Windows 上的 PowerShell 用户实际上几乎没有时间学习 PowerShell,而是把大部分时间用来学习各种 CommandLet 或小程序,这些程序可以通过 PowerShell 调用,并与其他小程序轻松结合,赋予系统强大的功能。
在 Linux 上,当然也会发生类似的事情。如果你在 Linux 上进行脚本编写,肯定会使用像 sed、awk、cut、head、tail、grep 等工具。这些工具类似于 CommandLet,但实际上只是日常的系统可执行文件。如果你将 BASH 或 zsh 移植到 Windows 上,你会发现你习惯在 Linux 上使用的工具仍然不可用。那是因为它们是你从 BASH 调用的小程序,而不是 BASH 本身的一部分。BASH 只是编程语言。
反过来也一样。如果你在 Linux 上运行 PowerShell,你仍然需要使用 sed、awk、cut、grep、head、tail 等工具。改变的是语言,而不是操作系统的工具和组件。
所以,尽管学习一种脚本语言并尝试在不同操作系统之间反复使用它是有价值的,但其价值并不像人们想象的那样大。你可能会花费更多时间去解决集成怪癖、误解和糟糕的文档,而这些时间远远超过了语言学习效率所能带来的回报。如果你尝试在 Linux 上使用 PowerShell,书籍、在线指南、示例代码等都不会对你有帮助。它们会假设你正在尝试用 Windows 工具来做 Windows 任务。PowerShell 从本质上来说,是一个真正现代的 Shell,利用操作系统对象来完成繁重的工作。而 BASH 则专注于文本处理和操作,因为 Linux 传统上是建立在文本文件上的,需要一个能够轻松处理这些文件的脚本引擎。
在 Linux 上使用如此陌生的 PowerShell 是一个很好的工具,可以揭示我们通常只视为 命令行 或 Shell 的不同组件的本质。如果我们在 Linux 上使用 zsh,几乎所有 BASH 内建的功能都可以在 zsh 中找到,并且它们都惯常使用相同的操作系统工具。而 PowerShell 几乎没有任何内建的命令可以复制,也没有共享的惯例,这使得它非常明显地区分了来自 Shell 的部分和操作系统中属于 Shell 之外的部分。
然而,一般来说,最推荐在你所在环境中得到良好支持的语言中进行所有脚本编写。就像我们在其他系统管理领域所说的那样,使用那些无处不在、被广泛理解并且适合该环境的工具非常重要。对于大多数人来说,这意味着仅使用 BASH。BASH 是唯一一个在你遇到的每个 Linux 系统上都可以绝对使用的脚本环境。其他的 shell 或脚本语言可能很常见,但没有哪个能像 BASH 那样普及。
当 BASH 对于更高级的脚本编写显得过于局限时,转向另一种 shell(例如zsh)并不常见,因为其他 shell 非常罕见,且通常缺乏在放弃 BASH 后你可能需要的强大功能。传统上,作为 BASH 替代品的高级脚本编写语言通常是非 shell 脚本语言,如Python、Perl、Tcl、PHP和Ruby。Ruby 一直未能获得太多青睐。PHP 虽然在某些任务中非常常见,但作为通用的系统自动化语言却比较少见。Perl 和 Tcl 的受欢迎程度急剧下降,但曾几何时,Perl 是系统自动化语言中的领头羊。这使得 Python 成为了高级脚本需求的一个非常明确的领先者。
Python 总体上有许多优势。它的运行速度相当快。它几乎可以在任何平台或操作系统上使用(包括所有 Linux、其他 UNIX、macOS 和 Windows)。它相当容易学习(通常被用作新程序员的第一门语言)。它非常常见,很多 Linux 上的应用和工具都依赖于 Python,因此即使它不是作为标准安装,也经常会发现它已经预装好了。由于它在这些任务中如此常用,Python 在这方面的文档逐渐增多,围绕它编写的其他工具也应运而生,使得它越来越适合承担这一角色。
目前,几乎所有 Linux 系统的脚本编写都尽可能使用 BASH,而在需要更多功能或灵活性时则使用 Python。其他语言基本上都是小众应用。这意味着 BASH 和 Python 也有额外的理由让我们在选择自己的脚本语言时应该重点考虑它们:标准化。
系统自动化不同于一般的编程。广泛的编程开发人员花费多年时间学习多种语言、语言家族、构造,并且将所有时间都投入到编程环境中。在不同语言之间切换、学习新语言、适应语言变化等,都是开发者日常生活的一部分,而在语言之间切换的开销非常小。对于系统管理员来说,这有些不同。从理论上讲,我们花在学习编程上的时间非常少,而且很少接触到真正的语言多样性。因此,对于管理员来说,拥有一两种常用的语言是非常重要的,这样有助于我们在未来找到资源、示例、同行评审等,支持我们的自动化工作。当然,这些语言并不是唯一可接受的选择,但它们相较于大多数其他选项,确实有着相当大的优势。
当然,脚本编写是一个非常广泛的话题,脚本的内容从几行简单的按顺序执行的命令到包含复杂代码的大型程序都有。提升脚本编写技能是一个值得专门投入大量时间的话题。好的脚本通常会包括自己的日志机制、错误检测、函数、可重用组件等。你可以在系统自动化脚本上不断地投资更多的编程技能。
开发人员的脚本编写工具
无论你是在编写一个非常简单的脚本,还是在为你的组织中代代相传的自动化杰作而努力,你都值得迈出额外的一步,学习一些软件开发中使用的工具,以帮助脚本编写过程。
最简单的一方是像集成开发环境(IDE)这样的工具,它们能让编写代码变得更快、更容易,并帮助你避免错误。开发人员几乎总是使用这些工具,但系统管理员往往会忽视它们,因为他们认为自己编写脚本的时间很少,学习另一个工具可能不值得。而也许确实不值得,但你学会的工具越多,你就越可能使用它们,进而编写更多的脚本。一款好的 IDE 可以是免费的并且非常易于使用,因此它是一个很好的起点,你可以将它整合到你的工作流程中,而不需要花费太多时间或金钱,下载并安装一个也不过几分钟的事。
另一个开发人员几乎普遍使用、而系统管理员很少使用的真正庞大工具集是代码仓库和版本控制工具,如 Git 和 Mercurial。借助这些工具,尤其是将代码托管在这些工具所关联的中央服务器上,我们可以在编写和管理脚本方面实现飞跃。这些工具对于管理我们环境中其他形式的文本数据也非常有用。尤其是 Linux 使用基于文本的配置文件,可以像脚本一样处理,并将其纳入版本控制系统进行管理。这是跨领域技能共享的一个优秀应用。
版本控制无疑是软件开发世界中最必须掌握的技术,对于我们自己的脚本编写至关重要。版本控制让我们可以跟踪随时间变化的代码,测试代码并轻松回滚,它允许多个团队成员共同管理同一份脚本,按用户跟踪变更,支持代码审查和审核,简化数据保护和部署等等。如果你只采用一种开发技术,那就选这个。刚开始时可能会觉得有些繁琐,但很快它会变成第二天性,让你做的许多事情变得更加轻松。
开发世界中有许多我们可能会用到的其他工具,如持续集成、自动化部署和代码测试,这些工具根据我们编写的脚本可能会非常有用,但几乎所有这些工具都是小众的,即使在高度自动化的环境中,它们也是完全可选的。了解这些工具可以让你接触到可能对你的工作流程有意义也可能没有意义的选项,同时还能让你深入了解你的潜在开发团队可能的工作方式。
将软件工程作为获取如何更好编写脚本的灵感来源,但不要觉得你必须或者应该采用每一个工具和技术。自动化和产品开发的脚本编写确实有交集,但它们最终是不同的活动。
编写脚本并没有什么秘密,唯一的秘诀就是不断实践。市面上有许多优秀的书籍和在线资源可供参考。可以从最简单的项目开始,寻找过去可能手动完成的工作中可以通过脚本实现的机会。系统任务,如部署或系统设置检查清单,可能是一个很好的起点,或者编写用于部署一组标准工具的脚本,或许是编写一个收集多台机器特定数据的脚本。我经常发现自己在编写数据处理脚本。一旦你开始寻找,你可能会发现许多新的脚本技能可以派上用场的地方。
使用非计划脚本的最佳起点之一是基本的构建和安装任务。使用脚本来执行初始系统设置和配置,包括安装软件包、添加用户、下载文件、设置监控等等。这些任务通常在相对较小的努力下提供了大量的收益,并且可以作为一种文档形式,列出系统所需的任何软件包和配置更改。以这种方式完成的文档具有很高的权威性,因为它真正记录了实际使用的过程,而不是预期或假设的过程。
文档优先
在软件工程领域,有一个概念是编写测试来验证代码。虽然并不完美,但运行测试使得软件出现 bug 的可能性大大降低,因为测试会检查预期的行为并确保其发生。我们仍然可能遇到 bug,这绝非百分之百的保证,但它是一个很好的步骤。在经历了几十年的代码测试后,提出了在编写代码之前编写测试的可行性这一想法,研究发现这样做不仅能够减少 bug,还能提高代码编写的效率,仅仅因为编写测试促使我们以更好的方式思考问题解决方法。测试优先编程被认为是软件开发方法的一次突破。
这个概念可以在系统管理领域中以某种方式延续下来,我称之为文档优先工程。在这个概念中,我们首先编写文档,然后使用这些文档来构建系统。如果没有文档,我们就不构建它。就像测试驱动编程一样,这种方法迫使我们提前思考系统应该如何工作,这给了我们另一个机会,确保我们正在做的事情是经过良好规划和合理的。而且它还让我们有机会验证我们的文档是否完整且合理。当我们事后编写文档时,往往更容易制作出无法真正执行任务的文档。
在某些情况下,比如自动化程度较低的情况,这可能意味着仅仅在 Wiki 或文字处理软件中记录我们能记录的内容,并在部署系统时依赖这些文档。如果我们有更高的自动化水平,那么我们实际上可以将代码作为文档来编写,这些代码会为我们构建系统。由于代码本身就充当了文档,它不仅仅是文档优先,而是文档实际上完成了工作,这完全可以保证文档的完整性和准确性!
自动化的内在特性是鼓励更好的文档编制,并将文档从事后记录转向事前记录,进一步转变为将文档本身作为构建机制。这也意味着我们有可能看到效率上的双重提升,因为我们希望用于文档和脚本的版本控制、备份以及其他机制可以自动应用于两者。
使用高级工具进行脚本编写在某种程度上也可以被视为自动化成熟度的更高阶段。
脚本与任务调度的结合
希望显而易见的下一步是将任务调度和我们新获得的脚本知识结合起来,以获得更强大的功能。让复杂的任务能够自动运行,而无需任何人工干预。
以这种方式自动化的常见任务通常包括软件更新。拥有一个脚本,能够查找最新的更新,下载它们,准备环境,并在预定时间自动部署,十分方便。几乎任何应当一起执行的复杂任务都可以以这种方式进行调度,无论是每分钟一次,还是每月的第三个星期二。脚本也非常适用于处理条件性情形,在这些情形下,只有在特定条件下才执行某些操作,例如,只有当存储超过某个水平,或者某些特定人员登录时才执行。
几乎是一个特殊情况,因此我认为非常值得提及的是使用定时脚本来管理备份或复制。
状态管理
我们在系统自动化中经历的最令人惊叹的变化之一是引入了状态机和系统的状态管理。状态是一个难以解释的概念,因为这远离了 IT 和系统管理中的常规思维方式。然而,状态通常被视为系统的未来。
在传统的系统管理和工程中,我们谈论和思考任务:我们如何让系统从 A 点到 B 点。在状态理论中,我们不讨论如何管理系统的方式。相反,我们只关注预期的结果或结果状态。
换个角度思考:我们开始关注结果,而不是关注过程。我们从以过程为导向转向以目标为导向。
这种方法迫使我们真正改变几乎所有我们关于系统的思考方式和认知。它在各个方面都是一个游戏规则的改变,让我们这些人能够更好地专注于我们擅长的领域,同时让计算机在它擅长的领域做得更好。
所有这些魔法都是由所谓的状态机完成的。在系统管理的背景下,状态机是一个代理或代码片段,它接收一份或一系列文档,这些文档规定了系统所期望的状态。状态可以指系统的几乎任何方面,例如已安装的包、当前的补丁级别、配置文件的内容、防火墙中打开的端口以及应当运行的服务列表。
状态机会根据这些描述目标状态的文档,确保(或至少尝试)系统处于期望的状态。如果缺少某个包,它会安装该包。如果某个服务没有运行,它会启动该服务。如果配置文件不正确,它会进行修正。相反,如果某个不该安装的程序出现在系统中,它会被删除。如果某个不该运行的服务被启动,它会被关闭。
状态机通常每隔几分钟或几秒钟运行一次,扫描其状态文件并确定系统应该是什么样子,然后扫描系统以验证其已知的状态与预期的状态是否匹配。如果发现不一致,状态机会采取必要的纠正措施。当然,在背后,这一切都是通过复杂的脚本和系统工具完成的,这些脚本和工具组合在一起提供了强大的能力来强制执行状态。状态机能够采取纠正措施的程度取决于它可以访问的脚本的能力。这并不是无限的,但通常在 Linux 系统上,状态机具有足够的能力来应对现实世界中非攻击场景中的实际需求,并且在缓慢或阻止许多低强度攻击方面仍然非常有效。
从理论上讲,状态机通过保持系统处于我们所期望的几乎恒定的状态来实现这一目标。使用状态机时,我们花时间编写文档,描述我们希望系统具备的特性,然后让状态机本身负责如何使系统按预期方式运行。这包括机器的初始设置,将一个基本的、原始的操作系统安装转变为特定工作负载的功能组件。状态机也可以在虚拟化管理程序和云级别运行,从而使我们不仅能在单个系统内维护标准化的概念方法,还能在提供系统的平台级别保持这一标准。
登录的终结
状态管理的本质是鼓励(如果不是强制的话)彻底取消为了管理目的而登录服务器的概念。然而,在我们考虑消除登录之前,状态管理系统的作用是通过状态来改善传统的远程管理方式。
传统上,远程管理中最大的风险是需要开放端口,并且必须灵活地保持这些端口开放,以便在任何必要的时刻从任意位置进行管理。虽然将端口数量减少到最少,并将其限制为单一的 IP 地址在理论上看起来是一种很好的安全措施,但在实际应用中几乎没有用处。为了让管理员能够在紧急情况下从任何位置快速登录,要么需要暴露太多,要么需要过多的步骤来限制访问。
进入状态管理。通过状态管理,系统可以通过存储在集中式仓库中的状态定义文件指示开启 SSH 服务,开放一个用于 SSH 服务的随机端口,并将其锁定为管理员或管理员组的当前 IP 地址。版本控制系统将轻松追踪变更请求的时间、请求人以及变更的内容。在理论上,机制中还可以包含一个审批步骤。变更记录后,系统将授权指定管理员的访问权限。一旦他们完成操作,或者按照预定计划,状态管理系统将在完成所有文档记录后恢复变更,并完全关闭所有访问通道。增强安全性的潜力是巨大的。
但这仅仅是一个过渡步骤。通过完整的状态管理,我们理论上应该不再需要登录到系统。我们应该能够通过状态系统本身执行任何必要的管理步骤,或者更合适地,这些步骤应该由状态引擎自动执行,以确保保持适当的系统状态。
要完全实现这种无需登录的机制,我们必须将状态管理与上一章中提到的一些概念结合起来,例如远程日志收集和告警系统,这样即使是像容量规划这样的任务,也无需登录到单个系统。对于传统的系统管理员来说,这听起来通常像是亵渎神明,几乎不可能实现,但今天许多公司正是如此运作,并且通过事先做好的工作,这完全是可行的。
对于运行在办公室内物理硬件上的系统来说,这听起来可能像是过度防护,也许确实是。但对于运行在云服务器上的系统来说,这在许多情况下非常实用。对于一个经过充分测试、文档化且正常运行的系统来说,不应需要人工干预。手动管理既难以文档化,又很难重复操作,并且极容易出错。当然,人工干预可以作为最后的手段,但今天完全可以通过完全依赖重新部署来避免人工干预。
自动化成熟度模型为我们提供了一种从当前状态到希望达到的状态的路线图。当然,并不是每个组织都必须达到管理所有需求的状态管理水平。并不是每个环境都需要脚本化!大多数组织将继续受益于我们所处的任何成熟度水平。
我们将为成熟度模型的最终级别留出独立的部分。将我们所学到的内容应用到实际中,我们最终会得到…
基础设施即代码
从我们在这里讨论的概念出发,从另一个角度看,我们发现了基础设施即代码的概念。意味着我们可以编写代码或配置文件来表示我们的基础设施的整体。这是强大且解放性的。
很容易将基础设施即代码的概念与状态机的概念混淆,因为它们在许多情况下会有相当广泛的重叠。然而,它们之间存在着关键的区别。
基础设施即代码可以与状态机并行使用,但状态机不允许命令式的系统定义。基础设施即代码可以用来定义状态,也就是基础设施即代码的声明性方法,或者通过命令式的方法定义操作,而不是最终状态,使其更像传统的系统管理,关注的是手段而非结果,即关注 如何 而非目标。
平台与系统
基础设施既指我们运行的系统,即操作系统容器,也指承载这些系统运行的平台,即虚拟机管理程序和物理机器。对于我们在本节讨论的内容,特别是像基础设施即代码这样的概念,其适用性是针对基础设施的两个方面的。
我们在系统级别应用的工具和技术可以与我们的平台级别一起工作,反之亦然。这意味着我们不仅可以依赖这些优秀的工具和技术来配置操作系统和应用程序,还可以利用它们来实际部署和构建虚拟机容器(包括完整虚拟化和容器化),无论是在云环境还是传统的非云环境中。
在这两个领域应用相同或相似的工具,意味着通过概念整合获得更大的整体能力,并呈现我们基础设施的更完整的图景。现代计算的一个关键好处是,从单纯将操作系统视为工作负载构建块,到将虚拟机管理程序也视为直接参与工作负载的角色。虚拟机管理程序不仅仅为操作系统提供一个容纳工作负载的空间,而是作为一个了解工作负载的工具,能够分配资源并作为工作负载组件的一部分。
例如,虚拟机监控程序或甚至虚拟机监控集群级别的管理将意识到它正在为应用服务器、代理、处理节点、存储、备份、数据库等提供工作负载容器。由于平台级别对工作负载有感知,它可以做出智能的资源配置决策,不仅知道需要什么样的资源,还知道将工作负载部署到哪些节点。如果我们有一个三节点的虚拟机监控集群并且我们配置了三个应用虚拟机,那么配置应该知道将这些虚拟机分布在不同节点上,每个节点一个虚拟机,以增加冗余;而且它还应该知道,对应的数据库也应该这样配置,确保数据库与应用服务器分布在相同节点上,并且配置这些应用服务器连接本地数据库实例,而不是随机的非本地数据库实例。从应用程序通过操作系统一直到平台都具备工作负载感知,这意味着更好的性能、更少的工作量和更强的数据保护。
通常,当我们进入基础设施即代码时,我们自然会开始合并系统和平台管理团队,因为将它们视为更大、更整体的基础设施愿景的两个部分是合乎逻辑的。
命令式基础设施即代码设计为我们带来了许多与状态机相似的前期好处,但初期设置工作量较小,而长期维护则需要更多的工作。因此,当基础设施即代码首次推出时,命令式系统被认为是常见的,但随着市场的发展,声明式(有状态)工具集和预构建的命令式结构的出现,转向声明式基础设施即代码是不可避免的。
当然,在底层,所有这样的系统最终都会是命令式的。任何声明式系统最终都会使用预定义的命令式步骤来达到所需的状态。因此,为了拥有一个供我们使用的声明式系统,我们或其他人必须编写命令式脚本和工具,这些脚本和工具可以将我们从多个不同的起点引导到同一个终点。即便设计了基础状态引擎,构建这些组件仍然需要大量的时间和测试。
这些脚本必须为每个任务存在。如果你想定义一个文件必须存在,那么我们需要在后台有工具来检查文件是否存在、判断如果文件不存在该怎么做、如何查找文件、如何复制文件、将文件放在哪里、文件复制失败时该怎么处理等等。这可能是最简单的使用案例,你可以轻松地想象,处理任何其他任务时它将变得多么复杂。即使是一个简单的声明式系统,也将由无数管理员可能永远不会知道的命令式脚本构成。或者它可能是管理员为了特定的需求而为特定系统构建的。这个概念是灵活的,但也很复杂。
理论上,我们可以拥有声明式的状态管理,而不需要像基础设施即代码那样深入。尽管这听起来有些奇怪,但实际上,那些刚开始使用状态系统的人常常几乎是手动进行的,尝试以接近命令式的方式发出有状态的指令,以通知系统所需的状态,而在此之前并没有将所有方面记录在代码中。
这些技术的工具通常会被部署,甚至被使用,但往往是非常不完整的。这可能是由于挫败感、缺乏规划、公司内部政治等等原因。因为完全在这种模式下工作非常密集,并且需要前期的充分规划,所以很难获得足够的时间和来自上层的支持来进行完整的实施。因此,我们经常看到这些工具被用来推出基本的、众所周知的功能,使用预构建的第三方脚本,但复杂的、通常是组织特有的配置仍然以传统方式进行。急于部署系统的压力通常会驱动这种行为。
这引出了关于基础设施即代码的真正关键最佳实践。最重要的是获得广泛的组织支持,并在工作负载投入生产之前,投资于适当的文档编写和代码的完整性。
就像我们在软件工程领域讨论的任何代码一样,我们的基础设施即代码也需要在使用之前进行测试。然而,测试系统管理代码通常比其他类型的应用程序更为简单。为新工作负载创建代码,然后从零开始部署该工作负载是相当直接的,直到结果完美为止,可以一遍又一遍地尝试。然后可以测试系统修改、故障和其他潜在场景,以确保系统能够在潜在的实际问题下良好响应。
这种测试的一个重要好处是,我们代码的功能就是从大致“什么都没有”的状态中创建基础设施。所以我们所要做的就是从一张白纸开始,如果一切正常工作,我们的基础设施就会自我创建,我们可以从那里进行测试。
即使我们无法像希望的那样创建一个完全自我创建、自我修复、自我配置和销毁的基础设施,我们至少可以使用这些工具和技术走一部分的路。从简单地从零开始构建基础设施,并不维护或退役它,这是一个很好的第一步。
基础设施即代码作为灾难恢复
我们在其他地方已经提到过这个概念,并将在下一章关于备份和灾难恢复中深入探讨,但它非常重要,以至于我们在讨论现代系统中灾难恢复的组成部分时,必须始终提及它。我们谈论基础设施即代码时,实际上是在讨论自动化创建以前不存在的系统。
这正是灾难恢复场景中所需要的。当我们的系统消失时,我们需要将其恢复。将我们的系统、它们的标准文件、它们的配置等,作为代码存储在一个能够轻松恢复的地方,或者更好的是,在正常的灾难期间完全不会丢失,这意味着我们已经准备好在任何我们想要的地方,以极短的时间建立一个新的系统。
因为这些类型的构建系统大部分时间用于为测试和生产部署构建工作负载,它们通常具有快速、高效、易用、易懂并且经过大量测试的优点。以这种方式构建的系统在测试中构建时与生产中的构建完全相同,在紧急灾难恢复时也是如此。我们在前期就做好了所有艰苦的工作,确保系统快速且可重复构建,这样当发生可怕的事情时,我们就不需要偏离既定的流程。
传统的灾后系统恢复需要通过一个独特的过程来构建系统,而这个过程与最初构建系统的过程完全不同。这种做法容易出错,原因有很多。这是一个很少经过良好测试或文档化的过程。通常是在没有充分规划、且承受很大压力的情况下进行的。这是经历这种情况的最糟糕时机,因为此时是对一切做到完美要求最大的时刻。
通过创建一个每次第一次、第二次、每次几乎瞬间并完全相同地自动构建自己的系统来避免这些问题,的确是一件大事。如果有什么能够证明自动化和基础设施即代码的好处,那就是这个。拥有系统能够快速且正确地恢复的信心是今天大多数公司所没有的。担心备份无法恢复,缺少正确配置工作负载的系统启动知识,许可证或系统细节没有文档记录,或是所需的软件包不容易获得,都是非常严重的问题。我们有一种现代的方法,能够让这些问题迎刃而解,而不是忽视它们并希望问题自行解决。
将我们的组织带到真正实现基础设施即代码的水平是一个巨大的步伐,但这就是未来。做到这一点的公司拥有更快的构建速度、更快速的灾难恢复、更好的安全性、更强的灵活性、更快的扩展速度,所有这些意味着它们有更大的机会赚取更多的利润。归根结底,作为系统管理员,我们的唯一工作就是以一种方式来做我们的工作,借此通过我们的努力,无论这种努力多么间接和难以衡量,都能提高组织的盈利能力。
现在我们知道了这些技术是什么,是时候谈谈那些实际存在的、已经准备好进行测试的工具,它们使得状态机和基础设施即代码成为可能。
现代自动化工具
所有这些强大的功能主要来自于过去十五到二十年内引入系统管理领域的现代工具。Linux 世界非常幸运,从一开始就处于这一运动的前沿。这自然源于 Linux 社区倾向于在创新上蓬勃发展并专注于创新,也因为基于命令行接口和简单文本文件进行配置和软件仓库的系统本质,使得自动化变得更加简单。Linux 的设计可能并非有意鼓励自动化,但几乎每一个主要方面,无论是系统实现还是生态系统的行为,都使它具备了理想的组合因素,几乎总是成为新的自动化工具和策略的领导者。
配置管理系统
新的工具不断涌现,技术也会随着时间而变化,因此在此列出一个权威的工具清单并不可能,但有一些重要工具已经成功地在行业中树立了自己的名声,值得作为调查适合你环境的工具的起点。目前,最流行的基础设施自动化工具(基础设施即代码)包括Chef、Puppet、SaltStack、CFEngine、Ansible和Terraform。其中最古老的工具CFEngine,早在 Linux 内核发布不到两年时就首次推出!
所有这些工具,通常被称为配置管理系统,共享一种共同的方式,即允许你编写代码和配置文件来定义你的基础设施环境,并且它们基于这些代码管理基础设施的自动化。它们中的大多数提供多种功能行为,比如可以选择以命令式或声明式的方式工作。大多数还提供从被管理系统拉取配置或从中央管理位置推送配置的选项。因此,你可以获得各种功能选项以及多种产品选项。
这些产品之间的最大区别实际上是用于记录你基础设施的编码风格,以及产品的成本、支持或授权方式。大多数这一领域的产品最初都是开放源代码,或者后来转为开放源代码。开放源代码是有道理的,因为这个领域发展得非常迅速,而管理工具也自然倾向于开源,因为它们主要是由最终用户或来自开源社区的人开发的,并且主要用于技术圈子里。封闭源代码的产品则更适合面向客户的产品,其中经理而非工程师在选择这些工具。大多数基础设施即代码工具的一个关键优势是它们是免费的、开源的,并且通常包含在 Linux 发行版中,因此工程和管理团队通常可以选择测试并将其部署到生产环境中,而无需管理层的批准,甚至管理层可能并不知道它们正在这样做。由于授权和使用场景,这与部署 OpenSSH 或其他日常系统管理中使用的标准组件没有太大区别。
当然,这里最简单的方法就是简单地了解一些工具,下载并安装一些,看看你喜欢什么。同时使用多个工具并不是一件坏事,大多数概念都可以从一个工具转移到另一个工具,即使脚本编写和文档编制的风格有所不同。许多这些工具都是跨平台的,虽然它们通常以 Linux 作为主要平台进行部署和管理,但其他平台,尤其是 BSD,以及 Windows、macOS 和其他平台,也可能被管理。考虑选择一个能够扩展以满足您组织未来所有需求的平台。如果您是一个异构商店,您可能希望投资您的技术知识到一个平台上,该平台可以跨领域管理所有内容,而不仅仅是管理 Linux,即使 Linux 是您的起点。
桌面就是服务器
把桌面视为服务器的一种形式可能会有点令人困惑,但从某种意义上说,它们确实是如此。它们只是一对一终端用户图形用户界面服务器,通常部署在桌面或家庭而不是数据中心。这只是一个微不足道的语义问题,直到我们开始试图理解桌面如何或不如何适应我们更大的支持战略。
但是,当我们考虑到桌面实际上只是服务器的一种特殊类别时,很快就会意识到,将它们归为通用管理也是有道理的。当然,例如,如果我们在桌面上使用 Linux 发行版,这一点比在使用 Windows 时更为明显,但事实仍然如此。如果我们可能会支持同时使用相同工具的 Linux 和 Windows 服务器,那么无论部署在哪种操作系统上,为桌面也采用同样的方法并不存在实际障碍。
传统上,但出于我所知的原因,服务器和桌面通常使用完全不同的工具集进行管理。我可以假设为什么会是这样。通常情况下,两个不同的团队提供此管理,并且每个团队都独立选择其自己的工具。服务器在一个世界中发展,而桌面支持在另一个世界中发展。供应商希望销售更多工具,并且迎合傲慢总是使销售变得容易。最有可能的因素是:服务器通常从命令行进行管理,而大多数桌面支持团队希望纯粹从 GUI 操作。
当我们退后一步看待桌面(和其他终端用户设备)就像它们是服务器时,很容易看出,管理、文档化和监控服务器的同样工具同样适用于桌面。没有真正的理由对待它们有所不同。当然,桌面支持团队始终需要能够远程查看,并可能与终端用户的图形桌面进行交互,以直接帮助解决终端用户的问题,但这与管理职责完全不同。
桌面计算机可以,甚至应该,使用与任何其他服务器相同的高级工具和技术进行管理,例如基础设施即代码和状态机。没错,当我们理解它们实际上是服务器时,适用于所有服务器的规则同样适用于桌面计算机。良好的语义使一切更容易理解。
事实上,甚至有充分的理由认为,终端用户设备是应用这些技术的最有价值领域,因为它们最可能需要重建、修改、共享配置文件、经历变化、被攻击或需要在没有与中央服务通信时进行管理。最后这一点尤其重要,因为那些保持现有状态并继续运行的状态机,可以为脱离网络的设备提供安全性和自我修复的特性,并能够独立执行策略。传统方式虽然也可以做到这一点,但实现起来更困难,且实现的可能性较小。
由于基础设施即代码系统的部署方式,这些系统更有可能在桌面或笔记本电脑脱离公司局域网时仍能继续运行,而传统的管理工具通常完全围绕局域网概念构建。由于终端用户设备传统上具有较高频率的在局域网中上下线或根本不连接局域网的情况,因此使用非局域网中心的工具,在终端用户空间通常比在数据中心空间更为重要。
在某种程度上,移动设备管理(MDM)通常被看作是尝试使工具更倾向于基础设施即代码和状态机的尝试,但这些工具呈现得更像传统工具,并通过更传统的渠道销售,专注于终端用户管理。我觉得这些工具之所以成功,是因为它们在很大程度上复制了该领域的技术和常见做法,一旦我们使用这些工具,我们通常会发现,除非我们在组织中缺乏这些能力,否则移动设备管理工具是没有意义的。
当然,任何新系统的许多优势都来自于约定,而非严格定义。基础设施即代码领域的最大约定之一,就是从以局域网为中心的管理转向网络无关的系统管理部署。通常,基础设施即代码系统的工具都会以某种公共形式托管,无论是在云、VPS,还是在机房托管,并且与可能存在的任何局域网隔离开来。
将托管管理基础设施置于局域网(LAN)之外,意味着我们可能会意外或随意建立的任何局域网中心的连接将不再可能,除非我们部署类似 VPN 这样的局域网扩展技术。这一做法自然促使我们远离部署仅在局域网内有效或利用局域网边界作为安全功能的技术。消除局域网边界使我们能够从一个平台透明地管理多个站点、移动用户甚至多个组织,只要这些系统使用互联网。传统系统在许多情况下会崩溃,并且有共同的安全漏洞,既因为它们容易崩溃或在利用上存在漏洞,也因为局域网中心的思维并不是良好的安全做法。
版本控制系统
我们在自动化主题中真正需要解决的另一个工具类别是代码仓库和版本控制系统。它们在技术上是两个独立的东西,但几乎总是密切相关。
从本质上讲,版本控制系统只是跟踪我们已拥有文档所做的更改,以便我们跟踪一些重要数据,例如谁做了更改,何时做了更改,以及在更改之前、当时和之后文档的样子。仅此一项就非常强大,但今天大多数实现此功能的系统还会用于分发代码和版本控制,使其可以被多人在多个地方使用。在能够做到这一点的同时,它也可以用来填充一个中央存储库,该存储库可以作为主存储位置,以便不需要将任何人的终端视为数据保护的关键位置。这个中央位置还可以作为备份和恢复的地方!
版本控制系统影响了许多现代文档系统,我们在早期的文档章节中介绍了两者,但在这个背景下,我们可以看看现实世界中的产品,例如 Google Docs、Microsoft Office Online 和 Zoho Docs,它们都呈现传统的文档文件类型或界面,但都提供文档的版本控制。为了编码和代码管理,这些系统的使用非常笨拙,但如果你只想迅速开始使用你已经部署的工具,它们也能应急。这些系统本质上是在复制传统代码版本控制系统的机制,并将其应用于电子表格和文字处理。
由于这些办公文档类型非常知名,因此几乎可以将它们视为标准(但它们并非如此),并认为代码版本控制系统是这些文档工具的代码特定修改版(事实上并非如此,它们早于文档工具)。这些系统通常(在我知道的每种情况中)处理标准文本文件,因此无论你使用的是像vi或nano这样的简单文本编辑器,还是使用像Atom或MS Visual Studio Code这样提供全面图形化编程环境并具有深度编辑功能的强大工具,都可以使用版本控制系统。一些高级环境实际上会将版本控制直接集成到应用程序中,以便你从一个地方自动化整个过程,让它看起来和感觉上更接近办公风格的工具!
在实际应用中,目前为止,两个版本控制协议已经崭露头角,几乎感觉市场上只剩下两个选择:git和mercurial。实际上,还有许多其他协议,但只有这两个值得一提。你可以自由地研究其他工具和协议,但请确保这两个协议出现在你可能有的任何研究简短名单中。它们都是免费的,功能类似,支持你今天通常期望的所有功能,包括中央仓库、用户机器上的副本、自动化部署、版本元数据等。
除了所使用的协议,今天版本控制系统的强大功能还来源于支持它们的在线仓库服务。这里有更多选择,而且你也可以自己运行本地服务。两大关键参与者是微软的 GitHub 和开源的 GitLab。两者都是托管服务,提供广泛的免费服务,GitLab 还提供免费的软件,可以让你在自己环境中托管(如果这是你的业务或技术需求)。这两项服务及类似的其他服务提供了中央 git 和 Mercurial 仓库位置、备份的集中位置、用于代码操作和管理的简单 Web 图形界面,以及围绕代码自动化的一系列流程、工具和服务。很多功能在系统管理环境中可能是多余的或无用的,但其中许多功能确实具有潜在用途。你当然可以在没有这些类型服务的情况下获得所需的好处,但这会更困难,几乎所有成功的环境都依赖于它们多年。这些服务对于系统管理的需求几乎总是免费的,别避免它们。作为托管服务,它们的使用也是突破局限,摆脱局域网思维的另一种方式。
在讨论工具时,并没有太多最佳实践或经验法则可以探讨。测试多种工具,跟踪市场上现有和即将推出的工具,评估适合你组织的工具,并深入学习所选择的工具,都是标准的良好做法。
一些经验法则:
-
管理工具几乎应该始终是开源的。这是一个安全至关重要的领域,而许可限制本身就可能带来安全风险。因此,在这个领域,开源比大多数领域更加重要。
-
以与网络无关的方式部署管理工具。这意味着将它们部署到互联网上,选择一个任何位于任何地方的机器都能合理访问的地方。除非绝对必要,避免依赖传统局域网网络连接或安全性。
最佳实践:将所有类型的代码进行版本控制,并保存在代码仓库中。
现在我们已经介绍了这些技术,并简要讨论了一些你可以用来启动调查的实际工具,这些工具可以帮助你在自己的环境中尝试部署并学习。
总结
在本章中,我们探讨了自动化为何如此重要。我们研究了应如何接近自动化并从哪里开始。我们讨论了成熟度建模。我们深入探讨了相当复杂的状态机和基础设施即代码等话题。最后,我们讨论了你今天就能下载并学习的实际工具,这些工具可以将你的编程水平提升到一个全新的高度。
在下一章中,我们将讨论系统管理中最重要且最常被回避的主题之一:备份与灾难恢复。如果有一件事是我们在管理中必须做对的,那就是我们的灾难避免或恢复能力,请不要跳过接下来的章节。
第十章:用户与访问管理策略
在Linux世界中,我们很容易忘记我们依然有用户,而这些用户仍然需要我们在Windows或macOS世界中期望的所有监督、安全和管理。在基于 Linux 的操作系统中,用户通常是被忽视的,因为这些系统常常被视为黑盒服务器工作负载或奇怪的设备,最终用户不需要关心。这当然并不正确。用户在任何 Linux 系统中都很重要,就像在其他任何系统中一样。
在本章中,我们将讨论服务器和最终用户设备的用户及用户访问管理。我们将研究在 Windows 世界中常见的方法,以及在 UNIX 世界中常见的方法,并且我们还会谈到一些在行业中开始出现的替代方法。
我们还将讨论 Linux 的远程访问——即支持或从我们的系统进行远程工作。当然,所有这一切都将在安全的背景下进行,因为用户管理本质上是一个安全话题。
在本章中,我们将学习以下内容:
-
本地用户与远程用户
-
用户管理机制
-
远程访问方法
-
SSH、密钥管理和跳转服务器
-
替代的远程访问方法
-
终端服务器和虚拟桌面基础架构(VDI)
本地用户与远程用户
从最高层次来看,任何系统上的用户账户有两种基本的思考方式。第一种是本地账户,存在于本地系统上并被使用。第二种是用户账户,存储在某种远程服务器上,本地系统通过网络进行引用。当然,也有将这些技术以各种方式结合的混合方法。
我们应该首先谈论这两种方法的明显好处。对于本地管理的用户账户,我们可以迅速访问账户信息,并且不依赖于网络。这带来了明显的性能优势、更好的安全性,并且防止了其他服务的故障影响到我们的本地系统。本地用户是稳健且简单的,快速且易用。直到 1990 年代,甚至很少有人考虑其他可能性。
远程管理的用户今天占据了绝大多数的情况,因为这种模式使得不同组织之间的用户可以有一个单一的真理来源,有时候甚至可以跨组织使用!这有许多好处,比如允许用户创建一个复杂的密码,他们有可能记住并在多个地方使用,修改一次密码就能在所有地方生效,同时也使得支持团队(这可能是我们这些系统管理员)可以轻松重置、锁定或禁用账户。
在现代企业中,假设只有远程用户账户是可行的已经成为常见做法,但本地账户依然完全可用且可行,对于各种规模的组织来说,仍然是一个不错的选择。不要仅仅因为你的规模或现代化程度而认为某种方式适合你的使用场景。当然,几乎所有现有组织都已经在他们将要使用的架构上进行了大量投资,改变架构是一个非常庞大的工作。我们很少能有机会在一片空白的环境中实施类似用户管理的项目,但偶尔也会遇到这种情况。
本地用户管理需要的网络带宽更少,但今天这基本上已经不是一个问题。更为重要的是安全性和可用性问题。如今,大多数网络非常快,用户管理所需的资源也很少;这导致供应商将用户管理提供为一种服务,通过托管服务商通过互联网提供集中式用户账户。如果互联网能够为这些服务提供足够的带宽,那么基于局域网的版本应该也不会有问题。
安全性成为问题的原因是,多个地方共享同一个账户意味着有一个账户会成为攻击的目标,而如果这个账户被攻破,实际上将无限制地访问所有使用该账户的地方。如果我们使用本地用户账户,并且在不同地方重复使用相同的密码,那么这就模拟了这个问题,因此在很多情况下,除非我们遇到一种情况,用户在不同位置使用不同的凭证,否则这个问题并不成立。对于传统的终端用户来说,这种情况不太可能发生。对于系统管理员来说,这可能相对容易做到。经过培训并理解凭证重要性的高安全性用户,可能很容易利用本地账户的灵活性。你必须了解你的用户及其参与意愿,才能真正评估这种情况中的安全潜力。
围绕安全性的更大问题是支持远程账户的具体机制,它们可以单独受到攻击,而与其支持的账户是分开的。无论你选择哪种机制,都必须通过网络进行通信,以便这些账户能够集中化。在几乎所有情况下,还会有某种形式的本地回退机制——例如凭证缓存——它也可能成为攻击的目标,因此远程存在的账户几乎从未能完全消除本地账户及某种机制的需求。如果缺乏这样的机制,那么就有现成的方法可以通过攻击网络访问来中断登录。
远程用户管理的优势在于拥有一个中央存储库,这个存储库可以接收更专注的安全关注,并且能够更轻松地防止物理暴露给攻击者。终端设备通常最多只会缓存少数的用户账户或紧急访问账户,而不是整个用户列表,从而减少了盗窃笔记本电脑或桌面被攻击时,影响超出设备上缓存的账户列表的风险。
这两种方法都不能算作最佳实践。两者都是完全可行的,并且应当在组织层面以及工作负载层面进行评估。企业选择使用不同的方法来满足不同需求并不罕见。通常没有必要实行单一机制,因为大多数组织足够庞大,拥有多样化的需求,且可以合理地在组织内部实施多个机制。通常,这种混合方式效果最佳,因为集中账户对于大多数终端用户最有利,而本地账户则更适合 IT 和其他技术部门。
在我们掌握了这些基础知识后,我们准备好讨论可以管理这些用户的机制,无论我们选择在哪里实现它们。
用户管理机制
在现实世界中,有许多用户管理机制的实现方式需要考虑。有些是 UNIX 或 Linux 原生的,有些在 Windows 世界中常见,有些是新兴的,还有些则是通用且中立的。
需要说明的是,任何探讨用户管理机制的旅程,首先要研究的就是 Linux 用户系统本身。简单而通用,每个值得一提的 Linux 系统都会自带此系统。当然,这个系统是可以被替代的,但实际上它几乎从未被替换。这个系统有着巨大的优势:它始终内置、速度非常快、安全性高,且为每个 UNIX 管理员所熟知。系统中几乎没有出错的地方,也没有复杂的设计。虽然有一些过时的组件可能会因为早期的遗留而存在,如果有必要进行手动配置,可能会让人感到有些困惑,但如今几乎没有人手动操作这些系统(尽管了解如何手动操作总是有备无患)。本地用户通常可以通过自定义脚本、现有工具或状态机等方式非常轻松地自动化。
使用自动化将本地用户转化为远程用户
这正是我们无法区分本地用户和远程用户之间差异的一个典型案例。对本地用户管理的一种重要方法是将主用户列表存储在其他地方。这个列表可能是一个简单的文本文件,我们对其运行脚本,或者更可能是一个配置文件,在基础设施即代码的实现中作为状态管理系统的一部分。
在这个例子中,我们的中央管理系统可以用于将用户账户、权限和细节从中央配置系统推送到我们网络中的每台主机上。系统可能会将所有用户推送到所有机器上,或者只将分配给这些机器的用户推送上去。这些决策在实施过程中完全由你来决定。
在这个例子中,是的,我们仍然在每台计算机上使用本地用户机制,并且在任何给定时刻都不需要通过网络进行登录,然而账户仍然是以一种几乎完全模仿像 Active Directory 这样的系统的方式进行中央控制的。我们可以集中执行密码规则,可以集中创建或撤销账户,可以集中控制哪些机器可以或不可以登录,等等。我们本质上有一个中央用户系统,而不是本地系统。
关键的区别在于,像 Active Directory 这样的真正中央用户目录中,用户活动会被导向中央系统,只有在系统离线或处于某种降级状态时,才会可选地触发本地缓存。当可能时,网络活动会支持登录过程。我们所描述的机制中,所有的登录都是通过本地资源进行的——也就是说,非网络化的资源,而中央系统仅用于更新本地登录列表和细节。虽然“本地账户”和“本地缓存账户”之间存在精确的语义差异,但这两者的行为确实是不同的。这是一个非常有趣的思维实验。假设本地维护的账户必须在每台设备上包含所有用户,但实际上有许多方法可以将其限制为仅几个用户,甚至有时仅一个用户,同时假设没有用户或只有少数用户会从远程用户管理系统缓存到本地设备,但在某些情况下,整个用户列表可能会被缓存到本地。这里的区别在于用户列表是如何本地创建的,了解这种机制在你案例中的工作原理,再加上了解系统的使用方式,就能告诉你两种方法对你的暴露程度。
然而,这种自动化本质上提供了一个相当重要的机会,让我们重新思考关于本地用户限制的假设。在这种情况下,我们或许能够仅通过本地用户重新创建许多或所有通常被认为仅由更重、更脆弱的远程用户系统提供的期望功能。在现代环境中,应用程序通常不会对操作系统认证系统的扩展进行身份验证,这种方法可能会非常奏效,尤其是在基于 Linux 的操作系统上,在这种系统上,这种集成并不常见。如果你的网络架构采用共享认证方法,例如通过 Active Directory 提供的方式来允许访问网络资源,那么这种方法将无法提供与这些模型通常所具有的平滑、集成体验。依赖这些共享认证过程的网络资源设计模型在如今的主流方法中正逐渐失去其地位,因为随着居家办公的增加、用户的流动性增强以及安全问题的关注,用户体验的格局开始发生变化。
在超越本地用户之后,实际上只有默认机制可用时,我们开始看到各种遗留的和更现代的用户管理选项,随着这一领域的升温,未来肯定会有更多选项出现,因为新的基础设施需求正在推动许多企业对用户管理优先级的转变。
在 UNIX 环境中,当然包括 Linux,传统的用户集中管理服务是网络信息服务,最初称为 YellowPages,后来简化为NIS。NIS 由SUN Microsystems于 1985 年推出,并迅速在 UNIX 世界中普及,改变了人们对跨系统用户的思考方式。NIS 是推动 1990 年代 IT 发展运动的先锋,当时目录服务成为那个时代的热门战略技术。NIS 可能不是第一个目录服务(尽管也许是),但它无疑是第一个广泛应用并且从根本上改变了行业的用户管理范式的服务。
NIS 非常基础,但灵活且易于管理,几乎没有现代所需的所有安全性——这些特性在当时使其非常有效。NIS 几乎在所有 UNIX 系统上都普遍可用,包括 Solaris 和 AIX 等商业产品,以及 BSD 和基于 Linux 的开源操作系统。学习 NIS 意味着你可以轻松跨操作系统进行工作,NIS 还提供了不同 UNIX 版本之间的互操作性。
考虑到 NIS 的巨大历史以及它在安全性和可扩展性方面的不足,似乎 NIS 早已过时,成为人们围坐篝火旁给老一辈讲述的故事,但事实并非如此。NIS 至今仍在使用,尤其是在一些历史悠久的大型企业中,NIS 的实现可能早在 1990 年代就已开始使用,那时它仍是关键技术。新的部署可能早在十多年前几乎就消失了,但旧的实现仍然存在。事实上,在撰写本文时,每个主要的基于 Linux 的操作系统仍然包括 NIS 的包和支持,既可以使系统作为 NIS 客户端使用,也可以创建新的 NIS 服务器!有人提出 RHEL 将在未来几年弃用 NIS,但目前这仍然只是一个提议,离实际发生还有一段时间。NIS 为自己创造了相当深远的影响。
NIS 存在许多不足,特别是在安全性和可扩展性方面,以至于它的设计者在仅仅七年后就尝试用 1992 年推出的 NIS+来替代它(我告诉过你,1990 年代是目录服务的黄金时代)。然而,NIS+并不是 NIS 的直接升级,并且管理起来非常困难,从 NIS 到 NIS+的升级过程也并不顺利。NIS+从未获得足够强大的支持,未能成为主流技术,实际上 NIS 在现实世界的使用和软件支持方面超越了 NIS+。制造 NIS 和 NIS+的 SUN 公司宣布 NIS+将在 2002 年停止使用,虽然它在几年后仍然得到官方支持,但已经逐渐衰退。毫无疑问,NIS+推动了集中式用户管理技术的发展,但它本身从未成为关键技术。它的黄金时代是在 1990 年代中期,但由于当时涌现了大量的技术,NIS+在来自各方的竞争中逐渐被遗忘——包括来自 Novell 和 Microsoft 等新兴厂商的竞争。
为了避免深入讨论 1980 年代和 1990 年代那些复杂且大多被遗忘的目录服务历史,我们只需关注 1993 年推出的一项主导技术——LDAP(轻量级目录访问协议)。LDAP 在许多方面改变了游戏规则。首先,它是厂商中立的,允许任何系统自由实现。其次,它具备许多先进的数据库、协议和安全特性,既能够灵活使用,又能保证安全,同时具备良好的可扩展性。虽然当时也存在其他技术,但到了 1997 年 LDAPv3 发布时,其他目录服务几乎不再成为新闻头条。LDAP 被视为局域网目录市场的明确胜者和未来。
LDAP 在 1990 年代开始取代 UNIX 世界中的 NIS 和 NIS+,包括在基于 Linux 的操作系统中,尽管当时可用的实现复杂且尚未广为人知。LDAP 真正取得突破是在 2000 年,Microsoft 宣布他们将用名为 Active Directory 的 LDAP 实现来取代传统的安全账户管理器(SAM)系统(该系统以有主备域控制器(PDC 和 BDC)而闻名)。Active Directory 被证明是一个制作精良且易于管理的 LDAP 实现,它完全主导了市场,并且超越了 LDAP,甚至到了今天,很少有人意识到 Active Directory 本质上只是市场上众多 LDAP 实现之一。
基于 Linux 的操作系统几乎可以使用任何 LDAP 服务器作为目录服务源,甚至可以使用 Active Directory 本身,后者是一个 LDAP 服务器,但除了 LDAP 系统部分外,还有像 Kerberos 这样的高级要求,赋予了它比普通 LDAP 更强的功能和安全性。自 1990 年代末以来,LDAP(以某种形式)一直是 Linux 系统需要认证到基于局域网的目录服务时的通用标准。今天,有多种 LDAP 服务器实现可以在 Linux 上运行。甚至还有用于 Linux 的 SAM 和 Active Directory 实现,可以作为服务器运行!
如果选择使用本地目录服务器作为方法,那么在基于 Linux 的操作系统中,几乎可以肯定实现 LDAP 的方式是唯一合理的选择。如果目的是与其他系统(如 Windows 或 macOS)进行集成,那么带有额外特殊功能的 Active Directory 版本的 LDAP 几乎可以肯定是必需的选项——无论是直接来自 Microsoft 的版本,还是可以在几乎任何 Linux 上运行的开源 Samba 实现。如果是为了实现全 UNIX 设备的集成,那么更传统的 LDAP 服务器产品更可能是合适的选择,例如 OpenLDAP 或 389 目录服务器。
一般认为 LDAP 不适合暴露给公共网络(如互联网),通常被认为是局域网中心化的,这意味着它至少部分依赖于网络防火墙来提供一个安全的操作空间,以便它能够执行其工作。暴露 LDAP(即使假设通过升级版 LDAPS 协议支持 SSL/TLS)也有一定的风险。一些公司仍然这样做,虽然它可以工作,但需要大量的规划和对暴露范围的理解。许多公司通过第三方代理不小心暴露了 LDAP 组件,导致了无意的暴露(也突显了局域网中心化安全方法的围墙花园理论的风险)。
著名的 RDP 暴露风险
在 Linux 或 UNIX 圈子里,RDP 暴露风险的例子并不像在 Windows 世界中那样广为人知,因为通过微软的远程桌面协议(RDP)远程访问系统是非常常见的。然而,RDP 通常相关的概念和问题,如容易受到暴力破解攻击和对潜在攻击者的高可见性,实际上与 Windows 本身无关,而是与架构设计有关。
问题在于,将 RDP 暴露在一个公开可访问的 IP 地址上被认为是非常高风险的。然而,RDP 协议的安全性与 SSH 相似,SSH 通常被认为是可以公开暴露的(在合理范围内)。为什么这两种用途和安全性相似的协议会导致两种如此不同的安全态势?
秘密在于,Windows 世界中的一个惯例是普遍使用 Active Directory(一个 LDAP 实现),或者是微软标准的多用户 RDP 环境RDS(远程桌面服务)要求 Active Directory。提到 RDP 时,Active Directory 几乎成为了一个不言而喻的结论,但使用 SSH 时,通常假设不会使用 Active Directory 或某种形式的 LDAP(至少不是作为外部认证方法)。
为什么底层的安全方法会产生不同的效果,而 Active Directory 和 LDAP 本身都是高度安全的,RDP 也是一个非常安全的协议?答案在于,RDP 以一种与其在内部局域网中的使用方式截然不同的方式强制暴露了对 Active Directory 的访问。
在局域网内,我们基本上有一个自动白名单,它包含了我们局域网中的设备。在许多环境中,这个白名单会被 VLAN 进一步限制,将不必要的设备(手机、物联网设备等)隔离在终端用户设备之外。在更大的环境中,网络访问控制可能进一步限制潜在的暴露,从而为我们的 Active Directory 提供一个非常安全的环境。此外,Active Directory 本身通常通过限制对任何给定账户的登录尝试来保护自己,在允许进一步尝试之前,会将账户锁定一段时间。远程攻击局域网中的 Active Directory 通常是相当困难的。
当我们将 RDP 开放到互联网时,所有这些控制都会完全消失。当然,可以通过 IP 白名单、VPN 封装或其他技术来限制这一点,但标准部署将会大范围地暴露我们的系统(如果没有这样做,暴露它的目的通常就会丧失)。通常被忽视的是,在一定数量的失败尝试后锁定机制,这对于确保 Active Directory 的安全至关重要,但它也为对我们的用户发动拒绝服务(DoS)攻击提供了手段(也就是说,外部用户可以轻易地阻止我们的用户登录)。为了减轻这种攻击风险,我们必须禁用 RDP 的此机制,从而允许来自公共空间的无限攻击!两种选择都不完全可行,因此,尽管 RDP 和 Active Directory 在各自的领域内都相当安全,但在传统方式下使用 RDP 仍然具有很高的风险。
SSH 和其他机制通常与中央用户账户系统(如 LDAP 和 Active Directory)解耦使用,使它们能够保持一个完全独立的安全机制和姿态,相较于其他用户认证方法。RDP 当然也可以这样使用,但由于 Active Directory 的存在,通常假设它具有中央用户账户访问功能,这使得将其视为解耦服务变得困难,因为我们组织中的许多人会期望它与 Active Directory 有即时的集成。
今天,我们生活在一个后 LAN 和通常是后 LDAP 的世界里。即使是 LDAP 的最大支持者微软,也在尽可能避免使用它,并且可能比其他任何公司都在投资 LDAP 替代方案,主要是他们自己的 Azure AD 服务,这个服务令人困惑地保留了“Active Directory”这个名字,尽管它与 Active Directory 完全不相关(但可以与之连接以扩展它)。
对行业公认的认证系统的最大变化是,大多数系统是托管产品,而不是企业需要自行部署和维护的软件;而且大多数现代系统都是基于互联网的,允许用户几乎位于任何地方,只要他们有互联网连接,就能连接到认证机制。
这些新的机制来自许多不同的供应商和供应商类型,以不断增加的多样化形式出现。在完全不涉及服务器、仅限桌面的 Chromebook 世界中,Google 自身拥有一个独特的认证机制,并且今天代表了基于 Linux 的最终用户市场的一个非常重要的部分。
操作系统登录在现代世界中还有意义吗?
作为一本关于 Linux 管理的书,我们无可避免地要讨论操作系统级别的用户管理,并且我们必须(按照最佳实践)质疑这个概念今天是否仍然重要(或从历史角度来看是否重要),或者登录操作系统是否很快就会成为过去式。说实话,这个问题并不容易回答。直觉的反应是得出结论,操作系统用户是极其相关的,并且是所有安全的基础。但它们真的是吗?
首先,我想先说:是的,通常来说,操作系统的登录和用户管理今天仍然很重要,而且一直以来都是如此。
然而,我们对用户登录的思考方式发生了巨大的变化。今天的用户环境与一到两十年前大不相同。让我们从一点历史开始。
在 1990 年之前的时代,即古老的计算机世界,极少有系统使用用户身份验证机制,至少在操作系统级别没有。像 UNIX 和 VMS 这样的系统是特殊案例,是被视为先进和令人印象深刻的大型企业系统。大多数用户接触到的,甚至是使用像 Mac、Amiga 或 MS-DOS 这样的系统,都是单用户、没有身份验证的系统。直到 2001 年,微软的 Windows Millenium Edition(ME)发布时仍不支持真正的多用户(因为它仍然只是 MS-DOS 上的图形化外壳)。总的来说,操作系统需要管理多个用户的想法曾是一个陌生的概念。
在 1990 年代,随着网络的普及、互联网逐渐成熟,用户对更高级功能的需求显著增加,用户安全性和访问控制的转变非常重要。如果说 1990 年代有什么特征的话,那就是用户管理的时代(我们之前提到过)。突然间,每个人都开始关心如何处理多个用户共享同一设备,如何在多个设备之间使用户体验变得可移植。系统管理几乎被完全颠覆。
到了 2000 年代,操作系统级别的用户体验期望已经深深扎根,用户管理从竞争优势转变为商品化功能。最后那些没有支持原生多用户功能的操作系统逐渐消失,即便是面向娱乐用户的普通终端产品也开始鼓励用户管理和安全性。
当智能手机首次进入市场时,它们是对 1980 年代无用户系统的回顾。设备的持有者被假定为其普遍且未命名的唯一用户。即使是手机也已经至少转变为一个以用户和安全为中心的设备,即使它们仍然聚焦于单个用户,但也会考虑访问控制和用户身份。
在服务器端,用户管理在过去几十年里确实失去了光彩。在 1990 年代的巅峰时期,Linux 及其 UNIX 亲戚系统曾风靡一时,直接的终端用户登录和服务器上的用户管理占据了系统管理员大部分的工作时间。这个趋势逐渐消退,如今,终端用户需要在操作系统级别上访问服务器的账户或登录的想法,最多也只是显得过时。例外情况总是存在,但它们少之又少,并且越来越罕见。
即便在其巅峰时期,所有管理员必须使用单独的用户账户登录这一必要性也从未得到普遍接受。或许所有管理员共享单一账户从未真正成为常态,但也从未真正罕见过。共享 root 账户(默认的管理员用户账户)访问一直是一个普遍的做法,尽管很少有人愿意承认自己见过,它在 Linux、Windows,甚至可能在所有其他环境中都很常见。这种做法(并且肯定仍然存在)如此广泛,以至于通过外部机制管理用户访问单一账户的技术和工具甚至有点流行(比如登录到一个第三方控制台,按需访问多个服务器上的 root 账户!)
由于我们这本书是关于最佳实践的,我想花一点时间指出,作为系统管理员,维护用户身份和访问控制在我们的服务器上绝对是最佳实践,而且共享账户即使管理得当并且安全,通常也不是一个好主意。为了维持更安全和可审计的系统所需的努力并不大,我们完全没有理由去避免它。尽管如此,共享账户的访问并不一定像听起来那么危险,因为即使在这种情况下,仍然存在审计控制和访问控制的潜力,而虽然我真的怀疑是否存在实际正当的使用案例来支持这么做,但确实可以让共享访问变得足够安全,以便有效运作。
更重要的是,对于服务器(以及终端用户工作站的管理功能),现代设计技术如状态机、基础设施即代码、应用封装(如应用容器)、MDM(移动设备管理)甚至RMM(远程监控和管理)工具,可能完全消除了登录的需求,从而使整个用户管理讨论变得不再重要。如果我们从不登录,如果我们从不创建用户,那么我们就不需要考虑用户账户访问安全的问题,无论是远程的还是本地的。
因此,值得考虑的是,从服务器的角度来看,用户的需求可能不过是一个过时的时尚,或是那些无法保持最新技术的商店所依赖的备用支撑。这些当然是管理用户,但这长期以来一直是服务器上唯一预期存在的用户。
在终端用户设备上,用户的概念也开始发生剧烈变化,但原因完全不同。传统上,终端用户设备上的工作主要集中在本地安装的应用程序上,这些应用程序本身没有用户控制,而只是运行在操作系统提供的安全控制环境下。这可以是任何类型的应用程序,从文字处理、图像编辑到视频游戏。这个环境主要由可访问的本地存储位置来定义。对许多用户,尤其是家庭用户而言,这几乎已经完全改变。
如今,大多数应用程序是 Web 应用程序,即在浏览器中运行而不是完全安装的应用程序。用户可能会登录到应用程序,但这几乎总是与任何操作系统登录分开。即使是本地安装的应用程序,也开始通过互联网连接进行身份验证,越来越多地依赖于服务。
随着这一变化的发生,操作系统用户作为定义安全访问上下文的主要组成部分的概念正在迅速消退,用户需要在应用程序级别存在的想法已经成为常态。随着这一过程的推进,我们必须开始考虑操作系统用户账户的功能不再是精细的访问控制机制或用户管理的终极方式,而只是为了尝试确保一个安全、受保护的环境,从中我们可以启动我们的 Web 或网络应用程序,并在应用程序层面进行登录,在那里用户和访问控制才是更加相关的。将用户访问控制转移到应用程序层面至关重要,因为数据智能就存在于此,在这一层面可以进行更细粒度的控制,而不是在整个应用程序层面授予访问权限。
随着操作系统在用户管理中的传统角色逐渐消失,强大的用户管理和控制系统的优势也开始削弱。这不仅仅是因为行业和软件成熟导致了用户访问控制从操作系统上移到应用程序中的变化。还有其他因素在起作用。曾几何时,计算机被期望大量使用打印机,但这种情况已经不再普遍。打印机现在只是一个事后考虑的设备,如果它们存在的话,而不再是计算机的主要功能。同样,现代应用程序也不像过去那样使用操作系统管理的存储,严格管理本地存储和映射远程存储资源的需求已经减少。
即使是在十年前,用户管理系统,比如 Active Directory,首先用于协调打印和映射驱动器资源给终端用户。今天,随着应用现代化、工作力量的流动性和计算的普及,这些功能已经成为遗留功能。在家工作的笔记本用户可能完全不需要映射驱动器或打印机,而为了让移动用户能够以这种方式工作,办公室内的工作人员也不得不做出相应的适应。访问控制机制的趋势正在远离传统的操作系统级用户使用方式。
总结来说,用户仍然很重要,但他们的相关性已经不像过去那样强烈,未来看起来是一个用户价值将继续减弱的趋势。
知道哪些远程访问方法最适合你,需要的不仅仅是理解这些系统是如何工作的,了解它们的实现如何适应你的环境只是确定应该为你的组织选择哪种机制的第一步。了解市场上目前有哪些产品,它们的当前功能、局限性、定价和其他商业因素都是必要的。用户管理迅速发展成为一个市场,在这个市场中,我们更多的是需要了解现有的产品供应,而不再是自己来实施。
在接下来的章节中,我们将超越用户身份验证,深入探讨如何为这些用户提供远程访问他们所需系统的方式。
远程访问方法
假设我们没有采用基于状态机技术的无访问方法,我们有几种常见的途径可以用来访问我们的 Linux 系统。在大多数基于 Linux 的操作系统中,我们将讨论系统管理员,像你我一样,如何能够登录并交互使用操作系统,但我们所使用的任何典型方法,最终也将成为终端用户的选择。终端用户的需求通常与系统管理员的需求截然不同,但我们能使用的工具通常会有所重叠。
对于我们这些系统管理员来说,访问通常需要非常快速地设置,使用时也非常临时,重点是确保系统具有高度的可访问性并以命令行驱动。对于终端用户,我们则会期待相反的需求。管理员通常需要登录到多个不同的操作系统,可能是一个接一个地登录,也可能是同时登录多个系统。访问过程过长可能会显著妨碍我们发挥作用。
传统上,终端用户通常只会登录到单一系统,并在整个工作期间(通常是一个工作日或类似时间段)保持连接。虽然他们可能需要花更多时间进行一次登录,但优先考虑的是提供更稳定的终端用户体验。由于需求差异,远程访问技术可能是分开的,实际上没有必要强求将它们合并。
远程访问有两种主要类型。一种是直接连接,即我们暴露端口并使用像 SSH、RDP 或 RFB(VNC)这样的协议,通过软件客户端连接到我们的系统。这是最为人熟知的技术类型,也是最直接的管理方式。它不需要复杂的配置,且易于理解。在这种方法中,我们在目标虚拟机上(或者可能是在虚拟化管理程序上,但结果大致相同)运行传统服务,外部客户端访问该系统。
另一种访问方法是间接访问,其中使用访问服务器来管理操作系统和客户端的访问。该方法需要一个公开托管的服务器(通常是以服务形式提供,但也可以自托管),终端用户和客户端都作为客户端连接到它,从而确保只有访问服务器需要对外暴露。
两种解决方案的优点非常明确。直接连接较为简单,出错的可能性较低。间接连接则需要更多的基础设施,但能减少潜在的暴露点,整合连接,并隐藏网络的存在,使得基于远程访问发布的网络更难被发现和攻击。
出于多种原因,普通终端用户倾向于使用直接连接技术,如 RDP 和 RFB(VNC),而系统管理员则倾向于使用间接连接技术,如 MeshCentral、ConnectWise 和 LogMeIn。对于终端用户而言,直接连接技术通常能提供最稳定的体验,仿佛他们直接操作硬件,就像它就在面前一样。对于系统管理员而言,增强的安全性和对跨多个物理位置系统的访问整合是非常有益的。
然而,需要注意的是,我们在所有情况下都在说趋向。这里没有硬性规则,只有强烈的趋势。然而,由于我们正在处理 Linux,我们还需要考虑其他因素。例如,RDP 在 Linux 上的管理通常比在 Windows 上更为复杂,而间接访问方法可能更容易实施,但理解程度较低。此外,我们的用户群体可能有不同的固有期望——例如,Windows 用户可能期望使用 Windows 原生工具,而基于 Linux 的操作系统用户可能对不太熟悉的访问选项持更加开放的态度。
和许多 IT 领域的事情一样,理解基础技术只是第一步。在接下来的部分中,我们将讨论如何使 SSH(一种直接连接技术)变得更加灵活和强大,并从某些角度来看,我们将通过直接连接模拟间接连接。它们之间的差异并不大。
即便是经验法则在这种情况下也很难适用,远程访问的讨论通常会依赖于许多因素,例如如何使用这种访问,这些基础设施是否会与最终用户共享,可能存在的安全需求,是否还有其他访问方式如 VPN,是否有价值创建一个与其他技术或平台共享的统一连接过程?
然后,我们还需要考虑使用多种访问方式的可能性。为了确保即使一种方法失败,仍然能保持可用,使用不止一种方法是很常见的。某一种可能是方便但脆弱的访问方式,而备份方法则可能是高度安全、操作繁琐,但作为关键备份,能在其他方式都失败时派上用场。
我如何处理远程访问
在这样一个缺乏明确指导的主题下,我觉得花时间分享我自己常用的访问选择是有价值的。我这么做并不是要建议我的方法是理想的,而是希望为大家提供一些现实世界决策过程的洞察。
在我负责管理 Linux 服务器的系统行政工作时,我们通常需要远程访问正在运行的系统,而不是完全依赖于状态机或基础设施即代码的方式,通常会选择一种双重方法,一个是直接访问,另一个是间接访问。
对于间接访问,我们使用 MeshCentral,它本身是开源软件,运行在我们自己托管的 Linux 操作系统上。这使我们在与大多数解决方案相比,具有广泛的灵活性和成本节省,并且因为我们能够在与内部和客户部署相同的操作系统上运行它,我们能够利用其他地方已在使用的流程、工具和技能,从而最大化效率。像许多间接远程访问解决方案一样,使用 MeshCentral,我们可以进行远程终端访问、如果服务器上安装了 GUI,还可以进行远程图形桌面访问,并且有许多工具用于监控、文件传输和远程命令执行。
通过这种间接访问,系统管理员几乎可以立即访问我们所维护的所有服务器,跨越高度不同的技术栈和物理位置。一些服务器被隔离在局域网内,无法进行端口转发,一些有公共 IP,一些有图形桌面,大多数只有命令行接口。不管它们的地点、使用场景或配置如何,MeshCentral 都能为我们提供所需的访问权限,帮助我们管理系统。
对于主要涉及紧急访问的情况,我们还保持对几乎所有系统的直接 SSH 访问。这一点非常重要,因为当间接访问方式失败时,重新配置、打补丁或重启系统的能力通常至关重要。这种访问几乎总是会限制为仅从直接托管工作负载的本地 LAN 上进行访问,甚至可能在该网络范围内进一步限制,使得 SSH 只能从某些特定工作站或其他指定为高度安全远程访问用途的服务器访问。在某些情况下,SSH 服务可能甚至默认不会运行,只有通过更改状态机设置或通过某种带外管理方式手动开启;或者它也可能通过某种自动化方式启用。SSH 对某些自动化任务也可能非常有用。
拥有两种截然不同的访问方式,并且配备深度安全控制,为我们提供了访问性、保护性和安全性的最佳平衡。你必须意识到,每增加一种访问方式,意味着恶意攻击者的攻击途径也会增多,因此增加不必要的访问方式通常不是一个好选择。你需要确保可靠的访问同时又不危及系统安全。
在这类讨论中常常被忽视的一点是,有些直接远程访问工具的工作方式往往是我们没有预料到的,比如基于网页的直接访问工具。这些工具包括 Cockpit 或 WebMin 等产品,它们为我们的系统提供基于网页的界面。这些工具可能允许通过网页界面配置系统,甚至可能允许通过网页界面进行交互式控制台访问,从而使我们能够以完全不同的方式发布和确保远程访问。
在 Linux 世界里,跨越房间或跨越全球访问计算机最常见且假定的方法就是广泛使用的 SSH 协议。接下来,我们将探讨一些方法,让 SSH 比原生更强大。
SSH、密钥管理和跳板机
使用 SSH 进行 Linux 操作系统的远程管理是如此普遍,以至于它值得特别关注。单独使用 SSH 是高效且非常安全的,但它是一个广为人知的工具,通常会暴露出如此强大的功能,因此常常成为有针对性的攻击目标。我们在使用 SSH 时不能掉以轻心,尤其是当它暴露在互联网上时,风险实在是太高了。
使用 SSH 时,我们几乎有一长串的方式可以保障其安全。我们将探讨其中几种方式,以及它们如何协同工作,使得 SSH 极其难以被攻破。在 Linux 上,SSH 通过 OpenSSH 提供,它是一个成熟且经过实战检验的工具,接受的审查比几乎所有软件包都要严格。大多数角度来看,SSH 从一开始就是一个非常坚固的软件包。
我们确保 SSH 安全的第一个工具是完全取消基于密码的访问,而改为使用密钥。密钥快速高效,允许管理员比使用密码更快速、更安全地访问服务器。密钥还支持密码短语,作为一种两步验证的形式。如果根据安全需求,这对于你的组织是可行的,那么这就要求某人同时知道加密密码并拥有私钥,才能尝试通过这一通道攻击系统。密钥在远程访问认证中已经使用了很长时间,但它们并没有得到应有的普及。许多公司采取了如果你愿意,可以为自己设置密钥的做法,导致太多管理员根本不愿意利用密钥所提供的效率和安全性。
我们的第二个工具是来自失败尝试的帐户锁定。基于 Linux 的操作系统中用于此的标准工具是 Fail2Ban。Fail2Ban 处理 SSH 和其他具有标准登录模块的服务,与它们一起检测针对我们系统的可疑恶意尝试,并自动化我们本地的(即 Linux 基础操作系统上的防火墙)防火墙,阻止来自受影响 IP 地址的流量一段预定时间,通常是三到十五分钟。这种方法是我们对抗暴力破解攻击最有效的工具。
你是否仍然需要同时拥有网络边缘防火墙和操作系统防火墙?
你可能会对这个问题出现的频率感到震惊。让这个问题如此令人惊讶的是它总是出现在什么样的背景下。
首先,了解一些技术。在现实世界中,出于多种实际原因,所有路由器实际上也是防火墙。所以,没有硬件防火墙的网络边缘环境几乎是不可能的。在某些情况下,例如安装 VPS 或云服务时,我们可能默认一个完全开放的防火墙,但至少防火墙还是存在的。我们必须从一个假设出发,即所有操作系统实例通常都位于网络防火墙之后,而这个防火墙可能非常无效。
其次,稍微了解一下历史。由于性能影响,操作系统防火墙在 1990 年代末期之前极为罕见。它们也不太重要,因为在那之前,计算机网络化的程度远远较低。即使网络防火墙已经是普遍的假设,操作系统防火墙还是被引入了,因为它们能提供更细粒度和自动化的功能,例如我们在 Fail2Ban 中所得到的功能,而且它们保护的是已经突破网络防火墙或更可能的是来自局域网内部的攻击。
考虑到背景、技术限制和历史,认为两个防火墙不需要的想法显得荒谬。如果我们有能力绕过网络防火墙,理论上是可以做到的,但在这一层跳过安全性是没有意义的;虽然我们可以选择不使用操作系统防火墙,但这样会带来无法通过其他方法缓解的风险。操作系统防火墙在抵御本地和远程威胁方面具有独特的能力,而网络防火墙只能防御远程威胁。虽然没有什么比同时拥有两个防火墙更好的,但从安全角度来看,我们最关心的是操作系统防火墙。我们主要关心网络防火墙的原因是为了减轻操作系统防火墙的负担。
重要的是,今天的基本防火墙功能并不会产生任何可测量的系统开销。这曾是使用防火墙的缺点(大约二十五年前)。如今,使用防火墙没有有效的限制条件。
最佳实践非常明确且极其重要:网络防火墙和操作系统防火墙是绝对需要的。没有任何情况是可以移除或禁用其中一个防火墙的。
操作系统防火墙常常被禁用,因为系统管理员不愿意花时间了解网络需求或正确地保护工作负载。这从来不是一个有效的借口。我们都曾感到懒惰,也都希望避免在系统中维护另一个支持点,但这涉及到基础的安全性,能够正确地支持生产环境中的系统就要求我们具备启用并配置防火墙所需的所有知识。任何认为禁用防火墙有价值的情况(当然不包括故障排除)都应该被视为一个巨大的警告信号,提示我们需要解决某些问题。
在 SSH 的安全性方面,继基于密钥的认证和账户锁定后,我们的第三种工具是网络限制,通常以限制连接到 SSH 的请求来源 IP 地址的形式存在。这可以通过多种方式实现。通常,我们会在 Linux 系统上的防火墙上实现这一点,但它也可以由网络边缘的硬件防火墙或云服务提供商的网络防火墙等提供。
IP 限制通常最好通过白名单来设置,尽可能的话。白名单允许我们将 SSH 流量限制到一个单一的 IP 或一小组我们认为是已知且安全的 IP 地址,例如管理员的家庭、信任的数据中心或办公室的 IP 地址。这大大减少了我们系统的攻击面,使它们在第一时间难以被发现。
然而,对于某些人来说,白名单可能不可行,或者至少不太现实。在这种情况下,黑名单可以用来屏蔽那些肯定不需要访问的 IP 范围,依然能提高安全性。在这种情况下,系统管理员可以使用国家 IP 范围来阻止来自某些国家和地区的流量,这种做法是可行的。我从不推荐在面向客户的系统中使用这种做法,因为你可能会无意中阻止客户或商业伙伴,从而招致反弹(记住,对于试图从黑名单所在地点使用服务的人来说,他们并不会认为自己被阻止,而是认为服务失败了或离线了),但对于系统管理访问来说,管理员的位置应该大致已知,并且应始终有备选的沟通渠道,安全性更为关键,这种做法是非常有意义的。
第四,使用sudo要求在执行提升权限的命令之前进行额外验证是非常有用的。通过sudo,我们可以在已有的密钥或更好的密钥加密码的基础上增加更多的保护。如果我们使用拥有sudo权限的用户账户登录 root 超级用户账户,那么我们在成为普通用户之前已经证明了一个或两个认证因素。使用sudo时,我们可以选择要求该用户输入另一个独立的密码,以便获得提升权限的权限。这提供了很多潜在的保护。Sudo还帮助我们避免了直接以 root 用户身份运行时可能发生的危险错误,通常是由于打字错误。Sudo更可能保护我们免于自身的错误,而不是来自外部的攻击。它是一个非常有用的工具。
第五,由于上面提到的sudo的强大功能,我们可以完全禁用通过SSH登录的 root 用户,将最著名、也是目前风险最大账户完全排除在风险之外。当我们拥有sudo机制来保护 root 用户,并且在其被访问时进行日志记录时,就没有必要将 root 用户暴露在外了。
更改 SSH 默认端口有效吗?
你会发现许多人和文章告诉你应该始终更改 SSH 的默认端口,或任何访问协议的默认端口,以便使攻击者更难发现。这种做法通常被认为是一种“安全性通过模糊化”手段,但这种方式一般被认为根本没有安全性。
但实际上,这两种做法都有些被夸大。更改默认端口对于实际安全并没有什么作用,因为任何具有一定复杂性或力度的真实攻击都可以在几秒钟内发现一个非标准端口,而攻击者甚至可能不会意识到你试图通过更改地址来阻止攻击。就像你把家门移到房子的侧面,大多数闯入的小偷甚至不会注意到门的位置变得奇怪。门还是那扇门,非常明显。
认为使用非标准端口作为安全措施是错误的。充其量,它在名义上改善了安全姿态,最糟糕的情况可能是暗示你通过混淆来进行安全防护,并可能成为更有针对性攻击的良好目标。非标准端口潜在的好处在于减少了击中我们端口的流量量,使得存储和过滤日志变得更容易。
当然,通过减少日志混乱可以增强安全性,因为这样可以更快地发现或诊断令人担忧的攻击,并且减少存储需求总是一个不错的好处。因此,更改 SSH 端口可能是有益的,但应保持在适当的背景下考虑其益处。
除了 SSH 的所有这些最佳实践安全方法外,还有许多其他标准的加固选项可以使用,但我认为,除了这些,我们很难再定义更多作为最佳实践而不是强烈推荐或值得考虑的选项。稍作调整,SSH 对几乎任何组织需求都可以极其安全。
要提升 SSH 安全性的另一种方法是通过工具如 Google Authenticator 应用一次性密码进行多因素身份验证,这非常简单。还存在许多第三方安全增强措施,SSH 可以像你想要的那样安全。
SSH 密钥管理
一般认为,如果我们要使用 SSH,则需要使用密钥来保护对其的访问。如前所述,它们快速且非常安全。没有理由不使用它们。然而,并不仅仅是简单地使用它们。当我们选择使用密钥时,我们必须确定如何管理这些密钥。这如何才会有意义主要取决于我们组织的规模,或者至少取决于我们的系统管理团队的规模,以及使用这些密钥访问的系统数量。
在其最简单的形式下,SSH 密钥管理可以由个人自行管理。如果用户已经可以登录操作系统,则可以自由创建和管理自己的密钥。对于较小的组织或仅与少数系统管理员合作的情况,这可能是有意义的。
使用 SSH 密钥时,管理涵盖了两个组成部分,即公钥和私钥。通常用户会管理自己的私钥,确保安全,而公钥可以采用几乎任何方式管理。
对于希望改进密钥管理而基础设施较少的小型组织,最简单的方法可以是将用户(包括系统管理员)的公钥存储在维基或其他简单文档系统中,以便根据需要轻松获取。单单这一步就能极大地简化密钥的使用。
密钥也可以存储在类似管理服务器或工作站的文件系统中,并通过简单的自动化推送出去,比如通过 SSH 远程执行的脚本,将密钥复制到指定位置。脚本也可以从网页、文件共享中提取公钥,或者使用像 GIT 或 Subversion 这样的工具从仓库中获取密钥。密钥本质上是文本文件,因此管理它们非常灵活。
在更高级的设置中,可以使用状态机和基础设施即代码的方法,通过与其他自动化工具相同的工具来自动化密钥部署。密钥可以仅仅作为一组文件处理,并不需要特别对待。像状态机和基础设施即代码这样的 DevOps 流程是简化 SSH 密钥管理的极好机制。
然而,所有这些实际上几乎不值得考虑。一旦你在任何规模上使用密钥,并且你的系统管理中出现了密钥管理的问题,那么可能是时候考虑使用公钥基础设施(PKI)系统来管理证书,而不是密钥了。SSH 使用 TLS,这是与 HTTPS 以及无数其他安全协议相同的机制,因此它可以使用与网站相同的 PKI 系统。
当然,在几乎所有情况下,使用公共托管的 PKI 证书系统对于我们 Linux 基础设施中的几乎所有私有和内部主机来说都会是一个问题。因此,我们需要运行自己的证书授权机构,称为 CA,但这是一个标准的做法,成本和开销极低,虽然这种技能并不广泛存在,但它是可以轻松掌握的。使用 SSH 证书而不是SSH 密钥(这里的“而不是”是因为证书包含了密钥,密钥始终隐藏在背后)为我们提供了一个机制,能够快速扩展许多管理员和可能的许多最终用户的 SSH 密钥安全性。
我不会过于夸张地说运行自己的证书授权机构并建立 PKI 基础设施是最佳实践,但对于那些不仅仅是几个用户连接到几个 SSH 主机的组织来说,这是一条不错的经验法则。许多用户连接到不同操作系统实例的网络效应,可能导致 SSH 密钥数量激增,如果不采取措施,可能会无人管理。例如,十个管理员、二十个开发人员、十个测试人员和一百个虚拟机,光是这些就可能需要监控四千个 SSH 密钥组合!
随着几乎所有操作系统今天都支持 SSH,强大的 SSH 安全策略的好处更加显著。SSH 越容易安全地使用,就越有可能被采用,取代其他技术。
跳板机
跳跃盒子是一个重要的安全和管理工具,可以简化系统管理的许多方面。作为一个概念,它们非常常见,但作为一个术语,即使是经验丰富的系统管理员也可能不熟悉。跳跃盒子是一个系统,系统管理员(或普通用户,但通常只供技术支持人员使用,因为其设计较为繁琐)通过远程访问该系统,并授予访问权限到要管理的其他系统。
它被称为跳跃盒子,因为你在跳跃到另一个系统之前,首先登录到它。它是你任务的起点。跳跃盒子不仅用于访问,还常常作为工具的中央存储库、临时存储位置,或者运行自动化脚本的公共位置。
跳跃盒子通常用于提供一个中央访问点,以便直接访问系统,获取类似于间接远程访问技术和传统直接访问之间的混合特性。从技术上讲,跳跃盒子只是一个两阶段的直接访问系统,但它非常有用,可以避免使用像 VPN 或复杂代理这样的网络路由器来实现访问整合。
通过访问整合,我们可以更实际地保护我们的第一道访问防线。跳跃盒子通常会收到最复杂的 IP 过滤、严格的 Fail2Ban 规则、详细的日志记录、双因素认证、快速修补等,以紧密保护最脆弱的进入点。以这种方式,系统管理员可能会通过登录到他们的跳跃盒子开始一天的工作,然后快速轻松地从该点连接到他们管理的系统。
由于其设计,跳跃盒子通常容易存在于局域网内,托管在共置数据中心,甚至可以是云托管的。它们可以被放置在任何实际需要的地方,并可以在任何地方访问资源。它们可以被加固、监控,并通过直接访问协议,甚至 VPN 或多个 VPN 连接到系统和网站,根据需要进行访问。
由于跳跃盒子是一个单一系统,因此管理的系统可以允许从它的单一 IP 地址连接,即使使用直接访问技术时也能保持良好的安全性。
基于 Linux 的操作系统的跳跃盒子通常用于 SSH,因此它们可能被构建为精简的服务器。没有图形界面的 Linux 跳跃盒子可以运行在最小的虚拟机上,这些虚拟机几乎不占用任何资源,使得它们非常容易在需要的地方部署且成本低廉。
跳跃盒子还可以处理其他协议,通常是 X 或 RDP 协议。例如,这在 Linux 系统管理中并不常见,因为图形界面通常对我们来说只是负担,而当使用跳跃盒子时,提供中央图形界面源的资源需求和复杂性通常会让我们重新考虑是否提供图形界面。
跳板机不是最佳实践,但它是一个常见的安全和管理工具,在需要直接访问以加快、简化和提高安全性时非常有用。
替代性远程访问方法
至少从我们通常的理解来看,传统远程访问完全是围绕终端用户的需求设计的,用户需要通过远程会话来替代他们的本地桌面。作为系统管理员,能够在合适的场景下使用这些工具对我们来说是非常有帮助的,并且我们必须理解这些工具,因为它们通常是由我们来管理的组成部分,但就我们自身使用而言,这些工具可能不是最实用的。
当然,我们可以将大多数间接远程访问技术归类为替代性远程访问方法,但它们本质上只是经过调整的传统访问方式,以使其更适合我们的使用场景。作为管理员,我们希望减少与远程机器的登录或交互式会话,期望最终完全消除这种访问,至少在理想状态下是这样。
为此,我们今天有了其他方法来在我们的服务器上运行命令。这些方法并不会在所有情况下取代我们现有的方式,但它们可能是帮助我们从当前状态向未来目标过渡的一项过渡性技术。
使我们大多数系统访问方法看起来传统的原因,实际上是它们涉及完全的交互性。这意味着无论我们使用 RDP、Splashtop 还是 SSH 会话,我们都假设正在与需要管理的系统建立完全连接,包括用户级别的环境设置,并在一个持续的输入和输出过程中进行工作。这种假设已经深入人心,许多应用程序或工具实际上也假设使用这种方法,可能需要一些不合逻辑或不合适的会话环境变量。
除非像我们之前讨论的那样完全移除访问——即通过基础设施即代码的方式——否则我们的过渡性访问步骤是远程命令执行或使用非交互式命令。这与我们其他访问方法一样有效,但没有交互能力。远程命令执行使我们能更轻松地从手动任务过渡到自动化,并且非常适用于审计、安全性和可扩展性。
从最简单的角度看,远程命令执行可以通过 SSH 处理,使用与交互式会话相同的基础设施。SSH 设计得能够优雅地处理这两种方法,并且由于它是透明地执行的,它可以是从一种方法平稳过渡到另一种方法的便捷工具。这些方法可以根据情况混合使用,或者一位管理员使用一种方法,另一位使用另一种方法。
使用远程命令执行,我们可以获得所有命令都在源系统上执行的好处,因此可以被记录。非常适合像跳板机或管理服务器这样的工具,可以记录所有执行的操作。然而,交互式会话,即使是从跳板机启动的,也会将所有重要的会话信息记录到最终的操作系统中,跳板机只会知道远程会话已启动——对于到底执行了哪些命令及其响应的详细信息,将会丧失在中央日志平台的可见性。
在许多方面,远程命令执行是系统管理员在软件开发世界中的函数式编程类比。交互式会话更像是过程式编程,其中动作被视为一系列事件。远程命令执行则是使用单一远程函数来执行任务。如果你不熟悉这些编程范式,这个类比可能难以应用,但对于那些使用过这些范式的人来说,我认为这个例子是有价值的。
SSH 可能是悄然引入远程命令执行的理想方式,并且本质上始终可供系统管理员使用。即使在高度严格、结构化和正式的流程驱动环境中,政策法令通常也不太可能不允许管理员在允许传统交互式 SSH 会话的情况下,随时随地使用这种方法。
其他工具,尤其是越来越流行的工具,今天也允许远程命令执行。这已成为大多数间接远程访问工具的标准选项,从大型商业软件服务产品到小型开源自托管产品几乎总是包含某种形式的远程命令执行。在某些情况下,还具备扩展功能,如能够同时对一组或列表中的多个系统运行相同的命令或命令集。
远程管理工具(RMM)通常以相同方式构建远程命令执行系统。这比创建自定义交互式会话机制要容易得多,并且可以被吹捧为更先进的选项,同时实现起来也更简单。
在我看来,最有趣的远程命令执行应用场景是状态机系统。正如 SSH 可以被视为具有远程命令执行作为可选策略,远离交互式会话,逐步过渡到一种稍微不那么熟悉的方式,状态机也可以并且确实将远程命令执行作为一种方式,保持在更传统的操作模式中,为系统管理员提供在状态定义过于复杂或耗时时的备用方法。
从状态机进行远程命令执行也是一种测试状态机访问或功能的方法,尤其是在开发状态文件时。状态是通过在被管理的系统上运行命令来维持的,不管是哪种方式。在某些情况下,命令是通过一个远程代理来执行的,而远程命令虽然被执行,但具体的命令并不是由状态管理中心系统发送的。在其他系统中,命令可能直接按照管理系统上输入的内容发送,状态机只是作为执行助手。
远程访问,尽管一开始看起来很简单,并不是“一刀切”的解决方案,我们甚至可以在同一个组织内使用不同的解决方案。考虑跳出固有思维,尝试新的或不同的方法来提升工作流程的安全性、稳定性和效率。
现在我们已经准备好从各种方法中获取系统管理员访问和安全性的概念,我们应该讨论一些更适用于终端用户访问系统的技术:终端服务器和虚拟桌面基础设施。
终端服务器和虚拟桌面基础设施(VDI)
与 Windows 世界不同,在基于 Linux 的操作系统中,远程 GUI 访问相对较少。这只是因为 Linux 并不将此视为其核心功能,在这种自我实现的情况下,客户没有需求,所以供应商也没有在此方面做专门化,导致客户觉得这方面的可用性很低,从而形成了一个循环。然而,这并不是说终端服务和VDI(即虚拟桌面基础设施,但它通常更为人熟知并直接以缩写形式使用)选项在 Linux 系统中不存在,它们当然存在。
概念上理解终端服务和 VDI
终端服务器和 VDI 架构交织在一起并不罕见,这主要是由于市场营销部门试图在不适用的场景中推销 VDI,并且因为常常使用重叠的技术。VDI 被作为一种新的热门技术来推广,好像它并非一直存在一样,这也加剧了混淆。而作为该领域领导者的微软,将其核心产品从终端服务器重命名为远程桌面服务器(RDS),也没有起到任何帮助。这导致了一个问题,即许多 Windows 管理员,更不用说用户,常常将 RDP(远程桌面协议)与 RDS(微软的终端服务器产品)混淆。一个是由多种不同产品实现并使用的通信协议;另一个是一个具体的产品和许可工具,必须从微软购买,可能会使用 RDP,也可能不会。
所以我们必须从定义这些技术开始。两者都涉及远程访问计算机。两者都可以使用相同的一套潜在协议来实现这一“魔法”。两者的基本目的是相同的,但实现方式有所不同。
终端服务器一直意味着一个单一服务器(即:一个单一操作系统实例),可以被多个远程用户同时访问。在最初的时代,这通过使用串行连接到哑终端来远程显示文本来实现。后来出现了诸如 telnet、RSH,最终是今天我们使用的 SSH 等技术。这些技术推进了安全性和可访问性的状态,但从根本上讲,远程访问仍然是一个类似于原始串行物理终端的命令行活动。几十年前,图形桌面环境的远程使用成为终端用户的常态,新的协议如 RDP、RFB、X 和 NX 变得流行,但本质上没有什么根本变化。许多用户仍然连接到一个单一的操作系统实例,并共享其资源。只有一个操作系统需要修补,所有人共享相同的内核和应用程序。终端服务器采用的是多对一架构。
VDI(虚拟桌面基础设施)是一种替代方法,用户可以远程访问仅为他们存在的虚拟化操作系统实例。在 VDI 中,每个用户的操作系统实例可以完全不同,具有不同的补丁级别,甚至可能是完全不同的操作系统。一个用户可能使用Windows 11,另一个用户使用 Windows XP,另一个用户使用 Ubuntu。VDI 意味着一对一架构。
在大多数情况下,这两种方法之间的概念和区别几乎完全是出于管理微软软件许可限制的需要。在 Linux 世界中,终端服务器或 VDI 部署之间的区别纯粹是根据系统在访问时如何使用即时决定的。每个 Linux 设备本身已经是多用户的。Linux 缺乏 Windows 生态系统中始终存在的一次只有一个用户的框架。这些概念在非 Windows 环境中往往会被忽视或造成混淆。对于 Linux 管理员来说,任何 VDI 系统其实就是多个轻度使用的终端服务器。在 Windows 世界中,许可规则以非常复杂的方式支配了这个方程式的各个方面。
在 Windows 世界中,Windows 7、10 或 11 的最终用户工作站许可证总是单用户许可证,没有例外。远程访问总是允许的,但只允许单一用户使用,绝不允许替代或附加用户。一个用户坐在控制台前,或者该用户远程访问,但一次只能有一个用户使用。即使是 Windows Server 许可证也只允许一个用户同时使用(另有一个额外许可证仅供系统管理用途),除非购买了 RDS 许可证以支持额外用户。RDS 只能作为附加许可证用于 Windows Server。由于这些许可证规则,Windows 世界中什么是服务器,什么是最终用户工作站,界限非常明确且显而易见。
当然,在 Linux 中并不存在这样的许可证限制。任何工作站都可以作为服务器使用,任何服务器都可以作为桌面或供多个用户使用。任何机器都可以灵活地在任何时间以任何方式使用。诸如终端服务器和 VDI 之类的术语仅指我们打算如何使用系统或系统在任何特定时刻的使用方式,但对于大多数非 Linux 管理员来说,它是一个固定、石沉大海、昂贵的、以许可证为驱动的设计和决策过程,因此我们必须能够理解这些术语和概念如何影响那些处于我们自由灵活的环境之外的人们的认知。
当然,还有一个显而易见的第三种选择,它没有名称。终端服务并不考虑系统是物理的(也就是说,直接安装在裸机硬件上)还是虚拟化的,在这两种情况下它都是一个终端服务器,虚拟化是无关紧要的。对于 VDI,虚拟化是名称的一部分,因此我们只有在系统没有明显理由进行虚拟化时,才会将其视为 VDI。如果我们在裸机操作系统安装上做与 VDI 相同的逻辑架构,那么这个架构没有名称,至少没有一个广为人知的名称。没有虚拟化的一对一远程访问实际上是最常见的远程访问基础方式,甚至以至于大多数人都不会将其视为一种架构。它基本上不需要规划或协调,通常用于各种目的。这个没有名称的设计在任何操作系统中都很常见,无论是 Linux、Windows、macOS 还是其他。
基于 Linux 的操作系统将支持我们所需的任何远程访问架构,甚至支持通常与其他操作系统相关的协议:即来自 Windows 生态系统的 RDP。在 Windows 生态系统中,RDS 技术上与 Active Directory 绑定,导致用户管理与远程访问策略紧密耦合。在 Linux 中,我们没有这样的约束。部署基于 RDP 的终端服务器可以使用我们想要的任何用户管理系统。
像终端服务器和 VDI 这样的工具,更有可能被终端用户使用,从办公室工作人员到开发者,而非系统管理员,但这并不是唯一的情况。在我当前的部署中,我们同时维护这两者,专门供系统管理使用。我将以此为示例场景,展示这些技术如何在管理方面有效地使用。
有时,系统管理员可能会从拥有图形会话中受益。这可能是因为图形工具,如记事本、截图、网页界面等,使工作更高效,或者在某些情况下,工具本身需要图形会话。不幸的是,许多系统,虽然 Linux 本身不常见,但常常是为 Linux 系统管理员所需的系统,只提供基于 Web 的 GUI 界面,或者更糟的是,像 Java 应用程序界面或甚至原生应用程序。我们在主信任数据中心内部,拥有一个专为多用户 RDP 支持构建的 Linux 终端服务器,并且具有静态 IP 地址,这使得我们的管理团队可以随时随地为所有团队成员提供访问权限,在受信任的位置打开图形会话,执行任何必要的工作。
拥有图形界面在进行文档编写、通过屏幕共享进行培训或类似任务时,往往会非常有益。
终端服务器非常适合,特别是在基于 Linux 的操作系统中,提供一个干净、标准的共享环境。VDI 提供了一种竞争的方式,我们和许多公司一样,使用 VDI 提供高度定制化的环境,满足个别系统管理员的需求,例如替代操作系统或桌面环境,这些在共享服务器环境中实施时可能会与其他用户发生冲突。VDI 在某些情况下也更适合,个别系统管理员可能需要成为自己环境的管理员,通常是为了测试,但在共享环境中,这从安全角度来看可能不明智或不可行。
无论是图形界面还是仅命令行的终端服务器和 VDI,都可以作为跳板、管理站、远程执行环境等平台使用。当然,我们还可以将它们用作向终端用户提供基于 Linux 的桌面环境。简单来说,完全没有理由在概念上将这些技术仅限于 Windows,Linux 在这里也能大放异彩,而且在许多情况下,表现得更为出色。
摘要
Linux 操作系统上的用户和用户访问是一个复杂的话题,主要因为 Linux 给我们提供了极大的灵活性。我们可以从多个角度探讨用户的存在位置、如何创建用户、如何管理用户、我们信息的来源以及用户如何以多种方式访问他们的系统。我们有古老的技术,也有极其现代的技术。我们几乎可以使用任何机制,来自任何时代、任何生态系统,我们甚至可以自己构建并且是独一无二的。我们可以遵循传统的流程,也可以轻松地构建自己的流程,并以独特的方式工作。
在 Linux 上没有简单的最佳用户管理实践。相反,我们的最佳实践通常是,我们需要理解技术的各种可能性,了解不同的风险和利益如何适应我们独特的组织,了解市场上现有的产品——从开源到商业,从软件到服务,并从各个方面评估这些需求,以确定适合我们组织的解决方案。没有预设假设。使用本地用户帐户并不错误,即使是在非常大规模的情况下。使用远程用户并不错误,即使是在非常小的规模下。我们不必为安全性维护和运行自己的基础设施,但也不必依赖第三方供应商来为我们做这件事。天空才是极限——大多数方法都有其优点,但所有方法都有其局限性,因此它们都值得彻底调查。
总是有一种倾向,认为任何系统都需要过度复杂化。我们被教导复杂就是好,因为它显得先进,而且感觉是对的。但最终,简单通常能提供最低的总体拥有成本,同时承载最少的风险。使用简单的系统和设计,部件更少,出错的机会也更少,这通常会取得成功。
我希望通过这些信息,你能拥有知识和勇气,从不同的角度来看待用户管理。太多的用户管理解决方案是因为误解了行业趋势应该驱动决策,或者认为常见的解决方案比实际更加安全。最好的解决方案永远是最适合你情况的,而适合你的是很少是适合别人(你所比较的对象)的,只有在极少数情况下,任何你所比较的对象都花时间真正评估过他们自己的需求,因此,允许他人的决策过度影响我们往往是非常危险的。
在我们的下一章节中,我们将要讨论一个极其复杂且常常令人困惑的话题——故障排除。
第十一章:故障排除
在系统管理中,故障排除是最具挑战性的任务之一,尤其是在问题出现时。故障排除即使在最理想的情况下也很困难,但作为系统管理员,我们的工作几乎总是需要排除一个系统中的问题,系统要么正在生产环境中运行并且必须在我们尝试修复某个方面时保持正常运行,要么系统已经宕机,我们必须尽快让它恢复生产环境中的运行。通常我们并没有足够的能力在不让业务因此丧失收入的情况下进行修复,即使有,这也是例外而非常态。故障排除既困难,又至关重要,还充满压力。
故障排除不仅仅是解决明显的技术问题,应用商业逻辑同样至关重要。我们必须在更大的工作负载和业务背景下理解我们的故障排除,并应用不仅仅是简单的技术知识。既有解决问题的方式,也有解决工作负载的方式,还有评估工作流需求的方式,最终的目标是保持业务的可行性。
在本章中,我们将讨论以下主题:
-
避免灾难的高成本
-
初步评估技能与员工
-
逻辑性故障排除方法
-
调查与修复
避免灾难的高成本
在本章中,我们将详细讨论灾难发生后该做些什么。在本书中,我们考虑了如何避免灾难的方法。一个容易被忽视的事实是,保护工作负载免受故障的过程中是有成本的,我们必须将这一点与故障本身的成本以及灾难发生的可能性进行权衡。
我们常常被告知,或者暗示灾难必须不惜一切代价避免。这是荒谬的,绝不应当如此。避免灾难是有成本的,而且这个成本可能相当高。灾难本身也会带来成本,虽然这个成本可能相当高,但并不总是如此。
我们所面临的风险是,避免灾难的成本有时会超过灾难本身的成本。曾经有一段时间,公司常常花费数万美元购买容错解决方案,以保护那些常见故障场景只会造成少部分损失的工作负载。灾难本身实际上比避免灾难的成本更低!而且灾难避免是一个确定的成本,而灾难只是一个潜在的成本。如果我们将两者视作成本进行比较,我们可以简化评估为一个简单的问题:今天损失 50,000 美元,还是明天可能损失 10,000 美元,哪个更好? 这样比其他方式要简单得多,并且能去除大部分情绪化反应。
我喜欢用一句话来形容在灾难避免上过度消费,那就是:今天为了避免明天可能的头痛而对自己开枪。
永远不要将灾难防范计划中的灾难视为必然发生,它并非必然发生。它只有可能发生。评估并运用数学方法。
在本章中,我们将深入探讨支持在企业中的运作方式,如何改善 IT 组织的支持姿态,了解急救需求,讨论如何找到合适的人来组成故障排除团队,然后深入讨论何时调查问题,何时解决问题。
这是我们要覆盖的一些最困难、最模糊且最终最重要的内容。
解决方案的来源
作为系统管理员,我们从哪里获得解决问题的方法呢?我想通过我自己的职业故事来开始这段话题,因为我认为每个人对 IT 支持在广义上的运作方式有非常不同的看法,理解这些不同的视角在我们开始定义“好的支持”是什么之前是非常重要的。
当我刚开始从事 IT 工作时,尤其是在前近二十年,大家普遍认为任何和所有问题都应由 IT 部门来解决。当然,也有一些情况需要应用厂商的补丁、更新或修复,但获取这些补丁、测试它们、应用它们等工作总是由 IT 员工全权处理。甚至认为可以请求厂商提供帮助、指导或建议的想法也显得陌生,更别提实际去做了。联系厂商寻求支持被认为是绝对的最后手段,只在认为硬件或软件中存在未知且尚未解决的缺陷时才会使用,这时将问题交给厂商修复,然后再由 IT 部门应用更新或修复(如果有的话)。
在这个时代,IT,尤其是系统管理员,预计能够全面了解系统的运作,能够解决可能出现的任何问题,坦率地说,还要弄清楚需要做什么。没有如果,没有但是,当然没有“也许”。如果你不知道一个系统如何工作或可能出现什么问题,那么你就需要依靠知识和逻辑去找出问题的根源。对系统的工作原理有透彻的理解,即使有时缺乏具体的细节,良好的逻辑通常也能让你解决问题。
直到 2000 年代末,我才首次遇到那些依赖供应商和经销商来提供某些方面支持的 IT 部门。公司和其 IT 组织(无论是内部的还是外部的,都不重要)无法安装、配置和支持的系统,这个概念对我和我多年来在行业中的大多数同事来说都是完全陌生的。如果你偶尔需要供应商的支持,为什么你不需要全天候的支持呢?如果 IT 团队不具备实施和运营他们负责的系统所需的知识,那它们的存在有什么意义?你需要更多的知识来规划和考虑所有解决方案选项,而不仅仅是修复你最终部署的那个单一方案。如果你需要供应商来处理日常任务,那显然你缺乏进行更为重要的高层决策所需的技能和经验,而这是供应商无法提供帮助的。遗憾的是,许多组织最终在解决方案规划方面完全缺乏能力,这也解释了为什么那么多明显无法满足业务需求的糟糕解决方案会被部署。
今天,似乎大家都将焦点放在了来自销售组织和供应商的支持上,而不是来自 IT 部门,但这带来了两个关键问题。首先,如果 IT 不在关键的支持路径上,它到底是做什么的呢?它们真的有必要存在吗?其次,当供应商仅仅支持他们自己生产的产品时,怎么可能具备满足内部 IT 需求的所有技能呢?这里的脱节是相当显著的。
并没有魔法支持
经常会有一种不言而喻的信念,通常是在管理者中间,甚至有时是 IT 人员中,也会认为有一些神奇的公司,在技术领域内可以提供类似于无限的支持,而这种支持是内部 IT 无法提供的。我猜想,大家可能以为这些公司并非由人类组成,或者认为服务器、存储和操作系统的供应商拥有一些不公开的秘密手册,里面充满了那些不公开的信息,包括秘密代码,可以让失常的系统重新开始工作。
在现实世界中,硬件和软件供应商基本上不知道他们的客户不了解的事情,至少在设备操作方面是如此。这和你打电话给福特或丰田,问他们如何驾驶一辆赛车是一样的,而不是去问赛车手。当然,汽车公司会有一些员工对赛车在性能条件下如何驾驶有一定了解,但他们没有任何人比实际的赛车手掌握更多的知识,他们显然也不会比正在赛道上绕圈的车手有更多的实践经验。
硬件和软件供应商只是一些由 IT 人才组成的团队,和任何其他公司从相同的人才库中招聘的人一样,事实上,如果你在行业中工作了一段时间,你会发现你认识的人可能会从现场工作转到供应商公司,反之亦然,而且很有可能这种情况也会发生在你自己身上。我自己曾在至少六家大型供应商公司担任过工程师,在这些公司中,没有任何特殊的“秘密”知识被隐藏起来。我们所有的客户支持甚至内部支持知识,获取方式和客户一样。有时候,客户实际上比我们还更能接触到我们的文档!
如果供应商知道如何让他们的产品在现场工作得比目前好得多,他们会尽一切可能将这些信息传递出去。几乎所有主要供应商都有广泛的文档、培训、认证和其他项目,希望现场的 IT 工作人员能够独立完成工作,且不出现任何问题,尽可能自己解决问题。供应商并不希望人们说产品无法正常工作,供应商必须介入修复问题。供应商迫切希望 IT 能够在没有供应商介入的情况下,正确地部署、配置和维护产品。这对市场营销有好处,也能带来最大化的利润。同时,这也有助于建立与 IT 的最佳关系,而 IT 大体上是硬件和软件采购的最大推广者和最大门槛守卫者。
也许有人误以为,最优秀的 IT 人员会自动被供应商吸纳,剩下的领域只会留下那些无法胜任的人。这听起来可能有些道理,但实际上完全不是这样。首先,很少有供应商像人们想象的那样有雄厚的资金,而且往往有些客户比供应商更愿意支付并吸引顶尖人才。其次,供应商的支持工作通常与普通 IT 工作有很大的不同,很多人进入 IT 行业时并不喜欢这些工作,因为技术和商业方面的差异,虽然这两个职位高度相关,但也存在显著的区别,因此并没有形成自动的流动。第三,任何供应商提供的支持工作都没有 IT 职位那样技术性强。供应商的职位通常涉及销售和客户管理、遵循详细的规则和流程,并按照预定的方式实施,目的是为了适应销售流程,而非 IT 流程。总的来说,最优秀的 IT 人员很少愿意进入供应商工作,而那些愿意的人往往并不是因为供应商的工作更符合他们的 IT 理想,而是因为他们看到了一个利用自己专业知识的机会,同时离开了 IT 领域。许多供应商根本没有真正的 IT 支持。
记住,供应商生产产品,而不是提供 IT 服务。因此,供应商通常能提供的支持与 IT 部门在其组织中应做的事情有很大不同。即使他们的员工拥有强大的 IT 资源,这些资源也不太可能被允许为客户提供真正的 IT 支持。供应商通常只希望并且往往只能在按预期操作其产品的非常狭窄范围内提供支持。IT 组织知道的关于供应商产品的知识,甚至如何最好地实施这些产品,往往与供应商知道的一样多或更多,这并不罕见。供应商根本没有必要掌握这些知识。比如,制锤工并不可能像木匠那样了解如何使用他们的锤子钉钉子。丰田的工程师也不太可能像职业赛车手那样驾驶他们自己的车。Canonical 相比你们的内部系统管理员,不太可能知道在你们的组织中如何最佳地部署 Ubuntu。
供应商的技能,主要是硬件工程或软件工程(或者两者兼有),与 IT 技能不同,即便是最优秀的供应商也没有特别的理由在 IT 任务上表现出色。那根本不是他们的擅长领域,他们为什么要具备这些技能呢?这不是他们业务的一部分。对于我们这些从事 IT 工作的人来说,这才是我们的业务。
供应商应该擅长的,并且通常也擅长的,是了解他们的产品。他们知道什么时候有缺陷需要修复,他们知道大多数公司在如何使用他们的产品方面的趋势,他们知道未来会有哪些变动(但可能无法向客户透露这些信息)。供应商是一个宝贵的资源,但前提是要在合适的逻辑框架下使用他们。
因为供应商卖的不是 IT 服务,而是产品,所以没有理由在任何规模上,甚至完全没有,保持高度专业化的 IT 资源。即便他们能够做到内部 IT 所能做的任何事情,这种想法也是相当荒谬的,根本没有意义。供应商在提供一定量的 IT 帮助时,通常会聘用中级和初级人员,因为没有必要聘用更昂贵的资源。来找供应商寻求 IT 资源的客户不可能把 IT 当作优先事项或做出合乎逻辑的选择,因此也没有理由为他们提供昂贵的资源——这些资源他们并没有准备好利用:销售低成本服务的利润远大于高成本服务。而那些足够成熟,真正需要高端 IT 资源的客户,通常知道不应该向供应商寻求这种帮助。
所以,没有什么魔法。供应商并不知道我们不知道的事情。通常,他们知道的内容要少得多,至少在我们环境中重要的东西,他们知道得更少。他们几乎没有获取必要的业务知识来做出合理的 IT 决策的权限。他们不能以跨行业的广泛技能和产品来处理问题或解决方案,而只能依赖他们提供的产品、互补产品以及鼓励更多使用其产品的流程。他们与 IT 的价值观没有对接,并且在财务上鼓励他们为自己的利益工作,而不是为你的利益工作。没有捷径,IT 资源应该提供的支持水平是无与伦比的,没有任何其他组织能够像你的 IT(通常应包括来自非供应商的外部 IT 资源)那样支持你的组织。
支持我们系统的方式本质上有三种。首先,我们有内部 IT 员工。根据本书的背景,这指的是系统管理员或团队。第二,我们有来自付费 IT 公司的外部 IT 资源,这些公司提供外部 IT 服务,而非销售服务,且他们为扩展内部 IT 团队而收费,可以是临时性的,也可以是长期的。第三,我们有供应商和增值经销商(供应商代表)。
我们必须记住,IT 不是一个特殊的例外,产品销售商也不是我们的商业顾问。就像房地产中的销售代理不能代表买方,买方代理也不能代表卖方一样,IT 领域也存在利益冲突和对立的代理关系。内部 IT 部门和任何外部 IT 服务提供商的职责是代表企业的需求,他们在法律和道德上都有义务这样做。另一方面,供应商和经销商通过销售利润或佣金获得报酬,代表供应商的需求,他们在法律上有义务这样做,从道德上讲,他们对供应商负责,而不是对客户负责。当然,这并不意味着供应商和经销商不能友好、有用、重要或专业,他们当然可以,也应该这样做。这仅仅意味着他们是产品销售商的代表,而我们作为 IT 专业人士,则是我们所服务企业的代表。
我们可以合作,最好的方式是理解彼此的角色和职责。在其他行业中,我们很少觉得销售人员或产品代表是为我们的最佳利益着想,而不是试图推广他们的商品,但在 IT 领域,这却是一个常见的混淆点。
当然,供应商及其经销商代表(准确来说称为 VARs,但常常以 MSPs 的身份出现,但要小心不要将真正的 IT 服务公司与那些只希望客户不质疑其名称的经销商混淆)可以是宝贵的盟友,我们不应完全忽视他们。他们可以成为我们解决方案的一部分,尤其是在获取特殊工具、测试版组件、补丁、发布信息、错误修复、更换硬件以及其他来自工程团队的组件(而不是 IT 处理的部分)时。
形象化 IT 负责的部分和工程负责的部分
即便作为 IT 专业人员,有时理解什么属于 IT 范畴,什么属于供应商工程(或软件工程部门)范畴,也可能令人困惑。但这里的答案应该非常简单。
作为 IT 专业人员,我们使用他人制作的产品,并将这些产品组装成完整的解决方案。我们不制作 Linux,我们不创建新的数据库引擎,我们不编写企业运行的应用程序。我们也不制造钣金,不运营芯片厂,或以其他方式制造计算机硬件组件,但在少数情况下,我们可能会购买部件并将其组装成计算机(就像机械师可能组装汽车零部件,但不实际铸造金属做零件一样)。
供应商负责制造 IT 部门负责使用和操作的工具和产品。供应商编写操作系统,我们在 IT 部门安装它们。供应商制作应用程序,我们安装它们。供应商参与的是产品的制造,而不是解决方案的创造。IT 解决的是组织性挑战,而不是生产产品。
如果我们谈论的是汽车,也许会更清楚。汽车供应商制造汽车。顾客乘坐汽车。这两者显然有着重要的相互关系,但显然,设计和制造汽车是一个非常不同的任务,而不是规划路线并开车到目的地。我们显然可以看到供应商为我们制造工具,而我们是使用这些工具来解决交通运输问题的汽车买家。将这种逻辑应用到 IT 领域,便能一目了然。
真正的支持,最重要的支持,始终来自我们自己的 IT 团队(这其中通常也包括外部 IT 工作人员)。我们自己的 IT 团队不仅具备做出关键支持决策所需的广泛业务知识,而且还拥有解决供应商限制的潜在解决方案范围。解决方案通常是一个单一产品供应商无法单独处理的。
举个例子,如果你是一家物流公司,需要将一个集装箱从纽约运送到洛杉矶,而你的卡车坏了,当然你可能会向卡车制造商咨询修理信息,但你不会就此止步。你会考虑更换卡车、租用卡车、寻找其他卡车供应商,考虑在维修期间使用其他物流伙伴为你运输,或考虑改用铁路或海运!在所有这些选择中,只有修理或许更换你的初始卡车,才可能是卡车制造商的支持范围,甚至从他们那里修理它的范围也远远不如你从修理工那里得到的帮助。一个熟练的修理工可能会提出部分功能的恢复、第三方配件,或者一些原厂供应商无法提供或批准的替代修理方案。原厂供应商在这里有其价值,重要的价值,但只是整体部门价值的一个小小部分。
处理大多数灾难需要更广泛的范围。我们很少愿意坐等供应商判断问题是否属于他们,然后再决定是否有有效的支持,再决定他们如何处理这个问题。即使是优秀的供应商,拥有出色的支持,相比于 IT 员工应该做的事情,他们的能力也是受到极大限制的。IT 部门拥有或应该拥有足够的权限,做任何必要的事情来保护公司。这可能涉及与现有供应商合作,或者可能需要绕过供应商,或者仅仅是协调多个供应商的工作。即使需要供应商介入,IT 部门也应当负责监督这些供应商。
IT 供应商管理
与其他 IT 部门相比,系统管理部门更常与供应商互动,也更需要直接监督这些供应商。同时,系统管理部门也是最可能没有任何供应商的部门,至少在传统意义上是如此。
供应商不应被视为一个部门,而更像是一个特定的工具。一个需要监督并在适当时使用的工具,但使用权和决定权在 IT 部门。单独的供应商缺乏方向和控制。
管理 IT 部门的硬件、软件和服务供应商应当是该部门的日常任务。这个层级的供应商关系非常重要,因为这是技术知识应当交换的层级。对于我们 Linux 系统管理员来说,这意味着与像 IBM Red Hat 和 Canonical 这样的供应商的操作系统供应商对接,他们可以让我们及时了解补丁、即将发布的更改、发布日期、安全警报等,有时也可能成为我们依赖的专门技术资源。
系统管理可能还涉及许多其他类型的供应商。我们可能需要与服务器硬件、存储、数据库,甚至应用程序供应商合作。供应商众多,强调了 IT 管理供应商的重要性。没有 IT 的监督,这些供应商之间没有协调,也没有要求他们进行合作或朝着共同目标努力。此时,推动业务发展的责任完全在于 IT。只有 IT 才能确保在适当的情况下,利用供应商资源为业务发展提供帮助,而不是让其成为供应商的销售行为。
最佳实践是支持应当来自内部。根本上,所有的核心内容应该是,我们应将 IT 团队(包括内部和外部工作人员)视为解决方案团队,不仅是为了前期设计解决方案,也是为了在出现问题时处理它们。当供应商需要参与解决方案过程时,他们应当由 IT 团队进行协调、管理和监督,并且作为另一种资源进行管理。
分类技能和人员
大多数公司在灾难发生时会遭遇严重失败,因为分类流程要么不存在,要么非常不完善。日常运营所需的技能与危机中实时决策所需的决策过程是不同的:几乎没有时间开会,几乎没有与不同方协商的能力,规划根本不可能进行。在这种模式下,我们需要的是一个值得信赖、能应对压力且更倾向于观察而非规划的人——一个能快速决策、且不需要提前规划事件的人。规划固然重要,合理的规划应尽可能提前完成,但从初级 IT 人员到高级管理人员,每个人都应该明白,真正的紧急情况是无法充分预见的,现实生活中会有很多未知情况需要即时评估。
当发生灾难时,我们的第一个过程就是进入分类模式。我们需要准确知道什么地方出了问题,发生了什么,影响是什么——基本上,我们需要知道一切的状态。我们认为这能在几分钟内解决吗?需要进行调查吗?人们受到了什么影响?我们在失去金钱、生产力或客户吗?
灾难可能会对我们产生多种影响。能够迅速掌握业务影响,了解各个部门在大局中的作用,哪些团队能正常运作,哪些团队处于停滞状态,哪些团队能运作但在艰难维持,等等,都是至关重要的。这一点可能意味着从大家都站在那里不知所措到一个分类经理迅速解决问题的巨大差异。我们需要状态信息,并且需要大量的信息,且非常迅速地获得。
在大多数情况下,我们真正用于解决技术问题的时间竟出乎意料地少。这可能是因为只是硬件故障,我们只需要等待替换硬件到达。或者可能是完全的软故障,我们只需重建系统。有时候,深入的技术调查是有价值的,而且确实需要很多专业知识来查找问题的根源,但这并非大多数情况。我们更可能遇到相对快速的修复,至少在管理员需要投入的时间上是相对快速的。当修复时间很长时,通常是因为需要等待第三方的支持。
通常,我们会将注意力集中在停机的技术方面。停机的其他方面通常更为重要。一些组织拥有操作分诊专家,他们介入并处理停机的这些方面,使我们作为系统管理员能够专注于我们职责范围内的技术问题。然而,对于大多数企业而言,处理 IT 灾难从头到尾都需要 IT 的监督。在大多数情况下,我们希望帮助 IT 解决问题并管理操作环境分诊的团队,反而成为了寻找解决方案的障碍,而不是解决方案的一部分。
我可以提供状态更新,或者我可以解决问题。
每个曾经处理过任何形式的停机、灾难或其他影响企业的事件的人都知道,预期的反应不是让高管和管理层冲进来,开始寻找保护企业的方式,或在你突然被指派处理问题时提供帮助,而是我们依赖的那些人,应该创造一个最小化影响的环境并让我们有效工作,但几乎普遍会转而要求我们提供解释、状态报告、更新、估算、承诺和奇迹,所有这些充其量是无用的,最坏的情况是完全破坏了业务。
即使在理想情况下,报告、状态更新、测量等也有成本,并且这些成本通常会从生产力中扣除,哪怕是极小的部分。在灾难发生时,除了那些在最关键岗位上试图减轻和解决灾难的人,很少有人能提供状态更新。所以,最常见的情况是,所有人都会集中在那些少数关键岗位上,要求状态更新。
这里有几个问题,对于我们这些从事这些职位的人来说,这些问题显而易见,但对于那些现在正在经历生产力受影响的人来说,往往是无法察觉的。我们有两种工具可以帮助解决这个问题。第一,把这本书展示给管理层,让他们花时间理解情况。第二是规划。确保在灾难规划和准备过程中,管理层有相关培训,以及政策和程序计划,明确如何提供状态更新、谁可以索取这些更新,以及从谁那里获取。考虑指定 IT(及其他部门)的官方发言人,他们可以将所有时间用于提供更新,因为他们不参与灾难恢复工作的其他方面。也许他们会亲自主持一个战情室,或者维护一个电子邮件消息组,管理一个聊天室,或者主持一个电话会议,其他人可以根据需要拨入。
然后,任何现有的更新可以主动传递给这些指定的报告人员,他们可以为组织维持这一状态。整个组织应当理解设立一个指定报告点的重要性,这样,真正试图解决问题并让公司恢复正常运作的团队,可以将时间用于拯救公司,而不是报告公司的失败。显然,企业有一些业务需求,需要尽可能多地了解发生的事情。更具影响力的是内部的政治问题,管理者会觉得他们也必须提供他们无法获得的状态,而组织中的多个层级往往会有情绪化的人,他们可能会故意造成重大的财务损失,希望看起来更关心,或只是为了满足自己想要知道更多信息的欲望。
在培训管理层时,解释为什么 IT(及其他部门)不能提供详尽的更新,我们需要他们理解,作为试图解决问题的人,我们不能花时间提供状态更新。
我们没有任何信息可以提供。基本上,这是这个问题的最大难点。虽然我们可能会有一个简单的答案,比如替换部件计划明天到达,但通常我们对修复需要多长时间一无所知。IT 中的大多数问题在我们知道是什么问题时,本质上就已经解决了。直到完全修复,我们通常只是从假设中工作。向我们索要信息,实际上就等同于要求我们故意提供虚假的信息,因为我们没有其他可以提供的东西。这就像是在折磨一个不知道任何信息的囚犯,如果你折磨他们,他们很可能会编造些东西,只是希望折磨能停止。
我们都很忙。如果事情还没有解决,很可能我们正在全力以赴地试图解决它们。用来提供状态更新的时间必须从解决问题的时间中挤出。这不仅仅是浪费时间,它还会造成中断,打击那些在解决问题的人士的士气。它传递了一个巨大的组织信息,那就是问题并不那么重要,而且解决问题的努力没有得到应有的重视。这会让 IT 部门产生*如果管理层都不优先解决问题,我们为什么要做?*的想法。
政治风险。在试图让所有想要获得灾难信息以便做出规划的人能够从那些正在解决问题的人那里获取信息时,他们通常处于一个非常困难的境地,需要大胆猜测最终问题何时能解决。大多数组织都会对这种无法避免的不确定性采取非常消极的态度。故意提供错误信息往往会得到奖励,而诚实则常常受到惩罚。将信息提供者置于可能不得不只告诉人们他们想听的或提供不准确的信息以保护自己政治利益的位置,意味着公司可能会用错误的数据运营,从而导致不必要的额外财务损失。在这个时候推动错误的数据而不是没有数据是非常糟糕的,但这正是最有可能发生的时刻。
优先事项。如果组织开始从管理层开始优先考虑那些报告、状态会议、电话和其他无法解决问题的事情,而这些事情并不能帮助公司恢复正常运转,那么这将自然而然地,也应该绝对改变 IT 或任何其他部门处理问题的方式。如果任何问题都是如此琐碎,以至于我们开会讨论时间表而不是修复系统,那么随着时间的推移,加班、重新安排家庭活动,甚至跳过午餐,都会成为显然对公司没有价值的 IT 牺牲。我们绝不会仅仅为了某个会议而做这些事情,如果那个会议比找到解决方案更重要,那我们就有了相对价值评估,能够帮助我们找到行动的方向。
那么管理层应该如何行动呢?管理层需要做完全相反的事情。如果状态更新重要,我们理解它通常确实很重要,那么就让那些没有参与修复工作的人来处理这些沟通。保持优先事项清晰。指定团队来进行干预,避免所有打扰到正在修复系统的团队成员。让人们为他们送餐、饮料、咖啡,或者做些杂务,无论需要什么——让他们感到重要,而不是暗示他们不重要。不要因为传递坏消息而惩罚信息传递者,要奖励他们的诚实。站在他们的立场,考虑对公司最有利的结果。
这些都是容易说却难以做到的事情,尤其是在灾难发生时。提前规划,进行这些讨论,制定计划,在事情发生之前获得高层批准。制定一个行动计划,明确谁负责,事情如何进行,等等。
我们的首个分诊阶段是评估。我们是否有一个快速恢复在线的计划?我们需要了解当前的情况,然后需要以某种方式将这些信息传达给管理层。从这里开始,情况变得复杂。由于变量太多,教学分诊并非易事。擅长分诊的人需要能够评估现有的情况,找出解决当前问题的方法、可行的替代方案,并且在许多情况下,如何调整组织以便更好地应对。
这的确是一个跳出框架思考的情景。此时我们需要从大局出发,找出如何最好地保持企业的财务运转。这看起来可能像是管理层的任务,理想情况下确实是如此,但 IT 部门也应发挥作用,因为我们具备一些其他部门可能缺乏的见解。
除了技术修复外,应对策略会根据业务类型、影响类型等因素有很大差异。我们是不是应该让大家去喝咖啡?也许计划一个长时间的午餐?现在就让大家去休假,以节省保险费用,因为可能要过一段时间才会有人重新变得高效?也许可以让大家从纸质工作转到即时消息,而不是继续使用电子邮件?利用一种任务的空闲时间来集中精力做其他任务。也许在大家有空的时候,我们可以进行一次彻底的办公室清洁——拔掉那些电缆,真正把地方清理干净。
大规模紧急情况也可能带来大机会。我曾多次看到公司将灾难性停机当作机会,执行本来需要长时间审批或会导致大规模停机的重大更新和变更,但这些操作可以在反正已经发生的停机事件中顺利进行。有一次,我甚至遇到一个 ISP 故障,预计会持续很长时间,结果一个团队从纽约开车赶往华盛顿 D.C.,将一排服务器装入卡车,赶到纽约一个准备好的新地点,成功地执行了一个本因必需停机而被无限期搁置的数据中心迁移,并在 ISP 恢复华盛顿 D.C.服务之前,将工作负载从纽约恢复上线。一次看似小规模的停机,反而变成了部门的巨大胜利。一个大项目在艰难地等待安排和审批时,恰巧作为意外的好处被成功执行,同时团队通过迁移到备用数据中心,克服了原始地点由 ISP 租用线路所带来的限制,实现了一个重要的修复。
急救很难,因为它要求我们具备创造性、开放的思维、避免恐慌、广泛地思考并跳出常规框架,并且通常没有太多的规划或准备。如果你的组织没有一个合适的人来担任这个角色,而实际上很少有人适合,那么这应该是你外包的工作,但系统管理员是最有可能胜任此角色的人,因为系统管理员的技能和素质往往更适合急救和灾难恢复,而非工程和规划。
在许多情况下,停机不仅仅意味着一个工作负载无法访问,还需要在技术领域进行优先级排序。你的急救人员或团队需要深入了解各个工作负载之间的相互关系,哪些依赖于其他工作负载,哪些可以绕过,哪些可以跳过,以及这些工作负载如何与业务本身相关。只有了解技术范围和业务的关系,才能为修复顺序、优先级排序以及业务如何潜在应对提供有价值的见解。
我希望我们能够提供具体的指导,告诉大家如何在灾难中生存,但我们做不到。灾难有各种形式和大小,我们应对它们的方法也更多。最好的方法是学习如何思考、如何反应,并尽可能为任何可能的情况做好准备。
急救人员的招聘:感知者
我曾经有幸在一个大型 IT 部门工作,在那里,深度心理分析是管理过程的一部分。这听起来可能是件可怕的事,但这种方法非常优秀,公司运用了适当的心理分析来了解人们的工作方式、他们如何一起工作、谁在不同领域可能是强者或弱者,以及如何最好地组合人员以取得最佳结果。
我不想详细讨论这些技巧在何种情况下有帮助或可能有帮助,但我想提到的一个具体概念是迈尔斯-布里格斯性格测试中的“评判者”和“感知者”量表。我不是心理学家,所以我建议你自行研究这个测试及其解释,并理解像所有心理学一样,它的有效性既被广泛接受,也受到激烈争议。我在这里不会辩论赞成或反对,只是想说理解“评判”与“感知”偏好对的确非常有价值。
我通常将评判者描述为一个计划者,喜欢在事件发生前整理和安排事物。感知者则更像是一个反应者或应答者,喜欢按部就班地接受世界的挑战,并在当下做出反应。
在我们的世界里,工程师和大多数经理人都是判断型人格(Judgers)。他们的角色和价值在于提前思考,并组织业务或技术,以便完成需要做的事情。知觉型人格(Perceivers)则往往更擅长做管理员,而不是工程师,他们正是你在灾难发生时所需要的人。知觉型的人格是处理紧急情况、临场应变的自然候选人。人类天生是多样的,彼此互补,共同应对生活的多个方面,这正是这一点的典型例证。
成为合适的人选或团队成员,远不止是符合某项能力测试中的个性类型。迈尔斯-布里格斯评估仅仅是一个工具,用来识别哪些人可能在不同职位上表现得强或弱,并解释人们通常如何思考和感受。对我而言,发现自己是一个强项知觉型和弱项判断型的人,帮助我深刻理解自己,也让我学会如何将我的特点传达给他人。它还为我提供了工具,帮助我理解生活中的其他人,以便更好地沟通,并在他们的行为与我不同的时候,设定更好的期望。
无论你的公司是否使用正式的流程,还是你仅仅通过在线调查来了解自己,我都推荐使用迈尔斯-布里格斯(Myers-Briggs)等工具,至少可以帮助你更好地了解自己。你越了解自己,就越能在擅长的领域做好准备,并在薄弱的地方寻求帮助。如果你是团队领导或经理,这类信息对于帮助你更好地理解团队成员以及他们如何协作以变得更强大也很有帮助。
不要过度解读心理学工具或试图将它们广泛应用。总的来说,这些工具在应用于自己时最有效,当你以开放和诚实的态度,带着学习自己弱点的愿望,而非仅仅是发现自己的优点时,使用这些工具能起到自我提升的作用。记住,这类测试并不是关于结果的比较,某个结果并不比另一个更好或更差;每个人都处于不同的维度中,维度的两端或中间都没有好与坏之分。然而,强大的团队通常由多种不同的能力和个性的组合组成,以满足多方面的需求。
我希望我刚才所说的能让你充满信心和灵感,让你能够将分诊过程提升到一个新的水平,而不是让你对处理灾难的复杂性和不确定性感到恐慌——这不是你应该从中学到的重点。把现在的恐慌当作动力,立即开始你的计划和文档工作,并与管理层展开对话,争取利益相关者的支持。把这作为优先事项,你可以迅速从没有准备好转变为在几乎任何情况下都能最佳响应的领先企业。
不要觉得必须由你来处理分诊工作。也许你是做这项工作的最佳人选,也许你不是。很少有人拥有合适的个性,而分诊是一项非常特殊的能力。重要的是要确定你的分诊人员或团队,不管他们是谁。每个人都有自己的角色,找到你的定位,并找到合适的人来填补你需要的角色。
关于人员配置的最佳实践是,在灾难发生之前就确定你的分诊人员,并确保他们的角色已被文档化并随时可以接管,且有足够的权限在时机成熟时接管。不要等到停机时钟开始倒计时时才开始寻找具备分诊能力的人,也不要让政治成为焦点,而不是解决方案,因为时间至关重要。
故障排除的逻辑方法
作为系统管理员,可能最困难的事情就是故障排除。能够最初部署一个系统是一回事,但当问题出现时,能够排除故障则完全是另一回事。在系统管理中,我们有太多地方可能出问题;我们坐落于众多技术和无数可能性交汇的地方,追踪问题的源头可能非常具有挑战性。
毫不奇怪,经验使得这一切变得比任何事情都容易。你在维护和管理系统上经验越丰富,就越能快速地感知一个系统,并且通常能够在情况变得复杂时就能感觉到可能出问题的地方。没有什么比真正了解一个系统在正常情况下的反应以及根据其行为感知问题更有价值了。资深的诊断专家通常正是因这一点而被召集。通过足够的经验,你往往能直觉地感觉到是索引、缓存、磁盘或内存不足的问题。
除了纯粹的经验,我们的下一个最佳工具是深入理解我们自己的系统及其相互作用、对适用于我们情况的技术基础知识的深入了解,以及逻辑性的故障排除方法。
当然,在许多情况下,故障是迅速且明显的。停电了,硬盘坏了,关键的数据库被删除了。没有什么需要追踪的,只有需要解决的事情。但在其他时候,我们会遇到一些复杂的问题,可能由几乎任何因素引起,我们可能需要追踪到一个真正难以定位的问题。
让我吃惊的是,我经常被叫来协助故障排除,但发现已经做过的工作往往是杂乱无章的,而且通常存在冗余。当然,有时候,一些对容易测试的故障点的猜测,或者对已知常见故障点的早期测试,确实能加速发现问题,但我们必须小心,不能迷失方向,而是要从我们测试的内容中系统性地学习。
故障排除的故事
作为作者的一个好处就是我可以和你分享我自己的故障排除历史故事,而且没有人会翻白眼或者打断我,你也不能在感到无聊时就离开。所以,来吧。
有一次,我被叫去处理一个用于超低延迟应用的系统,团队发现应用在接收其他系统响应时会偶尔出现问题。问题是在每隔几分钟后,响应会比预期晚几纳秒到达。没错,纳秒!没有任何崩溃,结果也没有错误,只是有一个非常微小的延迟,且并不常发生。
经过大量研究,我们最终通过研究和系统理解的结合找到了问题。最终,通过数小时盯着 top 命令的监视器,观察在延迟发生时活跃的进程,我们成功地找出了问题。
最终,经过缩小可能的过程范围,发现内核中一个很快被废弃的内存垃圾回收过程在其默认设置下消耗了过多的系统资源,并导致系统在处理内存清理时暂停几纳秒。
我通过将垃圾回收过程设置为每次清理部分内存,使其运行得更快,从而解决了这个问题。之所以会出现这个问题,是因为服务器上有大量物理内存,导致垃圾回收过程占用了可测量的时间,而这通常是意料之外的。
在这种情况下,良好的研究和耐心无疑是重要的。能够基于测量工具感觉到系统中的延迟(没有人能真正感觉到如此短的延迟),然后运用逻辑推理来判断进行内存垃圾回收的过程如何以及为什么会影响这种性质的进程,所有这些必须结合起来才能使故障排除成为可能。如果没有对系统运行机制的深入理解,这是不可能做到的。
在进行故障排除时,我发现有两个关键技巧我总是反复告诉大家使用。第一个是要有条理,工作时从一端或另一端开始。避免四处跳跃或随意测试。例如,如果你在测试网络连接,可以从网络栈的近端开始,并基于测试逐步建立知识基础。
在网络故障排除的例子中,我们可以从检查网络连接是否正常开始:它是否有 IP 地址?能否 ping 通网关?ISP?公共 IP?是否能够解析 DNS?是否能访问它应该连接的系统?是否能够访问正确的端口?是否得到了合适的响应?
与其四处跳跃进行不同的测试,不如从最近的点开始,逐步探索,这样有助于我们准确地了解问题在哪一刻发生了故障,并迅速给出反馈。
另一个我总是教给大家的关键技巧是从已知的事实开始工作。基本上,要先确认事实。你可能有很多不知道的事情,但不能因此而担忧。这些未知总是存在的。然而,总是有一些你可以确认的事实,我们必须从这些已知的事实开始,利用它们来逐步建立更大的知识体系,找到越来越多我们能确定的事情。
例如,如果你能 ping 通远程服务器,那么你就知道你的网络连接、路由工作正常,且你和远程服务器之间的所有设备都在正常工作。或者,如果你知道某个特定的数据库正在运行并且一切正常,那么你也知道它的操作系统在正常运行,承载它的虚拟化管理程序也在正常运行,而虚拟化管理程序所安装的裸金属服务器也在正常运行。
让我感到惊讶的是,在故障排除过程中,人们总是会花时间确认事实,但之后又质疑这些事实。在上面的例子中,他们可能会觉得看到一个问题后,可能是虚拟化管理程序出现了故障,然后再次去检查它,尽管他们刚刚已经证明它依然在正常工作。或者在网络问题中,他们可能会说服自己需要检查一个路由器的状态,而他们之前刚刚用这个路由器验证过网络是否能正常通过。
深入“兔子洞”并让自己(或团队)一遍又一遍地证明你已经知道的事情是否正常,是在浪费时间,最好的情况下,这会非常令人沮丧。一旦你开始反复确认自己已经确定的事实,而不是去探寻新的信息,你很可能会一直这样做。很容易将注意力集中在这些事情上,从而忽略了扩展与当前问题相关的知识体系。
我发现,将我们知道的事实写下来,无论是作为起点还是从调查中得出,都是一个很好的工具。如果我们觉得必须再次测试我们已经证明的某个事情,那我们就有问题了。为什么我们不信任已经证明的事实?如果现在我们怀疑它,那当初为什么觉得它已经证明了?如果我们不打算相信测试结果,那测试又有什么意义呢?
如果我们测试、证明,然后又在原地打转,那就是无意义的时间浪费,而在系统停机期间我们是无法承受这些浪费的。我们要么需要以不同的方式看待我们认为是事实的事情,要么就需要信任这个评估。通过建立可信的事实,我们可以利用它们来缩小可能的问题范围。
故障排除之所以困难,一方面是因为它非常技术性,许多因素可能未知,另一方面也因为在压力甚至是恐慌的情况下进行的操作带有情绪性。通常,这种情况还会被我们组织的额外需求和压力加剧。保持清醒的头脑是关键。深呼吸,集中精力,喝点咖啡,把问题说出来,发布到技术同行评审社区和论坛,甚至可以与供应商沟通。把你的资源写下来,因为在紧张时容易忘记步骤。
技术社交媒体在问题解决中的作用
超过二十年来,我处理严重问题的一个最强大的资源竟然是技术社交媒体。我并不是指传统的社交媒体平台,而是专门为技术思想交流建立的论坛。当面临设计挑战或更重要的,系统故障需要修复时,我发现对我和我的团队来说,将这些问题发布到论坛上是非常宝贵的。
这一点之所以如此重要,原因并不总是显而易见的。最明显的好处是,许多经验丰富的专业人士愿意为你的问题提供新的视角,可能轻松发现你忽略的某个细节,或者提供一些见解或建议一些你之前不知道的工具。
然而,真正的好处在于请求帮助的过程。往往,必须写出问题所在、需要清晰表达并记录我所采取的步骤的行为本身,会让我在别人回应我之前,自己就能发现问题所在。将步骤写下来鼓励我更加有条理,也让我考虑到别人可能会问的显而易见的问题,这促使我尝试填补空白,遵循良好的流程,并记录比我平时为自己做的更多的内容。
我也会将这个公开评审的过程用于我的团队,并要求其他人也这么做。当然,有些细节不能公开发布,有时候即使没有可识别的细节,整个过程也过于敏感,不适合公开,但通常至少有一定程度的灾难可以公开供他人协助审查。使用这种方式在团队内部进行沟通非常有效,并且鼓励大家认真思考已做的工作,尝试不同的方式解释问题,并迫使团队成员之间对故障排除过程的文档进行更清晰的记录,因为即使是文档过程也会在实时中公开审查。
这个相同的过程随后提供了故障排除的文档和自动时间线,用于事后分析。我经常也邀请事后分析的审查,通常是通过相同的机制进行非正式的审查。人们总是乐于批评决策。你必须准备好接受一些严厉的评价。
没有人比我更支持在专注的环境中进行公共同行评审的价值了。我从 1990 年代末开始倡导这一运动,并在这些社区中通过公共平台度过了我的职业生涯。它教会了我很多我从未接触过的东西,并且迫使我以不同的方式工作,因为我知道我所做的一切都将被审查、评估和质疑。准备好解释每一个决策,捍卫每一个结果,依靠逻辑和数学来支持你的决策,无论是赞成还是反对,因为你的论点将永久记录供审查,这会促使你重新思考自己的话语,我相信,这也促使你在所有工作中变得更加优秀。因为当你认为没有人会质疑你,或者没有人会注意时,很容易做出不合理的论点。
故障排除的最佳实践很简单:要有条理,记录一切,并在需要依赖资源之前将其准备好。
接下来,我们将探讨何时开始执行这个过程是合理的,或者我们是否应该直接从头开始。
调查与修复
当我们开始处理宕机、数据丢失或其他灾难时,最自然的倾向是集中精力找出根本原因,修复这个根本原因,然后将系统恢复到正常状态。这是合乎逻辑的,是显而易见的事件进程,且情感上也令人满足。
这个过程的问题在于它基于一些错误的信念。这是一种源于像汽车或房屋在受损或发生事故后进行维修的做法。其基本原则是,相关的物体或系统非常昂贵,而修复相对便宜。
它还侧重于确定发生某些问题的原因的价值,胜过让系统重新运行的价值。假设如果某件事发生过一次,它很可能会再次发生,通过了解发生了什么和为什么发生,我们可以避免未来几乎不可避免的重复故障。
当然,在 IT 和商业系统中,通常构建的成本低于修复的成本。更重要的是,构建的成本比修复更具可预测性。如果我们进行了良好的规划和文档记录,我们应该能够在已知的时间内,以极高的可靠性实现新系统。修复问题可能很快,也可能不快,它代表着许多未知因素。修复可能需要很长时间,而且修复可能不可靠。根本原因分析可能是耗时且不可靠的。
在大多数情况下,尽快让系统恢复运行具有很大的价值,而确定问题发生的原因并找到未来避免它的潜在方法的价值较小。商业基础设施在硬件、软件和系统设计等各个方面经历着巨大的变化。今天发生的硬件故障不太可能以相同的方式重复发生。软件可能会被快速修补、更新和修改,虽然担心旧的 bug 会重现是可能的,但这并不是值得过多关注的情形。
如果我们处理的是汽车、房屋、道路、桥梁或其他此类大型物体,故障可能会随着时间的推移在系统几乎没有变化的情况下再次发生。我们需要确定故障点,评估重复发生的风险,并找到防护措施。很难摆脱这种思维方式。
我们必须评估对业务的价值。让系统恢复运行的价值是什么?找到根本原因的价值是什么?我们需要比较这些价值,通常情况下,我们会发现解决方案优于调查。
当我们拥有更现代化的基础设施,包括镜像系统、状态机和基础设施即代码时,修复与调查的决策将越来越偏向修复。我们的自动化质量越高,重建系统的速度越快、成本越低,调查问题的价值就越低。
我们还必须考虑到,凭借合适的基础设施,我们可以重建一个镜像系统,用于必要时的诊断。我们可以创建一个初步重建来让系统重新运行,并在有意义的情况下创建一个镜像,以便用来尝试重现故障,并确定是否有方法或原因来防止未来的类似故障。在停机期间,花费时间尝试识别原因并修复问题,可能并不是实现这一目标的最佳方式,即使它被认为是必要的。
这完全是成本分析,但必须非常迅速地完成。这里的未知因素是非常困难的难点,因为确定根本原因的时间完全不可知,可能需要几分钟,也可能需要几天。
这种从头开始的逻辑不仅适用于桌面,也适用于服务器。即使是最终用户工作站,也有机会做到可互换,并设计成能够快速重新部署的方式。如果我们使用镜像、自动化软件安装和其他自动化方式,那么桌面、笔记本或任何我们为最终用户使用的设备,都能在几分钟内进行新的部署。全新的部署不仅仅是让这些系统以最大效率恢复运行,它还提供了一个全新安装的机会,作为额外的福利。任何可能发生在机器上的冗余、恶意软件、损坏或类似问题都会被清除,最终用户将像机器刚从生产线下线一样全新地开始。通过这种方式,我们得到了一个银色的边际:一个全新的重建过程,我们通常很难安排,但理想情况下,我们应该定期进行。
可重建的系统,无论是桌面、服务器还是云实例,都意味着我们只需要可用的硬件就能从大多数灾难中恢复并继续前进。这也意味着,假设我们的备份存储在某个在线或异地的位置,我们有能力进入一个新的站点,并在那儿重建整个公司。这种灵活性和舒适感是一个改变游戏规则的因素——几年前,几乎没有公司能考虑到这一点。知道从 头开始 重新开始始终是可能的,让我们在灾难恢复中完全不同地看待我们所做的一切。
根据我的经验,即使是在十五年前,在我们拥有今天这种自动化和复杂环境之前,我们几乎完全被迫 仅仅快速恢复,只有在恢复上线后才进行检查,而实现这一点的能力从那时起就一直在增强。今天,在几乎所有情况下,我们应该把从头重建作为默认的假设起点,只有在情况要求时才 resort 更复杂的恢复方式;我们还应该仔细评估今天为什么会有这样的需求。这并不意味着重建应该是我们工具箱中唯一的工具,重建是大多数情况并不意味着它是唯一正确的解决方案,只是它最有可能是正确的。
传统上,重建存在某种污名化,好像这意味着我们放弃了或是力不从心。我们必须抗拒这种不正确的情绪反应。恢复环境的正确方法是创造对整个组织最有利的局面。就像我们做的所有事情一样,情感在这里不起作用。这只是一个财务和风险计算的问题。我们做的是对公司最有利的事,仅此而已。
最佳实践:
-
评估每种情况,但在低谷时,应倾向于彻底重建。没有一种方法适合所有情况,但在大多数情况下,重建应该是更好的选择。
-
设计系统时要确保它们能够快速、轻松、自动地重建。
概要
灾难恢复、紧急分类、为紧急情况配备适当的人员、组织准备工作、在灾难情境下的管理过程监督,以及应对关键故障场景的其他各个方面都是困难、令人恐惧且压力重重的。公司如何处理这些时刻,往往决定了哪些公司能生存下来,哪些公司会失败。我们必须确保有合适的人在岗,尽可能多的组织流程和程序,出色的文档,深入的系统知识,以及应对困难时期所需的灵活性,以使公司度过难关,取得真正的成功。
每个公司都在与这些问题作斗争。这些不是我们能一夜之间就能应用的简单战术。它需要组织利益相关者的支持,需要专业精神和规划,不仅在事件发生之前,而且在压力使几乎每个人都可能做出非理性行为的恐慌时刻,也要维持这些流程和专业精神。从一方面来看,我们可以将此视为充满压力和困难,但从另一方面来看,我们可以认识到它的本质:这是几乎所有组织都在挣扎的地方,大多数组织失败,而这是我们闪耀的最大机会。
灾难规划和灾难恢复无疑是你承担系统管理角色并将其发展为比原本角色更大,甚至通常比 IT 部门本身更大的机会。你无法仅将灾难准备工作局限于 IT 部门;它需要跨部门的合作。系统管理可以领先,而不是跟随,使 IT 成为应有的核心业务单元。
我意识到,对于许多人来说,IT 部门的能力和范围深受政治因素的影响,难以轻易变得灵活。挑战自己,至少要评估并考虑一下,推动组织朝新的方向发展需要什么。没有任何组织应该强迫 IT 戴上销售帽,仅仅为了说服组织做对自己有利的事,但在现实世界中,我们推销自己、我们的部门和我们的想法的能力,往往决定了我们是否会被誉为公司的救世主,或者只是被忽视。
记住,解决方案来自于你,而不是供应商。牢记供应商及其范围,并记住,虽然灾难是你挽救组织的绝佳机会,它们也是供应商在恐惧和情绪主导下找到新销售机会的巨大机会,此时周全的规划几乎不存在。重新思考你如何看待供应商,把支持关系的背景放在心中最重要的位置。时刻了解谁代表了你的利益,谁在寻找你为他们提供服务的最佳机会。
事后分析
在总结中加一个边栏可能显得不合适,但我认为事后分析本身就像是灾难的总结。那么为什么不在这里讨论一下呢?
大多数公司跳过了执行事后分析这一极为重要的任务。事后分析不是为了归咎于谁,如果公司想要用它来做这种事情,那么最好避免进行事后分析,但在健康的组织中,它们作为一个多层次的关键学习工具。
一次好的事后分析将揭示系统设计、文档、规划、政策、流程以及我们系统的几乎所有其他方面的错误。它还应该帮助我们识别在危机期间表现强或弱的人员。我们应该通过事后分析过程来发现我们在哪里存在弱点,如何改进,或者有可能决定不做任何更改。
事后分析还应允许我们评估导致我们今天处境的决策过程。这几乎是普遍被忽视的,而实际上这才是事后分析真正的价值所在。改变个别计划或决策的结果是好的,但通常只是微小的,但发现整个决策过程的失败则为我们提供了一个机会,能够对所有未来的决策产生影响并进行改变。
学会做决策很重要,但很少有组织或个人关注决策过程的质量,更少的公司跟踪并试图随着时间的推移改善这一过程。这是一个巨大的失误。决策是一个不断发生的过程。定期做出更好的决策比修正个别决策更为重要。
事后分析需要深入探讨我们为什么做出当初的决定,然后评估这个决定是否正确,但我们不能陷入用当前的知识来评判过去的决定的陷阱。如果我们早知道的话这种推测游戏是非常危险的。我们必须评估当时我们能知道什么,并确定是否做了足够的调研、是否充分考虑了、是否应用了真正的商业目标等等。
在事后很容易做出推测并说看,事情失败了,我们损失了钱,这是某人的错。从情感上看,这似乎是必须正确的,但实际上并非如此。它可能是对的,但这通常不是一个有生产力的判断。坏事发生了,风险是商业的一部分,并非总有某个人在背后导致这些坏事的发生。在 IT 行业,我们每天都在处理经过计算的风险。在事后分析中,我们需要知道的是我们是否做出了正确的计算并抓住了正确的机会。
一个关于良好风险的好例子是我们需要从纽约旅行到洛杉矶。我们可以乘飞机,也可以开车。如果我们主要关注旅行中的安全,飞行会让人感到害怕,而开车则似乎一点也不可怕。然而,在这么长的距离下,发生车祸的死亡几率远远高于飞机失事的风险。如果我们坐飞机,而飞机确实发生了坠机事故,我们可能会用这次飞行即将坠毁的知识来判断,正确的决定是应该开车,但那是错误的。飞行依然是正确的决定。这两种方式都有风险,而飞行的风险明显较低。我们之所以会用这次飞行会坠毁的知识,是因为在事前无法知道这一点。我们是在规避风险,做出了正确的决定;但没有任何选项是没有风险的,而因为做出了正确选择而惩罚别人,是一种糟糕的结果。
人们需要因做出艰难决策而获得奖励,尤其是在他们做出了正确的艰难决策时。如果我们寻求归咎于某人,就有可能因为某人做出了任何决定而惩罚他们。如果我们这样做,就会推动他们避免那些有助于保护业务的决策,以避免成为错误指责的对象。当然,如果做出了真正糟糕的决策,我们是希望能够发现的。保持专注于组织和个人改进,而不是将事后分析用来寻找替罪羊或推卸责任,确实是一个非常困难的任务。
如果正确使用,事后分析是一个强大的工具。如果使用不当,它会浪费时间,甚至可能更糟。即使组织没有能力进行良好的事后分析,也可以仅在 IT 部门内部进行。如果 IT 部门本身存在让这种分析不可能的政治因素,也可以仅在系统管理层内部进行。即使没有其他人参与,也要为自己进行事后分析。
记录你的事后分析。人们倾向于消极地记住灾难,并情绪化地归咎于并不存在或不应承担责任的人。保持事后分析的文档,因为它通常在以后为保护个人、团队或流程提供帮助。即使是事后,良好的文档依然是一个强大的工具。
记住,事后分析不仅需要问我们是否能够避免这场灾难,还需要问*即便我们能,是否应该避免?*通常,避免灾难的成本往往大于灾难发生的风险成本。事后分析应当涵盖决策过程、决策本身以及对灾难的应对。
我希望本章中的思想和概念能帮助你打破传统角色的思维定势,拆除框架,让你在灾难恢复方面的方式体现出你和你的组织所能展现的最佳能力。
在关于 Linux 的书籍中,显然缺少对 Docker 和其他现代容器技术的讨论。这并非偶然,而是经过设计的。其原因在于,Docker 及其同类技术是应用容器技术,它们利用了我们已经讨论过的其他技术,而它们的实践则是它们自己的问题。从系统管理员的角度来看,应用容器只是另一种工作负载——它恰好使用了 Type-C 虚拟化并管理自己的依赖关系和更新。Docker 或其他应用容器管理超出了本书以及一般系统管理的范围。
在大多数情况下,系统管理员负责管理这些技术,但它们并不是特殊的案例。工作负载与我们在本书中讨论的其他工作负载相同。尽管它们可能有自己的名称、机制和管理工具,但所有这些仍然受到我们作为系统管理员应当已经掌握的一般情况准则和规则的约束。如果你打算与这些技术打交道,且如果你现在是系统管理员,几乎肯定会这样做,你将需要学习许多与应用容器平台及其管理工具特定相关的知识,并将这些知识应用到我们已经学到的内容上。
最佳实践专注于学习一般情况,即总是适用的规则,然后弄清楚不同的技术、技术方法和产品如何符合这些一般情况。
订阅我们的在线数字图书馆,全面访问超过 7,000 本图书和视频,以及行业领先的工具,帮助你规划个人发展并推进职业生涯。欲了解更多信息,请访问我们的网站。
第十三章:为什么订阅?
-
通过来自超过 4,000 位行业专业人士的实用电子书和视频,减少学习时间,增加编程时间
-
通过专为你打造的技能计划提高你的学习效率
-
每月免费获取一本电子书或视频
-
完全可搜索,方便访问关键信息
-
复制、粘贴、打印和收藏内容
你知道 Packt 提供每本书的电子书版本吗?PDF 和 ePub 文件可供下载。你可以在 packt.com 升级到电子书版本,并且作为纸质书客户,你可以享受电子书的折扣。有关更多详情,请通过 customercare@packtpub.com 联系我们。
在 www.packt.com,你还可以阅读一系列免费的技术文章,注册各类免费的新闻简报,并获得 Packt 图书和电子书的独家折扣和优惠。
你可能会喜欢的其他书籍
如果你喜欢本书,你可能对 Packt 出版的其他书籍感兴趣:
https://packt.link/9781789530384
](https://github.com/OpenDocCN/freelearn-linux-pt3-zh/raw/master/docs/linux-adm-bst-prac/img/9781789530384_Cover.png)](https://packt.link/9781789530384)
精通嵌入式 Linux 编程 - 第三版
Frank Vasquez,Chris Simmonds
ISBN: 978-1-78953-038-4
-
使用 Buildroot 和 Yocto 项目创建嵌入式 Linux 系统
-
排查 BitBake 构建失败并优化你的 Yocto 开发工作流
-
使用 Mender 或 balena 在现场安全更新 IoT 设备
-
通过阅读原理图、修改设备树、焊接突破板以及使用逻辑分析仪探测引脚来原型化外设扩展
-
无需编写内核设备驱动即可与硬件交互
-
将系统划分为由 BusyBox runit 监督的服务
-
使用 GDB 远程调试设备,并使用 perf、ftrace、eBPF 和 Callgrind 等工具衡量系统性能
https://packt.link/9781789951288
Linux 系统编程技巧
Jack-Benny Persson
ISBN: 978-1-78995-128-8
-
了解如何使用各种系统调用为 Linux 系统编写程序
-
深入了解 POSIX 函数的工作原理
-
理解并使用关键概念,如信号、管道、进程间通信(IPC)和进程管理
-
了解如何将程序与 Linux 系统集成
-
探索高级主题,如文件系统操作、创建共享库和调试程序
-
全面理解如何使用 Valgrind 调试程序
Packt 正在寻找像你这样的作者
如果您有兴趣成为 Packt 的作者,请访问 authors.packtpub.com 并立即申请。我们与成千上万的开发者和技术专业人士合作,帮助他们将自己的见解与全球技术社区分享。您可以提交一般申请,申请我们正在招募作者的具体热门话题,或提交您自己的想法。
分享您的想法
现在您已经完成了 Linux 管理最佳实践,我们很想听听您的想法!如果您是从 Amazon 购买的这本书,请 点击这里直接前往 Amazon 评论页面 为这本书分享您的反馈,或者在您购买书籍的站点上留下评论。
您的评论对我们和技术社区非常重要,将帮助我们确保提供优质的内容。
171万+

被折叠的 条评论
为什么被折叠?



