如果你使用Kubernetes作为应用程序的操作平台,那么你应该会遇到一些有关使用集群的方式的基本问题:
你应该有多少集群?
它们应该多大?
它们应该包含什么?
本文将深入讨论这些问题,并分析你所拥有的一些选择的利弊。
作为一个软件创建者,你应该开发并运行了多个应用程序。而且,你应该在不同的环境中运行这些应用程序的多个实例——例如,你应该有开发、测试以及生产环境。那么,不同的环境和应用程序的组合,我们可以得到一个“矩阵”:
在以上例子中,有3个应用程序和3个环境,两两组合为9个应用程序实例。每个应用程序实例是一个独立的部署单位,可以独立运行。
请注意,一个应用程序实例可能由多个组件组成,如前端、后端、数据库等。在一个微服务应用程序中,一个应用程序实例将由所有微服务构成。
那么作为一个Kubernetes用户,此时会遇到一些问题:
应该在一个集群中运行所有应用程序实例吗?
或者每个应用程序实例都应该有一个单独的集群吗?
或者应该以上两者相结合?
以上这些都是行之有效的方法——Kubernetes是一个灵活的系统,它并不会直接告诉你某一条指定的使用方法。
关于集群的搭配你有以下选择:
一个大型的共享集群
许多小型的一次性集群
每个应用程序有一个集群
每个环境中有一个集群
前两种方法分别是大型集群和小型集群的极端,其规模大小关系如下:
总而言之,如果一个集群包含了大量的节点和Pod,那么它就可以被定义为大于另一个集群。例如,一个有10个节点和100Pod的集群大于有1个节点和10个Pod的集群。
厘清了概念和选项,那么我们现在开始吧!
这个方法是指将你所有的工作负载都运行在一个集群中:
通过这种方法,我们可以像通用基础架构平台一样使用该集群——无论你需要运行什么,都可将其部署到现有的Kubernetes集群中。
Kubernetes中有一个命名空间的概念,可以 在逻辑上将集群的各个部分彼此分开。在上述情况下,你可以为每个应用程序实例创建单独的命名空间。
接下来,我们来看看这个方法的优劣势。
如果你只有一个Kubernetes集群,那么你只需要拥有运行和管理Kubernetes集群所需的所有资源的一个副本。这包含了master节点——一个Kubernetes集群通常有3个master节点。如果你只拥有一个集群,你一共只需要3个master节点(比起拥有10个集群,需要30个master节点来说轻松不少)。
当然了,肯定不止master节点,还包括其他集群范围的服务,例如负载均衡器、Ingress controller、身份验证、日志和监控。如果你只有一个集群,你可以为所有工作负载重复使用这些服务,并且不需要拥有多个副本。
由于上述原因,较少的集群通常更便宜,因为集群数量较大,意味着资源更多,因此会花费更多的费用。对于主节点来说尤其如此,这可能会用掉你大量的费用——无论你的集群是在本地还是在云中。
有一些Kubernetes托管服务会提供免费的控制平面,如Google Kubernetes Engine(GKE)或Azure Kubernetes Service(AKS),在这种情况下成本也许就不是问题。然而,有些托管的Kubernetes服务会为运行一个Kubernetes集群收取固定的费用,如Amazon Elastic Kubernetes Service(EKS)。
管理一个集群总比管理多个集群简单很多。管理集群可能包含以下任务:
升级Kubernetes版本
设置CI/CD流水线
安装一个CNI插件
设置用户身份验证系统
安装一个admission controller
等等……
如果你只有一个集群,这一切你只需要完成一次即可。如果你有许多集群,那么你需要将以上任务执行很多次,这需要你开发一些自动化流程以及工具,使其能够在所有集群中同步。
现在来说说缺点
如果你只有一个集群,如果这个集群恰好崩溃了,那么你的所有工作负载都会宕机。
有很多方式可能会导致出错:
Kubernetes升级过程中产生的“副作用”
集群范围的组件(如CNI 插件)无法正常运行
对集群的其中一个组件进行了错误的配置
底层基础架构发生故障
如果只有一个共享集群,那么只要类似的事情发生可能会对所有工作负载造成重大损害。
如果有多个app运行在同一个Kubernetes集群中,这意味着这些应用程序在集群的节点上共享硬件、网络和操作系统。具体而言,在同一节点上运行的两个不同的应用程序的两个容器是在相同硬件和操作系统内核上运行的两个进程。
Linux容器提供了一些隔离的形式,但这种隔离不如虚拟机所提供的隔离强。在后台,容器中的进程仍然只是在主机操作系统上运行的进程。
从安全角度来看,这的确是一个问题。从理论上讲,它允许不相关的应用程序(有意地和无意地)彼此交互。而且,在一个Kubernetes集群中的所有工作负载共享某些集群范围的服务,如DNS——它可以允许应用程序发现集群内的其他APP的服务。
以上所提到的这些也许会成为一个问题,也许不会,这取决于应用程序对安全性的要求。
Kubernetes本身提供了各种方法来防止安全漏洞,如PodSecurityPolicies以及NetworkPolicies。但是,要完全正确地使用这些工具需要一些经验,并且它们也无法防止所有的安全漏洞。
请牢记一点,Kubernetes是为共享而设计的,而不是隔离和安全。
既然在Kubernetes集群中有许多共享资源,那么许多不同的应用程序就可以通过各种方式互相挤占资源。例如,一个app可能独占了某些共享资源,如CPU或内存,因此导致同一节点上运行的其他应用没有资源可用。
Kubernetes提供各种方法来控制这一行为,如resource requests and limits、ResourceQuota以及LimitRanges。但是,同样地,要正确使用这些工具并非易事,而且它们也无法防止所有不必要的副作用。
如果你只有一个集群,那么在企业内部会有许多人必须得访问这一集群。越多的人访问,破坏的风险就会越高。
在集群内部,你可以控制哪些人可以使用基于角色的访问控制(RBAC)进行操作。但是,这仍然不能防止用户在授权范围内进行破坏。
如果你给所有的工作负载使用一个集群,这个集群规模大概率已经很大了(从节点和Pod的角度来说)。然而,Kubernetes集群无法无限扩大。理论上,集群的大小是有上限的,在Kubernetes中的定义大概事5000节点、150,000Pod以及300,000个容器。
然而,实际上,比上述规模更小的集群已经会开始面临诸多挑战,例如500节点。原因是较大的集群对Kubernetes控制平面造成了更大的压力,这需要仔细计划以保持集群的功能和效率。
接下来,我们来看看第二个选项——许多小型集群
使用这种方法,你可以为每个部署单元使用单独的Kubernetes集群:
在本文中,一个部署单元即为一个应用程序实例——如一个应用程序的开发版本。
通过这种策略,Kubernetes就可以像用于各个应用程序实例的专用应用程序运行时一样使用。
接下来,我们看看这种方法的优势和劣势。
如果一个集群出现故障,那么仅会损害运行在该集群上的工作负载,并不是所有工作负载都会受到影响。
各个集群中运行的工作负载不会共享资源,如CPU、内存、操作系统、网络以及其他服务。这样可以在不相关的应用程序之间提供强大的隔离,对于提升应用程序安全性十分有效。
如果每个集群仅运行一小组工作负载,那么就只需要更少的人访问这一集群。越少的人访问集群,集群出现故障的概率就越低。
接下来看一下这一方法的缺点。
正如之前所提及的,每个Kubernetes集群需要一组管理资源,如master节点、控制平面组件、监控和日志解决方案等。如果你有许多小型集群,那么你只能为这些管理功能牺牲资源使用的百分比。
低效的资源利用自然就会导致更高的成本。例如,如果你必须运行30个master节点,而不是3个才能获得相同的计算机功能,你看看每月的账单就能体会到这一点。
同时管理许多Kubernetes集群比管理单个集群要复杂得多。例如,你需要为每个集群设置身份验证和授权;如果你想升级Kubernetes版本,你需要执行这一操作很多次。你可能需要开发一些自动化流程,这样会使这些操作更高效。
接下来,我们看一下其他场景的集群。
使用这种方法,对于特定应用程序的所有实例,你都有一个单独的集群:
你可以将其视为每个团队单独拥有自己的集群,因为通常一个团队会开发一个或多个应用程序。
接下来,我们看看这个方法的优劣。
如果一个应用程序有特定的需求,这些需求可以在它的集群内安装,而无需影响其他集群。这样的要求可能包括GUI worker节点、一个特定的CNI插件、一个服务网格或其他服务。如此以来,每个集群都可以完全配备相应应用程序所需的配置——不多也不少。
这个方法的一个不足时来自不同环境的应用程序实例运行在同一个集群中。例如,应用程序的生产版本和开发版本都运行在同一个集群中,这意味着开发人员需要在生产版本应用程序运行的相同集群中工作。
所以,如果开发人员或一个有bug的开发版本在集群中造成了某些损害,那么生产版本绝对会因此受到影响——这是一个巨大的不足。
使用这种方法,你可以为每个环境创建一个单独的集群:
例如,你可以分别有一个开发、测试和生产集群,你可以在其中运行特定环境中的所有应用程序实例。
通常情况下,这个方法会使得所有环境彼此隔离,而这对生产环境而言十分重要。生产版本的应用程序现在不会受到其他集群以及应用程序环境的任何影响。所以,如果某些错误配置在你的开发集群中造成破坏,你的生产版本的app依旧可以持续运行,仿佛什么也没发生。
你可以为环境优化每个集群,例如:
安装开发和调试工具在开发集群中
安装测试框架和工具在测试集群中
给生产集群使用性能更好的硬件和网络
这样能够同时提升app的开发和运维效率。
没有人真的需要在生产集群内工作,所以你可以限制访问它。你甚至可以根本不向任何人授予生产集群的访问权限——可以通过自动化CI/CD工具对该集群进行部署。这将极大降低生产集群中人为错误的风险,这十分重要!
现在,来看看缺点。
这一方法的主要不足是应用程序之间缺少硬件和资源的隔离。不相关的应用程序共享集群资源,例如操作洗头膏内核、CPU、内存和其他服务。如上文所述,这可能是一个安全问题。
如果一个app有特殊的要求,这些要求则必须在所有集群中得到满足。例如,如果一个应用程序需要一个GPU,那么每个集群至少必须得有一个GPU worker节点——即便只有一个应用程序使用它。这会导致更高的成本和更低效的资源利用。
总而言之,如果你有给定的一组应用程序,你可以将它们运行在几个大型集群上或多个小型集群上。本文讨论了从几个大型集群到多个小型集群的各种方法的优缺点:
一个大型的共享集群
许多小型的一次性集群
每个应用程序有一个集群
每个环境中有一个集群
以下一张表格,总结了不同方法的优劣势:
所以你应该选择哪种方法呢?
通常情况下,这取决于你的实际用例——你必须权衡不同方法的优缺点,才能找到最合适你的解决方案。但是,选择不仅限于上述示例,也可以是它们的任意组合。例如,您可能考虑为每个团队建立两个集群:一个开发集群(用于开发和测试环境)和一个生产集群(用于生产环境)。
通过了解以上示例方案,您可以相应地结合特定方案的利弊。