2.4 基础设施
Kubernetes的部署是一个软件安装过程,对IT基础设施有依赖性。一个Kubernetes集群可以使用虚拟机或Docker容器在自己的笔记本电脑上启动。但这仅仅是一个用于测试的模拟环境。对于生产环境使用,需要有各种基础设施组件,它们通常是作为Kubernetes部署本身的一部分进行配置。
一个生产就绪的Kubernetes集群需要连接到网络的计算机来运行。为了保持术语的一致性,我们将使用术语“机器”来表示这些计算机。这些机器可能是虚拟的或物理存在的。而你需要面对的最重要问题是如何提供这些机器并且使它们上线。
你可能必须购买硬件并将其安装在数据中心。或者你可以简单地从云服务商那里申请所需的资源,根据需要来启动机器。最终,不管是什么过程,你都需要机器并且需要正确配置的网络。
作为自动化工程的一个重要部分,你需要仔细考虑基础设施管理的自动化。摒弃点击在线向导中的表单等手工操作。倾向于使用声明式系统,而不是调用API来实现同样的结果。这种自动化模型有按需配置服务器、网络和相关资源的能力,如AWS、微软Azure或谷歌云平台等云服务商。然而,并不是所有的环境都有一个API或网络用户界面来控制基础设施。大量生产环境中的工作负载在数据中心运行,这些服务器是由使用它们的公司购买和安装的。这需要在Kubernetes软件组件被安装和运行之前完成。重要的是,我们要做出这种区分,并确定在每种情况下都可用的模型和模式。
下面我们将讨论在裸机上运行Kubernetes与在Kubernetes集群的节点上使用虚拟机的问题。然后我们将讨论集群规模的权衡,以及对集群生命周期管理的影响。随后,我们将讨论你应该考虑到的计算和网络基础设施的问题。最后,我们将介绍一些具体的策略,以实现Kubernetes集群基础设施管理的自动化。
2.4.1 裸机与虚拟化
在探索Kubernetes的时候,很多人都在思考虚拟机层是否有必要存在。容器在很大程度上不是做同样的事情吗?本质上会不会运行了两层的虚拟化?答案是不一定。你需要通过选择正确的媒介部署,通过各种技术解决问题并且提升团队在这些技术方面的成熟度才能使Kubernetes在裸机或虚拟化环境上取得巨大成功,虚拟化革命改变了世界对基础设施的规定和管理方式。历史上,基础设施团队使用的方法有PXE启动主机、管理服务器配置,以及为服务器提供辅助硬件(如存储空间)等。现代的虚拟化环境将所有这些方法都抽象在API后面,资源可以被随意配置、改变和删除,而不需要知道底层硬件是什么样子。这种模式已经被VMware等服务商在整个数据中心和云计算(在云计算中,大部分计算都是在某种管理程序之上运行的)中证明有效。由于这些进步,许多在云原生世界中操作基础设施的新人可能永远不知道这些底层硬件的一些问题。图2-3虽然没有详尽地表现出虚拟化和裸机之间的区别,但展示了较多相互作用点的差异。
图2-3:配置和管理裸机计算基础设施与虚拟机时与管理员之间交互的比较
虚拟化模型的好处不仅仅是有一个统一的API来进行交互。在虚拟化环境中,可以在硬件服务器中建立许多虚拟服务器,使我们能够将每台计算机切分成完全等效的机器,在这里我们可以:
•轻松地创建和克隆机器和机器镜像。
•在同一台服务器上运行许多操作系统。
•根据应用需求,通过分配不同数量的资源来优化服务器的使用。
•在不影响服务器的情况下改变资源设置。
•以编程方式控制服务器可以使用的硬件,例如网卡。
•在每个服务器上运行独特的网络和路由配置。
这种灵活性也使我们能够在较小的基础上确定操作问题的范围。例如,我们现在可以升级一台主机而不影响其他所有在硬件上运行的主机。此外,由于虚拟化环境中的许多可用机制,创建和销毁服务器的效率通常更高。但是虚拟化也需要有一些取舍。通常,应用在虚拟化环境中运行会产生额外开销。许多对性能非常敏感的应用程序(如交易应用程序)可能更适合在裸机上运行。运行虚拟化栈本身也有开销。在边缘计算中,比如电信公司运行其5G网络的情况下,它们可能更希望不在硬件上运行。
现在我们已经完成了对虚拟化革命的简要回顾,让我们继续关注在使用Kubernetes和容器化抽象时,被迫使用更高层次的交互会对我们有什么影响。图2-4说明了在Kubernetes层通过操作员的眼睛所看到的情况。底层的计算机被看作一个“计算之海”,工作负载可以定义它们需要的资源,并将被适当地调度。
图2-4:Kubernetes与操作员的交互
值得注意的是,Kubernetes集群有几个与底层基础设施的集成点。例如,许多人使用CSI驱动(CSI-drivers)来与存储云服务商集成。当有多个基础设施管理项目时,可以从云服务商那里申请新的主机并加入集群。并且依赖于云服务商集成(CPI),它会帮助你做一些额外的工作,比如在集群外配置负载均衡器,在集群内路由等。
从本质上讲,基础设施团队在抛弃虚拟化时将会失去很多便利。而Kubernetes本身并不能解决这些问题。然而,有几个项目使得裸机的集成方式变得更加有前景。其中主要的部分是云服务商提供的裸机选项,并且像Packet(2020年3月被Equinix Metal(https://metal.equinix.com)收购)这样的裸机专用IaaS服务正在获得市场份额。但是,纯裸机集成也有一些需要解决的问题,如下所示。
较大的节点
较大的节点通常导致每个节点有更多的Pod。当每个节点需要数以千计的Pod来利用你的硬件时,操作会变得更加复杂。例如,在做就地升级时,需要操作每一个节点来升级,这也意味着你可能会触发1000多个重新安排的事件。
动态扩展
如何根据工作负荷或流量需求,让新的节点快速启动。
镜像配置
快速构建和分发机器镜像,以保持集群节点尽可能不变。
缺少负载均衡器API
需要提供从集群外部到内部Pod网络的入口路由。
不太复杂的存储集成
为Pod提供网络附加存储的方案。
多租户的安全问题
当管理程序发挥作用时,我们可以确保安全敏感的容器运行在专用的管理程序上。具体来说,我们可以将物理服务器任意分割,并在此基础上做出容器调度决定。
这些问题是确定可以解决的。例如,缺乏负载均衡器的集成可以通过kube-vip(https://kube-vip.io)或metallb(https://metallb.universe.tf)等项目来解决。存储集成可以通过与ceph集群的集成来解决。然而,关键在于容器并不是一种新的虚拟化技术。具体地说,容器是(在大多数实现中)使用Linux kernel基元,使进程貌似与主机上的其他进程隔离。虽然有无穷无尽的取舍需要解决,但本质上,我们在云服务商(虚拟化)、内部虚拟化和裸机之间选择的指导原则是:根据你的技术要求和组织的运营经验,考虑哪种选择最合理。如果Kubernetes被认为是虚拟化堆栈的替代品,那么你需要重新考虑Kubernetes到底解决了什么问题。记住,学习操作Kubernetes和让团队操作Kubernetes是一项任务。完全改变底层管理基础架构方式将显著增加工程量和风险。
2.4.2 集群的大小
Kubernetes部署模型的设计和基础设施的规划将与你计划使用的集群规模密不可分。我们经常被问:“生产集群中应该有多少个工作节点?”这是一个与“需要多少个工作节点来满足工作负载”不同的问题。如果你计划使用一个单一的生产集群来领导它们,那么这两个问题的答案将是相同的。然而,我们从未见过这样的情况。就像Kubernetes集群允许你把服务器机器当作牛一样,现代Kubernetes安装方法和云服务商允许你把集群本身当作牛。但每个使用Kubernetes的企业都至少有一个小牛群。
较大的集群有以下好处:
更好地利用资源
每个集群都有控制层面的开销成本。这涉及etcd和API服务器等组件。此外,你将在每个集群中运行各种平台服务,例如通过Ingress控制器进行代理将会增加系统的开销。而一个较大的集群可以最大限度地减少这些服务的重复。
更少的集群部署
如果你运行自己的裸机计算基础设施,而不是从云服务商或内部虚拟化平台按需提供,那么随着需求的变化扩展这些集群将变得不可行。如果不经常执行部署策略,那么集群部署策略的自动化程度就会降低。完成自动化集群部署的工程量将比管理自动化程度较低策略的工程量更大。
更简单的集群和工作负载管理概况
如果你有较少的生产集群,那么用来分配、联合和管理这些系统不需要那么精简和复杂。跨集群群组的联邦集群和工作负载管理是复杂且具有挑战性的,社区一直在努力解决这个问题。一些巨型企业的大型团队已经在这方面投入了大量的定制系统。到目前为止,这些努力取得了一些有限的成功。
较小的集群有以下好处:
更小的事故半径
集群故障将影响较少的工作负载。
租约的灵活性
Kubernetes提供了构建多租户平台所需的所有机制。然而,在某些情况下,你为特定租户配置一个新的集群,将付出少得多的工程量。例如,如果一个租户需要访问集群范围内的资源,如自定义资源,而另一个租户需要严格的安全或合规性的隔离保证,可能有理由将集群专用于这些团队,特别是在它们的工作负载需要大量计算资源时。
减少对规模的调整
当集群扩展到几百个工作节点时,我们经常需要解决规模的问题。这些问题因情况而异,但控制平面的瓶颈可能会出现。大量的工程量需要花费在故障排除和调整集群上。较小的集群可以大大减少这种开支。
升级选项
使用较小的集群可以更容易替换集群,以便对其进行升级。集群的替换当然有其自身的问题,这些问题将在2.8节中有所涉及,但这种替换策略在许多情况下是一种有吸引力的升级选择,而操作较小的集群可以使其更有吸引力。
节点池替代方案
如果你有专门关注的工作负载,如GPU或内存优化节点,而你的系统很容易容纳很多较小的集群,那么运行专门的集群来适应这些类型的专门关注的问题将是简单的。这就减轻了本章前面所讨论的管理多个节点池的复杂性。
2.4.3 计算基础设施
显而易见,一个Kubernetes集群需要机器。毕竟,管理这些机器的池是核心目的。你需要在早期就考虑应该选择什么类型的机器。多少个核心?多少内存?多少板载存储?什么级别的网络接口?是否需要专门的设备,如GPU?这些都是由你计划运行的软件的需求所驱动的问题。工作负载是计算密集型的吗?还是它们非常吃内存?你是否正在运行需要GPU的机器学习或人工智能工作负载?如果你的用例非常典型,你的工作负载很适合通用机器的计算-内存比率而且在资源消耗情况方面没有很大的差异,这将是一个相对简单的工作。然而,如果你有不太典型和更多样化的软件要运行,这将是一个复杂的问题。让我们为你的集群考虑不同类型的机器。
etcd机器(可选)
这是一种可选的机器类型,只有在你为Kubernetes集群运行专用的etcd集群时才适用。我们在前面的章节中介绍了这个选项的取舍。这些机器应该优先考虑磁盘读/写性能,所以千万不要使用老式的旋转盘硬盘。另外,即使在专用机器上运行etcd,也要考虑将一个存储磁盘专门用于etcd,这样etcd就不会与操作系统或其他程序争夺磁盘的使用权。我们还要考虑网络性能,包括网络上的接近性,以减少特定etcd集群中机器之间的网络延迟。
控制平面节点(需要)
这些机器将专门用于运行集群的控制平面组件。它们应该是通用的机器,根据集群的预期规模以及故障容忍度的要求来确定大小和编号。在一个更大的集群中,API服务器将有更多的客户并管理更多的流量。这些可以通过增加每台机器的计算资源,或者增加更多的机器来解决。然而,像调度器和控制管理器这样的组件在任何时候都只有一个领导者。增加这些组件的容量不能像API服务器那样通过更多的副本来实现。如果这些组件变得缺乏资源,就必须提高每台机器的计算资源来进行垂直扩展。此外,如果你在这些控制平面的机器上集中管理etcd,那么上面提到的关于etcd机器的考虑因素也适用。
工作节点(需要)
这些是一般用途的机器,承载非控制面板的工作负载。
内存优化节点(可选)
如果你的工作负载有一个内存配置文件,使它们不适合通用的工作节点,你应该考虑一个内存优化的节点池。例如,如果你使用AWS通用M5实例类型的工作节点,其CPU个数和内存大小的比例为1CPU:4GiB,但你有一个工作负载以1CPU:8GiB的比例消耗资源,这些工作负载将在你的集群中以这种比例请求(保留)资源时将会剩下未使用的CPU。这种低效率可以通过使用内存优化的节点来克服,如AWS上的R5实例类型,其比例为1CPU:8GiB。
计算优化节点(可选)
另外,如果你的工作负载符合计算优化节点的特征,如AWS中的C5实例类型(具有1CPU:2GiB),你应该考虑添加一个具有这些机器类型的节点池以提高效率。
专门的硬件节点(可选)
一个常见的硬件需求是GPU。如果你的工作负载(如机器学习)需要专门的硬件,那么在你的集群中添加一个节点池,然后将这些节点用于适当的工作负载,效果会很好。
2.4.4 网络基础设施
网络很容易被当作一个实施细节而忽略,但它却可以对你的部署模型产生重要的影响。首先,让我们来看看你需要考虑和设计的元素。
路由性
你几乎肯定不希望你的集群节点暴露在公共互联网上。能够从任何地方连接到这些节点是非常危险的。在你连接到这些节点之前,你需要解决如何访问这些节点的问题。一个允许SSH访问并允许你反向代理到集群节点且具有良好安全性的高防主机或跳板机是一个开销较低的解决方案。
然而,还有一些更细微的问题需要回答,比如你的私人网络上的网络访问。在你的网络上会有一些服务需要连接到你的集群,或者从你的集群连接到其他服务。例如,通常需要与存储矩阵、内部容器注册中心、CI/CD系统、内部DNS、私人NTP服务器等连接。即使是通过出站代理,你的集群通常还需要访问公共资源,如公共容器注册中心。
如果不可能访问公共互联网,那么这些资源(如开源容器镜像和系统包)将需要以某种其他方式提供。最好向更简单的系统倾斜,使其保证一致性和有效性。如果可能的话,尽量避免对集群部署所需的基础设施进行无谓的授权和人为批准。
冗余
在可能的情况下,使用可用性区域(AZ)来帮助维持正常运行时间。为明确起见,可用性区域是一个数据中心,它有一个单独的电源、备份系统和一个单独连接的公共互联网。一个数据中心的两个子网共用一个电源,并不构成两个可用区。如果两个不同的数据中心彼此相对接近,并且在它们之间有一个低延迟、高带宽的网络连接,则构成一对可用性区域。有两个AZ是好的,有三个则更好。如果有更多AZ则需要准备较高的容灾程度。数据中心已经有崩溃的案例,并且一个区域内的多个数据中心可能同时中断,但这种情况很少发生,而且通常意味着某种灾难。对于这种情况,则需要根据你工作负载的重要性来取舍。你是在运行国防所需的工作负载,还是在运行一个在线商店?还要考虑你在哪里需要冗余。你在为你的工作负载建立冗余吗?还是集群本身的控制平面?根据我们的经验,跨AZ运行etcd是可以接受的,但如果这样做,请重新阅读2.3.1节。请记住,将控制平面分布在不同的AZ上可以对集群冗余进行控制。除非你的工作负载依赖于集群的控制平面(应该避免),否则你的工作负载可用性不会受到控制平面中断的影响。会受到影响的是你对运行中的软件进行任何修改的能力。控制平面的中断不是小事,它是一个高优先级的紧急情况,但它与面向用户的工作负载中断是不同的。
负载均衡
如果你需要为Kubernetes API服务器配备一个负载均衡器。你有能力在你的环境中以编程方式配置吗?如果可以,你就可以把它作为集群控制平面部署的一部分来启动和配置。首先你需要考虑一下集群API的访问策略,以及随后你的负载均衡器将位于哪些防火墙后面。你肯定不会让它可以从公共互联网访问。通常,对集群控制平面的远程访问通常是通过VPN来实现的,VPN提供对集群所在本地网络的访问。另外,如果你的工作负载是公开的,你将需要一个单独的负载均衡器连接到你的集群入口。在大多数情况下,这个负载均衡器将为你集群中的各种工作负载提供所有请求的代理和转发。此外,为每个工作负载部署一个负载均衡器和集群入口的价值不大,因为这些工作负载会暴露在集群外部的请求中。如果运行一个专用的etcd集群,请不要在Kubernetes API和etcd之间放置负载均衡器。API使用的etcd客户端将处理与etcd的连接,它们不需要负载均衡器。
2.4.5 自动化策略
在为你的Kubernetes集群配置自动化基础设施组件时,你需要做一些与架构相关的决策。我们将把它分为两类:第一类是现在存在可以利用的工具;第二类是使用Kubernetes operators来解决该问题。由于裸机安装的自动化配置不同,我们做一个假设:你有一个API可以用来配置机器或将它们纳入Kubernetes部署的节点池中。如果没有,你将需要通过手动操作来填补空白,直到你拥有编程访问和控制权。让我们从你可能掌握的一些工具开始。
基础设施管理工具
Terraform(https://www.terraform.io)和CloudFormation for AWS(https://aws.amazon.com/cloudformation)等工具允许声明你的计算和网络基础设施的理想状态,然后应用该状态。它们使用特定的数据格式或配置语言,允许你在文本文件中定义你所需要的状态,然后告诉软件来满足这些文本文件中声明的理想状态。
它们的优势在于工程师可以很容易地使用工具获得结果。它们善于简化相对复杂的基础设施配置过程。当你有一套规定的基础设施需要反复使用,而且基础设施的实例之间没有太多的差异时,它们将表现出色。它非常适用于不可改变的基础设施,因为可重复性是可靠的,相对于特殊的改变而言,基础设施的替换会变得相当容易管理。
当基础设施的需求变得非常复杂、动态且依赖于可变条件时,这些工具的价值开始下降。例如,如果你正在设计跨多个云服务商的Kubernetes部署系统,这些工具将变得很麻烦。像JSON这样的数据格式和配置语言并不擅长表达条件语句和循环函数。这正是通用编程语言的优势所在。
在开发阶段,基础设施管理工具是非常普遍且成功的应用。它们确实也被用于管理某些生产环境。但是,随着时间的推移,它们的工作变得很烦琐,而且经常承担一种几乎不可能偿还的技术债务。由于这些原因,强烈考虑使用或开发Kubernetes operator来实现这一目的。
Kubernetes operator
如果基础设施管理工具施加了限制,需要使用通用编程语言编写软件,那么该软件应该采取什么形式?你可以写一个Web应用程序或者一个命令行工具来管理你的Kubernetes基础设施。如果考虑为此进行定制软件开发,强烈建议使用Kubernetes operator。
在Kubernetes的背景下,operator使用自定义资源和定制的Kubernetes控制器来管理系统。控制器使用一种状态管理的方法,该方法强大而可靠。每当你创建一个Kubernetes资源的实例时,负责该资源种类的控制器会收到由API服务器通过其观察机制发送的通知,然后使用资源规格中声明的期望状态作为指令来实现期望状态。因此,用代表基础设施关注点的新资源种类来扩展Kubernetes API,并开发Kubernetes operator来管理这些基础设施资源的状态是非常强大的。关于Kubernetes operator的话题将在第11章中更深入地探讨。
这正是Cluster API项目的意义所在。它是一个Kubernetes operator的集合,可以用来管理Kubernetes集群的基础设施。你可以利用这个开源项目来达到你的目的。事实上,我们建议你在从头开始一个类似的项目之前,查看一下这个项目,看看它是否适合你的需求。如果它不能满足你的需求,再考虑你的团队能否参与到该项目中来,帮助开发你所需要的功能或支持的基础设施云服务商。
Kubernetes为容器化软件部署的自动化管理提供了很好的选择。同样,通过使用Kubernetes operator也为集群基础设施自动化提供了相当大的好处。在此我们强烈建议你使用它,并在有可能的情况下,为Cluster API等项目作出贡献。如果你有自定义的要求,并且喜欢使用基础设施管理工具,你当然可以选择通过这个方法来实现。然而,由于使用配置语言和格式而不是全功能的编程语言的限制,你的解决方案将有较少的灵活性和更多的变通。