Kubernetes的原生多租户解决方案
Kubernetes提供一系列原生Kubernetes API与资源,用于帮助在单一集群内建立起多租户体系。下面,我们将介绍如何在计算、网络以及存储方面实现多租户资源隔离。
计算隔离
Kubernetes说明文档中将命名空间定义为“一种在多个用户之间分配集群资源的方法”,这也使其成为多租户机制的基础。大多数Kubernetes资源对象都属于一个命名空间。在下图中,我们定义了两个命名空间,每个命名空间各自运行一组彼此隔离的资源对象。
虽然K8S中并没有租户这样的概念,命名空间本身也不提供工作负载或用户的隔离,但是K8S除了以命名空间作为基础的资源隔离单位,还提供了基于 RBAC 的权限管理方式:RBAC用于定义谁能够在Kubernetes API上执行的操作。这种授权机制可以通过ClusterRole作用于整个集群,也可以通过Role作用于某个命名空间。例如,我们可以定义一个名为namespace1-admin的角色,该角色负责为管理员提供对namespace1命名空间的访问权限,同时将其与名为admin-ns1的组关联起来,具体操作代码如下:
Amazon EKS通过AWS IAM Authenticator for Kubernetes提供RBAC与IAM的集成功能,可以将IAM用户与角色映射至RBAC组。RBAC是Kubernetes的核心组件,负责控制其他隔离层的权限。我们将在后文中详细讨论。
Kubernetes允许用户对Pod的CPU与内存资源配额做出定义与限制。为了避免节点上发生资源争用,同时改善调度程序的资源分配,开发人员应始终设置资源配额。ResourceQuota资源配额允许用户定义和限制一个命名空间中可以使用的Kubernetes资源或对象的数量。从计算资源的角度来看,用户可以通过资源配额以原生方式定义CPU与内存限制,示例如下:
使用资源配额,可以为工作负载分配有限的资源,防止租户之间相互干扰。我们还可以通过Limit Ranges定义每个Pod甚至是容器的默认、最小与最大请求及其限制条件。
租户资源也应该保证与基础设施节点实例之间的隔离。Kubernetes Pod安全策略(PSP)是集群级的Pod安全策略,自动为集群内的Pod和Volume设置Security Context。Pod Security Policy定义了一系列Pod在系统中运行必须满足的约束条件,以及一些默认的约束值。这要求负责构建多租户集群的管理员通过PSP的Privileged确定Pod中是否可以启用特权模式。通过HostNetwork控制容器是否可以使用所在节点的网络名称空间,防止Pod访问回环设备和潜在的监听网络邻居的活动。自1.13版本起,Amazon EKS正式支持PSP,关于更多详细信息,请参阅AWS开源博客。
Kubernetes还提供多种Pod调度方案,在调度的时候考虑Pod与Pod之间的关系,而不只是Pod与Node的关系。例如,Pod Anti-Affinity允许用户使用以下设置保证带有特定标签的Pod不会被部署在同一节点之上:
在这里,namespace1中带有team: team-1标签的各Pod不会与在shared-services命名空间中拥有monitoring标签类型的Pod被部署在同一节点之上,这是为了防止业务应用与监控应用之间发生干扰。这里还有几点需要注意。首先,为了实现这项功能,我们需要保证在适当的工作负载上应用适当的标签。第二,这类配置可能提高大规模维护工作的难度,因为随着要求的增加与Pod量的提升,过度复杂的调度要求可能导致某些Pod找不到合适的部署节点。最后,Pod亲和性与反亲和性设定会给控制平面带来更高的工作压力,这里不建议大家在包含数百个节点甚至规模更大的集群当中使用。与此类似,我们可以使用nodeSelectors与nodeAffinity将Pod分配给特定节点。
但如果我们希望在调度Pod的时候排除某些节点,让这些节点只在特殊指定时使用,又该怎么办?这种情况就需要使用“污点(taint)和容忍(toleration)”的功能。在示例中,集群管理员可以使用以下节点组配置文件在EKS上创建专有的工作节点组,用于监控及管理工作负载:
通过使用污点,Kubernetes调度系统会避免调度不容忍这种污点的Pod到带有此污点标记的节点上。
另一种方式则是在EKS上使用AWS Fargate。Fargate在VM隔离的环境中运行每个Pod,而无需与其他Pod共享资源。从而消除了创建或管理EC2实例节点的需求。
网络隔离
在默认情况下,Pod可以在同一集群的网络上跨不同的命名空间实现通信。Kubernetes提供相应的网络策略,允许用户以细粒度方式定义并控制Pod之间的通信。网络策略的具体实现,由网络插件负责完成。在默认EKS集群当中,Pod到Pod间网络则被委派给Amazon VPC CNI插件实现,VPC CNI插件通过支持Calico来实现Kubernetes的网络策略。假设我们需要根据命名空间对各个租户进行隔离,则可以使用以下网络策略确保各租户只能在所在命名空间namespace1之内进行网络通信(换句话说,拒绝该集群之内不同命名空间之间的相互通信):
网络策略还提供更多高级配置,可用于限制多租户集群上的通信。关于更多快速入门以及环境设置指南,请参阅Amazon EKS说明文档中的相关内容。
我们还可以通过服务网格定义更多的保护机制,甚至可以将保护机制扩展到单一EKS集群之外。Istio是一个非常流行的开源服务网格技术,可提供流量管理、安全保护与可观察性等多种功能。Istio团队在相关博文中讨论了如何在多租户集群中部署Istio的详细信息。EKS Workshop还提供关于在EKS上设置Istio的快速入门教程。用户可以使用Istio在不同的网络层内实施对应的身份验证与授权策略。例如,大家可以将用于控制L3/L4网络流量的网络策略与L7层上基于JWT的令牌身份验证结合起来,更好地控制来自不同租户的服务间的通信方式。
AWS App Mesh是一种AWS提供的全托管服务网格,AWS App Mesh以Envoy为基础,实现了服务网格控制平面的全面托管,为客户提供了运行在AWS中应用程序的各项服务之间统一的可见性和网络流量控制的能力。关于App Mesh的实际效果,大家可以参考Amazon EKS快速入门中的相关测试。
存储隔离
在使用共享集群时,不同的租户可能需要不同的存储资源类型。Kubernetes提供不同的工具用于管理存储资源。其中最重要的当数Volume,它能够以持久性形式将存储资源接入Pod并管理存储资源的整个生命周期。正如前文“计算”部分所述,这里我们不建议直接挂载由节点提供的存储卷(大家最好在配合PSP的多租户设计中直接禁用掉对本地存储卷的访问)。下面,我们将向大家介绍PersistentVolume(PV)子系统的一些关键功能及其与PersistentVolumeClaim (PVC)的关系。
PersistentVolume(PV)是集群中由管理员配置的网络存储。它是集群中的资源,
,StorageClass也是如此。集群管理员实际上是以集中方式对可用的存储驱动程序、配置以及操作方式做出定义。在Amazon EKS中提供了不同的开箱即用的Storage Classes实现,具体包括Amazon EBS(既作为树内插件,又可作为CSI插件)、Amazon EFS以及FSx for Lustre。而PVC则允许用户根据存储类中的要求为Pod请求存储卷。PVC被定义为一个命名空间资源,并由此对租户的存储访问操作进行控制。管理员可以使用存储资源配额定义属于特定命名空间的存储类。例如,要在命名空间namespace1当中禁用对storagens2存储类的使用,则可按照以下方式使用ResourceQuota:
多集群间隔离
在实现多租户方面,另外一种可行的选项是使用多个只包含单一租户的Amazon EKS集群。通过这种策略,每个租户都可以在共享AWS账户(或者专供大型企业使用的专有账户)之内拥有只属于自己的Kubernetes集群。
每个集群既可以自行配置,也可以由运维管理团队统一提供,并部署标准化配置。如果选择后一种方法,那么运维管理团队需要高度关注两个问题:集群配置和多集群监控。
客户在使用Amazon EKS托管的控制平面的同时,可能还希望在新建集群上采用统一的配置标准。在这种情况下,Terraform可以与Kubernetes Provider一起配合使用,保证以自动化方式部署前文提到的PSP或网络策略。注意:EKS在每个区域内单一账户中设定了100个EKS集群的配额上限,但大家也可以根据需求进行更改。
在集群部署完成之后,我们可能还需要对所有已部署的多个集群进行审查,监控各租户运行状况、保证目前运行的EKS控制平面为最新版本且运行情况良好。Rancher是一款流行的开源工具,可用于管理多Kubernetes集群,这里建议大家参考开源博客上的讲解文章以了解Rancher部署与使用方面的详细信息。
总结
聊聊 Amazon EKS 集群上的多租户设计注意事项