本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效或不准确。
引入分层命名空间
在一个 Kubernetes 集群上安全地托管大量用户一直是一项棘手的任务。一个主要原因是不同组织使用 Kubernetes 的方式不同,因此没有一种租户模型可能适合所有人。相反,Kubernetes 提供了构建块来创建你自己的租户解决方案,例如基于角色的访问控制 (RBAC) 和 NetworkPolicies;这些构建块越好,就越容易安全地构建多租户集群。
用于租户的命名空间
迄今为止,这些构建块中最重要的是命名空间,它是几乎所有 Kubernetes 控制平面安全和共享策略的支柱。例如,RBAC、NetworkPolicies 和 ResourceQuotas 默认都尊重命名空间,并且 Secret、ServiceAccount 和 Ingress 等对象可以自由地在单个命名空间内使用,但与其他命名空间完全隔离。
命名空间有两个关键属性,使其非常适合策略实施。首先,它们可以用于表示所有权。大多数 Kubernetes 对象必须位于命名空间中,因此如果你使用命名空间来表示所有权,你总能确定存在所有者。
其次,命名空间具有授权创建和使用的特性。只有高权限用户才能创建命名空间,其他用户需要明确的许可才能使用这些命名空间——也就是说,在这些命名空间中创建、查看或修改对象。这使得它们可以在无权限用户创建 Pod 和 Service 等“常规”对象之前,先用适当的策略精心创建好。
命名空间的局限性
然而,在实践中,命名空间的灵活性不足以满足一些常见的使用场景。例如,假设一个团队拥有多个微服务,它们具有不同的 Secret 和 Quota。理想情况下,他们应该将这些服务放入不同的命名空间中,以便相互隔离,但这带来了两个问题。
首先,这些命名空间没有共同的所有权概念,即使它们都由同一个团队拥有。这意味着如果一个团队控制多个命名空间,Kubernetes 不仅没有记录它们的共同所有者,而且基于命名空间的策略也不能统一地应用于它们。
其次,如果团队能够自主运作,通常工作效果最好,但由于命名空间创建需要高权限,开发团队的任何成员都不太可能被允许创建命名空间。这意味着每当一个团队需要新的命名空间时,他们都必须向集群管理员提交工单。虽然这对于小型组织来说可能是可以接受的,但随着组织的壮大,这会产生不必要的繁琐工作。
引入分层命名空间
分层命名空间是由 Kubernetes 多租户工作组 (wg-multitenancy) 开发的一个新概念,旨在解决这些问题。最简单来说,分层命名空间是一个常规的 Kubernetes 命名空间,其中包含一个小型自定义资源,该资源标识一个单独的、可选的父命名空间。这建立了跨命名空间的所有权概念,而不仅仅是在命名空间内。
这一所有权概念带来了另外两种行为
- 策略继承:如果一个命名空间是另一个命名空间的子命名空间,RBAC RoleBinding 等策略对象会从父命名空间复制到子命名空间。
- 委派创建:通常你需要集群级权限才能创建命名空间,但分层命名空间增加了一种替代方案:子命名空间(subnamespaces),使用父命名空间中的有限权限即可对其进行操作。
这解决了我们开发团队面临的两个问题。集群管理员可以为团队创建一个“根”命名空间,并配置所有必需的策略,然后将创建子命名空间的权限委派给团队成员。然后,这些团队成员可以为自己使用创建子命名空间,而不会违反集群管理员设置的策略。
分层命名空间实践
分层命名空间由一个 Kubernetes 扩展提供,该扩展称为 分层命名空间控制器,简称 HNC。HNC 包含两个组件
- Manager 在你的集群上运行,负责管理子命名空间、传播策略对象、确保层级结构合法以及管理扩展点。
- kubectl 插件
kubectl-hns
使普通用户能够轻松与 Manager 交互。
两者都可以轻松地从我们仓库的 Releases 页面安装。
让我们看看 HNC 的实际应用。假设我没有创建命名空间的权限,但我可以查看命名空间 team-a
并在其中创建子命名空间1。使用该插件,我现在可以输入
$ kubectl hns create svc1-team-a -n team-a
这将创建一个名为 svc1-team-a
的子命名空间。请注意,由于子命名空间也是常规的 Kubernetes 命名空间,所有子命名空间的名称仍然必须是唯一的。
通过请求树状视图,我可以查看这些命名空间的结构
$ kubectl hns tree team-a
# Output:
team-a
└── svc1-team-a
如果在父命名空间中有任何策略,这些策略现在也会出现在子命名空间中2。例如,假设 team-a
有一个名为 sres
的 RBAC RoleBinding。这个 RoleBinding 也将存在于该子命名空间中
$ kubectl describe rolebinding sres -n svc1-team-a
# Output:
Name: sres
Labels: hnc.x-k8s.io/inheritedFrom=team-a # inserted by HNC
Annotations: <none>
Role:
Kind: ClusterRole
Name: admin
Subjects: ...
最后,HNC 会为这些命名空间添加包含层级结构有用信息的标签,你可以使用这些标签来应用其他策略。例如,你可以创建以下 NetworkPolicy
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-team-a
namespace: team-a
spec:
ingress:
- from:
- namespaceSelector:
matchExpressions:
- key: 'team-a.tree.hnc.x-k8s.io/depth' # Label created by HNC
operator: Exists
此策略将同时传播到 team-a
的所有后代命名空间,并且还允许所有这些命名空间之间的入口流量。“tree”标签只能由 HNC 应用,并保证反映最新的层级结构。
你可以从用户指南了解 HNC 的所有特性。
下一步和参与方式
如果你认为分层命名空间适用于你的组织,HNC v0.5.1 已在 GitHub 上发布。我们很想知道你对它的看法、你使用它解决的问题以及你最希望添加的特性。与所有早期软件一样,你应该谨慎在生产环境中使用 HNC,但我们收到的反馈越多,就越能更快地推进 HNC 1.0 的发布。
我们也欢迎更多贡献者加入,无论是修复或报告 bug,还是帮助原型化新特性,例如异常处理、改进的监控、分层资源配额或细粒度配置。
请通过我们的仓库、邮件列表或 Slack 联系我们 - 我们期待你的反馈!
Adrian Ludwin 是一名软件工程师,也是分层命名空间控制器的技术负责人。
注 1:技术上讲,你在父命名空间中创建一个名为“子命名空间锚点”的小对象,然后 HNC 会为你创建子命名空间。
注 2:默认情况下,只有 RBAC Role 和 RoleBinding 会被传播,但你可以配置 HNC 来传播任何基于命名空间的 Kubernetes 对象。