Z.S.K.'s Records

Kubernetes学习(kubernetes中如何实现多租户模型)

某种程度上说,kubernetes是个共享的架构,旨在通过共享来降低成本,但实际中,多租户是个绕不开的话题, Kubernetes 没有终端用户或租户概念, 不过kubernetes也提供了几个特性来帮助管理不同的租户需求,社区也有一些开源实现, 作者通过实践来聊一聊kubernetes中如何实现多租户(Multi-Tenancy)模型

租户类型

multi-tenantcy | Kubernetes一文中提到,multi-tenantcy可以大体分为两种: Multiple teams or Multiple customers

  • Multiple teams: 多团队租户,一般存在于组织架构中, 有明显的层级结构,这类租户有相应的操作kubernetes集群的权限,偏开发及运维团队

  • Multiple customers: 指的是saas平台上的用户, 一般是终端用户,终端用户不需要能够访问kubernetes集群,kuberentes对终端用户透明。

但是并不一定绝对:

在讨论 Kubernetes 中的多租户时,“租户”没有单一的定义。 相反,租户的定义将根据讨论的是多团队还是多客户租户而有所不同。

在多团队使用中,租户通常是一个团队, 每个团队通常部署少量工作负载,这些工作负载会随着服务的复杂性而发生规模伸缩。 然而,“团队”的定义本身可能是模糊的, 因为团队可能被组织成更高级别的部门或细分为更小的团队。

相反,如果每个团队为每个新客户部署专用的工作负载,那么他们使用的是多客户租户模型。 在这种情况下,“租户”只是共享单个工作负载的一组用户。 这种租户可能大到整个公司,也可能小到该公司的一个团队。

在许多情况下,同一组织可能在不同的上下文中使用“租户”的两种定义。 例如,一个平台团队可能向多个内部“客户”提供安全工具和数据库等共享服务, 而 SaaS 供应商也可能让多个团队共享一个开发集群。 最后,混合架构也是可能的, 例如,某 SaaS 提供商为每个客户的敏感数据提供独立的工作负载,同时提供多租户共享的服务。

待决问题

总结一下多租户要解决的问题可能有:

这里说的是可能,原因为:不以业务需求为导向的技术落地都是空谈, 所以技术方案不存在好坏之份,只有适不适合

  • 是否可操作集群级别资源,如 API、CRD、RBAC

  • 配额管理是否在租户之间合理隔离

生产需求

这里以一个实际的综合需求展开说明:

需求: 公司有一个kubernetes集群,一个saas平台跑在集群中,这个saas平台提供一些工具给算法研究员,比如可以申请notebook实例(是一种独占资源), 可以发布AI任务(可以是个人任务,也可以是生产任务),但是算力总是有限的,不可能让一个研究员无限制地占用算力,因此,需要限制某个研究员最大的资源上限, 同时又要限制每种业务所使用的算力, notebook算是一种业务类型,AI任务也算是一种业务类型

  • 由于notebook是独占资源,研究员只要愿意可以启用无数个notebook实例,只要不超过设定的notebook这种业务类型的上限即可
  • 对于AI任务这个业务,研究员发起的AI任务都需要丢到一个共享资源池中(会有上限,整体采用先到先得策略), 需要限制每个研究员可以发布的AI任务资源上限, 也就是说,当达到给研究员设定的上限后,研究员再发起的任务需要排队,如果整个共享资源池到达上限后,所有研究员新提交的任务都进行排队.
  • 对于生产任务,资源需要尽可能倾斜

第2条需求听上去不太合理,先不用去质疑需求是否合理,因为需求方都是爸爸

大多数的场景下,需求可能只到限制某个研究员最大的资源上限即可,因为给定了上限,研究员可以自己安排资源要如何分配

对于kubernetes来说,saas平台本身是一种业务,会有它的开发/运维人员,这种算是团队租户,而研究员,则是saas的用户,对Kubernetes来说就是终端用户

这算是一个比较复杂的需求,kubernetes原生能否实现这个需求,我们一起来拆分需求

Namespace

kuberentes中, namespace有个resourcequota, 可以限制多种资源的使用,是一种硬隔离

额外插一句, 这里提到多种资源,是说resourcequota并不只能够限制cpu, memory等计算资源,configmap, pvc等其实都可以限制,这里不展开,可参考resourcequota

回到上面的需求, 使用namespace能否实现上面的业务需求??

如果只从技术实现来讲,一定程度可以的,但是从运维友好角度来说,显然不行, OP同学会疯掉

对于一个研究员来说,他对应多种业务,每种业务都有上限,那么就可以给这个研究员创建N个namespace, 每个namespace对应一种业务,设置上限,这样可以控制某种业务的上限使用,研究员发布的任务会落到对应的namespace中

但还有一个问题即共享资源池问题,研究员都在自己的namespace中,相当于将大的共享资源平摊到多个namespace中,这样的话有没有这个共享资源池影响也不大

这是一种很粗糙的解决方案, 一方面如果研究员基数大、业务类型多,这是个NxN的结果,且如果这个配额是个动态可变的,那么在运维友好性方面将是灾难
显然,只有namespace还不够,有没有更好的解决方案呢?

kuberntes中,已经有多种多租户模型,硬、软隔离都有开源实现,大体就两种思路:

  1. 控制面隔离
  • 多集群/多APIServer: 借助多个集群进行硬隔离, 极端地说为每个租户都创建一个集群,这样肯定所有的需求都可以得到满足,但在多集群的上层,一定会再需要一个调度层,可以将用户请求下放到对应的集群中,对规模较小的场景下不合适,这属于控制面隔离

  • 虚拟集群: 在一个集群中,一个租户以虚拟集群的形式存在,虚拟控制面的多租户模型通过为每个租户提供专用控制面组件来扩展基于命名空间的多租户, 从而完全控制集群范围的资源和附加服务,开源实现有vcluster

从这里可以看出Cluster 或 Control plane 的隔离方案引入了过多的额外开销,比如每个租户需要建立独立的控制面组件,这样就降低了资源利用率;同时大量租户集群的建立,也会带来运维方面的负担

  1. ns/quota分层
  • 上面提到既然namespace是一种单一的资源隔离手段,如果它具备分层能力的话就会非常有用, 比如将多个命名空间组织成层次结构,并在它们之间共享某些策略和资源。 它还可以帮助你管理命名空间标签、命名空间生命周期和委托管理,并在相关命名空间之间共享资源配额,开源实现有hnc/capsule/volcano等

  • 对租户的请求进行协议转换,使得每个租户看到的都是独占的 Kubernetes 集群。对于后端集群来说,多个租户实际上是利用了 Namespace 的原生隔离性机制而共享了同一个集群的资源, 这种较轻量的开源实现有kubezoo

另外,组织结构在公司内部普遍存在,因此这种做法可以很容易让配额随着人员或者团队的变化而变化,接下来的解决方案也是基于这种方案实现,主要调研有hnc、capsule、volcano等开源实现

以下开源方案能实现生产需求所述要求,主要的思路为:

依然通过namespace来限制某个业务的资源配额,同时引入一种CRD来对研究员的总配额来限制

或者反过来也行, 即: 通过CRD来限制某个业务的配额,再使用namespace来限制总配额

不管是使用哪一种方案,有一个很重要的问题需要考虑,即: 当namespace或者CRD有很多时,对于一些共性的配置,如何传播到各个namespace或者CRD资源中去?因为对于某一类业务来说,对研究员的配额可能是统一的(当然也可能有例外),所以如果能通过继承某个要能对象来直接生成N个子对象,那运维友好性将大大提高,当然这个问题可以有多种解法,策略引擎是个很好的方式,比如kyvero、OPA等,很多对资源的传播也都是基于策略引擎开发而来

hnc

hnc,Hierarchical Namespace Controller, 是kubernetes-sig专门为解决namespace为单一对象而出的CRD, 为namespace赋于分层的能力

目前的kubernetes中,ns需要集群集群员才有权限创建,且namespace为单层结构,使用hnc后,管理员可以赋于其它非管理员在一个root namespace下新建无数个sub namespace的权限

同时,hnc支持在root ns中定义任一对象,可将这一对象propagation(传播)到所指定的sub ns中,这样在管理上是不是就非常简单

所以解决上述诉求使用hnc可以这么做:

集群管理员以业务为管理单元,创建root ns, 将sub ns下放到业务平台上,

业务平台可以根据业务属性创建sub ns,比如以研究员为单位(或者以团队为单位),限定resourcequota, 即

1
2
3
4
root-ns-notebook # define resourcequota for user in every subns
-- sub-ns-teamA-notebook # define resourcequota for user in every subns
-- sub-ns-teamAnotebook-userA #inherit resourcequota from tenant
-- ...

在root ns下定义了一个teamA的二级ns, 同时在这个二级ns上定义了resourcequota,不过这个quota会被你直接传播到这个二级ns下的所有sub ns做为resourcequota,即也代表所有的user的resourcequota

当然,这个resourcequota的传播到哪些subns是可以通过annotation或者namesapce selector进行控制

同理,对于共享资源池,也可采用这种分层的ns进行控制

还有一个对象叫hrq(hierarchical resorucequota), 对resourcequota进行分层, 非常有用

由于篇幅有限,hnc的具体结节将不在本篇展开,感兴趣的可以参考作者的实践:

Kubernetes学习(hnc实现namesapce分层模型)

hnc可以很方便地解决创建namespace的权限问题,同时利用层级关系可以很容易切入到公司的组织结构,不过hnc还是偏底层了一些,没有一个以租户为单位的CRD对象,capsule由然而出.

capsule

capsule基本思路与hnc基本类似,它的代码里很多特性都是基于hnc直接实现的,它有一个CRD: Tetant, 直接就可创建一个租户对象, 这个对象可以具有多种属性: 配额, 资源传播, NodePool、RBAC配置等等

所以解决上述诉求使用capsule可以这么做:

集群管理员以业务为管理单元,以notebook业务为例, 创建一个名为root-notebook-tenant对象,同时定义这个Tenant的resourcequota属性, 将创建sub namespace的权限下放到业务平台上,业务平台可以根据业务,再以研究员为单位(或者以团队为单位)来创建sub ns, 比如 namespace-nootbook-userA 属于root-notebook-tenant, 因此也将继承它的所有属性,包含resourcequota等, 即

1
2
3
4
Root-nootbook-tenant #define resourcequota for user in every subns
- namespace-nootbook-userA # inherit resourcequota from tenant
- namespace-notebook-userB, # inherit resourcequota from tenant
- ...

tenant上的resourcequota同样可以通过annotation或者namesapce selector进行控制

capsule还有很多其它特性,由于篇幅有限,capsule的具体结节将不在本篇展开,感兴趣的可以参考作者的实践capsule

Kubernetes学习(capsule实现多租户模型)

总结一下,hnc很好地解决了kubernetes namespace单一层级限制问题,而capsule又基于hnc实现更直接地实现了租户对象

hnc与capsule目前还不能很好地解决资源怎样分配可以更加合理问题,话说回来,这也不是它们要解决的问题,如volcano这类的调度系统,也有queue对象,都是在解决租户与资源之间关系.

当然,一些成熟的Kubernetes集群管理工具都会有自己的CRD来对租户进行管理, 比如rancher会有project这类的对象, kubesphere里有workspace等等

总之: 条条大路通罗马, OP同学可以不用疯掉了

参考文章:

转载请注明原作者: 周淑科(https://izsk.me)

 wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?