本文已发布一年以上。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

引入分层命名空间

在一个 Kubernetes 集群上安全地托管大量用户一直是一项棘手的任务。其中一个主要原因是,不同的组织以不同的方式使用 Kubernetes,因此没有一种租户模型可能适合所有人。相反,Kubernetes 为您提供了构建自己的租户解决方案的构建块,例如基于角色的访问控制 (RBAC) 和网络策略 (NetworkPolicies);这些构建块越好,安全地构建多租户集群就越容易。

用于租户的命名空间

到目前为止,这些构建块中最重要的是命名空间,它构成了几乎所有 Kubernetes 控制平面安全性和共享策略的支柱。例如,RBAC、网络策略和资源配额 (ResourceQuotas) 默认都遵循命名空间,并且诸如 Secret、ServiceAccount 和 Ingress 等对象都可以在任何一个命名空间自由使用,但与其他命名空间完全隔离。

命名空间有两个关键属性,使其非常适合策略实施。首先,它们可以用来表示所有权。大多数 Kubernetes 对象必须位于命名空间中,因此如果您使用命名空间来表示所有权,则始终可以指望存在所有者。

其次,命名空间具有授权的创建和使用。只有高权限用户才能创建命名空间,其他用户需要明确的权限才能使用这些命名空间 - 即在这些命名空间中创建、查看或修改对象。这允许在非特权用户可以创建诸如 Pod 和 Service 等“常规”对象之前,仔细地创建具有适当策略的命名空间。

命名空间的局限性

然而,在实践中,命名空间不够灵活,无法满足一些常见的用例。例如,假设一个团队拥有多个具有不同 Secret 和配额的微服务。理想情况下,他们应该将这些服务放入不同的命名空间,以将它们彼此隔离,但这会带来两个问题。

首先,这些命名空间没有共同的所有权概念,即使它们都由同一个团队拥有。这意味着,如果团队控制多个命名空间,Kubernetes 不仅没有关于其共同所有者的任何记录,而且命名空间范围的策略也无法在它们之间统一应用。

其次,团队通常在能够自主运行时效果最佳,但是由于命名空间的创建是高权限操作,因此开发团队的任何成员都不太可能被允许创建命名空间。这意味着,每当团队想要一个新的命名空间时,他们都必须向集群管理员提出工单。虽然这对于小型组织来说可能是可以接受的,但随着组织的增长,这会产生不必要的麻烦。

引入分层命名空间

分层命名空间Kubernetes 多租户工作组 (wg-multitenancy) 开发的一个新概念,旨在解决这些问题。在其最简单的形式中,分层命名空间是一个常规的 Kubernetes 命名空间,其中包含一个小的自定义资源,该资源标识单个可选的父命名空间。这建立了命名空间的所有权概念,而不仅仅是在命名空间

这种所有权概念启用了两种额外的行为类型

  • 策略继承:如果一个命名空间是另一个命名空间的子级,则 RBAC RoleBinding 等策略对象将 从父级复制到子级
  • 委托创建:您通常需要集群级别的权限才能创建命名空间,但是分层命名空间添加了一种替代方案:子命名空间,可以使用父命名空间中的有限权限进行操作。

这解决了我们开发团队的两个问题。集群管理员可以为团队创建一个“根”命名空间,以及所有必要的策略,然后委派创建子命名空间的权限给该团队的成员。然后,这些团队成员可以创建供自己使用的子命名空间,而不会违反集群管理员施加的策略。

分层命名空间的实践

分层命名空间由一个名为 分层命名空间控制器HNC 的 Kubernetes 扩展提供。HNC 由两个组件组成

  • 管理器在您的集群上运行,管理子命名空间,传播策略对象,确保您的层次结构是合法的并管理扩展点。
  • 名为 kubectl-hnskubectl 插件使用户可以轻松地与管理器交互。

两者都可以从我们的 存储库的发布页面轻松安装。

让我们看看 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 的所有后代,并且将允许在所有这些命名空间之间进行入口流量。“树”标签只能由 HNC 应用,并保证反映最新的层次结构。

您可以从用户指南中了解有关 HNC 功能的所有信息。

后续步骤和参与

如果您认为分层命名空间可以为您的组织工作,则 GitHub 上提供了 HNC v0.5.1。我们很想知道您对它的看法,您正在使用它解决什么问题以及您最希望看到添加哪些功能。与所有早期软件一样,您应该谨慎在生产环境中使用 HNC,但是我们获得的反馈越多,我们就越能尽快推动 HNC 1.0 的发布。

我们也欢迎更多的贡献者,无论是修复或报告错误,还是帮助原型化新功能,例如异常、改进的监控、分层资源配额或细粒度的配置。

请通过我们的 存储库邮件列表Slack 与我们联系 - 我们期待收到您的来信!


Adrian Ludwin 是一名软件工程师,也是分层命名空间控制器的技术负责人。

注 1:从技术上讲,您在父命名空间中创建一个名为“子命名空间锚点”的小对象,然后 HNC 会为您创建子命名空间。

注 2:默认情况下,仅传播 RBAC Role 和 RoleBinding,但您可以配置 HNC 以传播任何命名空间的 Kubernetes 对象。