由于 namespace 本身的限制,Kubernetes 对多租户的支持面临很多困难,本文梳理了 K8S 多租户支持的难点以及可能的解决方案。原文: Multi-tenancy in Kubernetes
是否应该让多个团队使用同一个 Kubernetes 集群?
是否能让不受信任的用户安全的运行不受信任的工作负载?
Kubernetes 支持多租户吗?
本文将探讨支持多租户的集群所面临的挑战。
多租户可以分为:
- 软多租户(Soft multi-tenancy) 适用于租户是可信任的情况,例如同一公司的团队共享集群时。
- 硬多租户(Hard multi-tenancy) 适用于租户不可信的情况。
实践中也可能是混合模式!
在租户之间共享集群的基本构建块是命名空间(namespace)。
名称空间对资源进行逻辑分组 —— 不提供任何安全机制,也不能保证所有资源都部署在同一节点中。
命名空间中的 pod 仍然可以与集群中的所有其他 pod 通信,向 API 发出请求,并使用尽可能多的资源。
开箱即用,任何用户都可以访问任何命名空间。
如何阻止访问呢?*
通过RBAC,可以限制用户和应用程序可以使用的命名空间或在命名空间内做什么。
常见操作是向有限的用户授予权限。
使用Quota和LimitRanges,可以限制在命名空间中部署的资源以及可用的内存、CPU 等。
如果想限制租户对其命名空间的操作,这是个好主意。
默认情况下,所有 pod 都可以与 Kubernetes 中的任何 pod 通信。
但这并不适用于多租户,可以用NetworkPolicies来纠正这个问题。
NetworkPolicies 类似于防火墙规则,可以隔离出站和入站流量。
很好,命名空间现在安全了吗?
别急。
基于 RBAC、NetworkPolicies、Quota 等作为多租户的基本构建块还是不够。
Kubernetes 还有几个共享组件。
Ingress 控制器就是一个很好的例子,通常在每个集群中只会部署一个。
如果提交具有相同路径的 Ingress 清单,最后一个会覆盖之前的定义,并且只有这一个才会生效。
更好的方法是为每个命名空间部署一个控制器。
另一个有趣的挑战是 CoreDNS。
如果某个租户滥用 DNS 怎么办?
集群的其余部分也将受到影响。
可以用一个额外的插件[https://github.com/coredns/policy](CoreDNS external plugin)来限制请求。
Kubernetes API 服务器也面临同样的挑战。
Kubernetes 不知道租户,如果 API 接收到太多请求,将会触发全局流控。
我不知道是否有解决办法!
如果进一步考虑共享资源,那么 kubelet 和工作负载也存在挑战。
正如Philippe Bogaerts提到的,租户可以通过 liveness 探针接管集群中的节点。
这也不容易解决。
可以将扫描器(linter)作为 CI/CD 的一部分,或者用准入控制器(admission controller)来验证提交给集群的资源是否安全。
还有隔离机制比虚拟机更弱的容器。
Lewis Denham-Parry在这段视频中展示了如何从容器中逃逸。
如何解决这个问题?
可以用gVisor这样的容器沙箱,或者用轻型虚拟机作为容器(Kata Container,firecracker-containerd)或完整的虚拟机(virtlet作为CRI)。
希望你已经意识到这个主题的复杂性,以及在 Kubernetes 中为隔离网络、工作负载和控制器提供严格的边界是多么困难。
这就是为什么不建议在Kubernetes中提供硬多租户的原因。
如果需要硬多租户,建议使用多集群或集群即服务(Cluster-as-a-Service)工具。
如果可以容忍较弱的多租户模型,以换取简单性和便利性,那么可以推出 RBAC、Quota 等规则。
还有一些工具可以把这些问题抽象出来:
最后,如果对这个话题感兴趣,可以进一步参考以下资源:
- 我们在Learnk8s上举办的 Kubernetes 研讨会
- twitter讨论集合
- 每周发布的Kubernetes时事通讯
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!