Z.S.K.'s Records

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

namespace在kubernetes中是一个很重要的基础构件,它构成了几乎所有 Kubernetes 控制平面安全和共享策略的骨干。命名空间有两个关键属性,使其成为策略执行的理想选择

  • 首先,命名空间可以用来代表所有权。大多数 Kubernetes 对象资源必须在某一个命名空间中,所以如果使用命名空间来代表所有权,那么命名空间中的所有对象都隶属于同一个所有者。
  • 其次,命名空间的创建和使用需要授权。只有超级管理员才能创建命名空间,其他用户需要明确的权限才能使用这些命名空间(包括创建、查看和修改命名空间中的资源对象)。可以设置恰当的安全策略,防止非特权用户创建某些资源对象。

namespace是个硬限制,在很多场景下会有诸多问题, 因此层级命名空间(hierarchical namespaces)出现了,它是 Kubernetes多租户工作组(Working Group for Multi-Tenancy)而提出的新概念

在最简单的形式下,层级命名空间就是一个常规的命名空间,它标识了一个单一的、可选的父命名空间;

更复杂的形式下,父命名空间还可以继承出子空间。这样就建立了跨命名空间的所有权概念,而不是局限于命名空间内。

这种层级命名空间的所有权可以在命名空间的基础上实现额外的两种功能:

  • 策略继承: 如果一个命名空间是另一个命名空间的子空间,那么权限策略(例如RBAC RoleBindings)将会从父空间直接复制到子空间
  • 继承创建权限: 通常情况下,需要管理员权限才能创建命名空间。但层级命名空间提供了一个新方案:子命名空(subnamespaces),只需要使用父命名空间中的部分权限即可操作子命名空间。

有了这两个功能后,集群管理员就可以为团队创建一个『根』命名空间,以及所有必要的权限策略,然后将创建子命名空间的权限赋予该团队的成员。这样团队内的成员就可以在不违反集群策略的情况下创建自己的子命名空间。

实践

这里忽略安装流程,比较简单,可直接参考github的user-guide

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# hns可以以plugin的形式安装到Kubectl中,之后便可以直接使用kubectl hns

kubectl create ns acme-org # 创建root ns
kubectl hns create team-c -n acme-org # 使用hns 直接创建一个subns

# 也可以通过创建ns一样创建
kubectl create ns acme-org
kubectl create ns team-a
kubectl hns set team-a --parent acme-org # 指定父子关系

# 使用hns tree查看关系树
kubectl hns tree acme-org

acme-org
├── team-a
│ └── service-1
├── team-b
└── [s] team-c

有[s]的表明是通过第一种方式创建subns, 这种叫subns

没有[s]表明是先创建的ns,然后set –parent的方式创建, 这种叫fullns,

单独拎出来说是因为这两种创建方式创建出来的sub ns会有一些区别:

subns与fullns(直接通过k create ns创建的ns)的区别:

  • subns的生命周期跟随rootns, 删除fullns的rootns,不会影响fullns, 而subns的rootns删除,subns也会被删除
  • subns的parent的rootns不能修改,而fullns可以随时调整

配置文件

在安装hnc时,存在两个配置文件

  1. hierarchyconfigurations: 为每个namespace的分层信息,记录某个ns是否存在subns及rootns是谁
  2. HNCConfiguration: 为hnc全局的配置文件,里面记录了需要传播的资源对象及资源个数等信息,只有集群管理员才有权限修改这个配置文件

propagation(传播)

hnc中一个很重要的特性就是propagation, 当以root ns创建了多层的subns, 对于一些通用的属性需要从root ns传播到subns, 这样可以实现一处维护,随处传播的效果

hnc支持所有资源类型,不仅包括kubernetes常用的类型,还包括CRD, 同时还可以控制传播的资源个数

默认情况下, parent namespace下的所属的Role 和 RoleBinding 对象会传递给 child 命名空间对象

首先查看现在的配置中哪些开启了传播

1
2
# 查看配置
kubectl get hncconfiguration config -o yaml

有两种方式实现:

  • a. 通过全局配置文件
    如果是k8s自带资源(可省略–group):
    kubectl hns config set-resource secrets --mode Propagate
    如果是crd资源:
    kubectl hns config set-resource podpresets --group redhatcop.redhat.io --mode Propagate
  • b. 通过annotaions(也需要hncconfiguration中设置该配置annotation方可生效)
    在需要propagation的对象添加如下的annotaions, 不同的–mode,使用的annotaions效果不一样, 详见how-to.md:
    kubectl annotate secret my-secret -n parent propagate.hnc.x-k8s.io/all=true

所有被传播的对象的label都会被添加上以下内容:
app.kubernetes.io/managed-by: hnc.x-k8s.io
hnc.x-k8s.io/inherited-from: acme-org

注意: 如果使用–mode Propagate, 在subns无法修改由rootns传播过来的对象,会提示
admission webhook "objects.hnc.x-k8s.io" denied the request: configmaps "team-b/cm-test" is forbidden: cannot modify object propagated from namespace "acme-org"

格式:

1
kubectl-hns config set-resource RESOURCE [--group GROUP] [--force] --mode <Propagate|Remove|Ignore|AllowPropagate>
1
2
3
4
5
6
7
# 举个例子
# 给所有的ns传播一个configmap,很简单,在HNCConfiguration中开启configmap的默认传播, 然后在parent ns中发布这个configmap,即可传播到subns

# 给所有的ns传播一个crd,同样,需要先在hnc的配置中打开该对象需要被传播的开关
# 这里以gvk为redhatcop.redhat.io/v1/podpresets这个crd对象为例
kubectl hns config set-resource podpresets --group redhatcop.redhat.io --mode Propagate
# 然后在parent ns中发布这个crd对象即可

传播策略

对资源的传播,可指定 3 种模式(即在上述命令中的–mode参数):

  1. Propagate(传播):将对象从祖先传播到后代,并删除过时的后代。

  2. AllowPropagate(允许传播): opt-in传播-当且仅当对象上至少有一个标签选择器时将对象从你对象传播到子对象并删除过时的后代。

  3. Remove(删除):删除所有现有的传播副本,但不会修改源对象。

  4. Ignore(忽略):停止修改该资源。不会传播新的或更改的对象,也不会删除过时的对象。这是默认模式

HRQ

HRQ(HierarchicalResourceQuota)是hnc中的一种CRD, 旨在解决resourcequota的传播问题, HRQ最终会转换成ns的resourcequota对象

rootns的HierarchicalResourceQuota虽然会传播到所有subns下生成相同的resourcequota,但HierarchicalResourceQuota指定的资源为所有subns下的资源总和

Q/A

  1. Q: 创建一个rootns及HierarchicalResourceQuota, 再创建一个没有设置HierarchicalResourceQuota的subns, resourcequota如何传播??
    A: subns与rootns下都会生成resourcequota且与HierarchicalResourceQuota相同,同时在这两个ns下的资源不会超过HierarchicalResourceQuota

  2. Q: 创建一个rootns及HierarchicalResourceQuota, 再创建一个subns,正常情况下rootns会传播到subns,
    此时在subns下再创建一个HierarchicalResourceQuota且规格大于rootns的HierarchicalResourceQuota, 会发生什么??
    A: 测试发现不管这个在subns上创建一个HierarchicalResourceQuota是否与rootns同名,都可以创建成功,但是查看生成的resourcequota会发现此时的resourcequota还是以rootns下的HierarchicalResourceQuota为准,
    如果此时在subns下发布一个job, 资源比rootns的hrq大,但比subns的hrq小,状态会pending, describe的原因是不能超时rootns的资源上限, 这里提示不能超过rootns的原因在于subns的quota比rootns的大,所以先超过了rootns

  3. Q: 接Q2问题,如果此时在subns下创建的HierarchicalResourceQuota小于rootns的HierarchicalResourceQuota,情况又如何??
    A: 如果此时在subns下发布一个job,资源比subns的hrq大但比rootns的hrq小,状态会pending, describe的原因是不能超时subns的资源上限

    总结: 经过Q2及Q3可以得出结论: subns的HierarchicalResourceQuota可以比rootns的大,subns下的资源不能大于subns的HierarchicalResourceQuota或者rootns的HierarchicalResourceQuota, 如果出现pending,提示的原因是先超过了哪个ns的quota则提示哪个ns的quota超出,这样符合原生的resourcequota限制,即一个namespace可以同时存在多个对某一类资源(如CPU)的限制,会以小规格为准

  4. Q: 在rootns开启HierarchicalResourceQuota的propagation情况下,subns的HierarchicalResourceQuota是否可覆盖rootns的HierarchicalResourceQuota??
    A: 开启–enable-hrq后,HierarchicalResourceQuota默认会propagation到所有subns
    如果此时subns中没有hrq资源,则在subns中会直接生成一条同等规格的resoucequota对象, 同时这个rq会跟着rootns的hrq修改而修改
    但如果此时subns有自己的hrq,则不会跟随rootns的修改而变化(见Q5),
    如果此时修改subns的hrq对象,是否会覆盖rootns的hrq对象?
    会覆盖, 但是subns的resourcequota还是以subns及rootns两者的小值为准, 如果此时将rootns的HierarchicalResourceQuota删除后,subns的resourcequota的规格会变成它自己的HierarchicalResourceQuota所对应的规格

  5. Q: 接Q4问题,如果只是resourcequota, 是否也会propagation??
    A: 不会, 在subns下创建一个名为notebook-user-quota的resourcequota对象,然后在rootns中发布HierarchicalResourceQuota
    在subns中会发现多了一个hrq.hnc.x-k8s.io的resourcequota,notebook-user-quota的resourcequota保存不变(一个namespace可以同时存在多个对某一类资源(如CPU)的限制,会以小规格为准)
    经测试,无法在subns下直接创建名为hrq.hnc.x-k8s.io的resourcequota,则会直接删除

  6. Q: propagation能否支持crd对象??
    A: 支持,任何对象都可传播,可使用以下命令进行,详情可看关于propagation小节

  7. Q: 由上可知最终生成的resourcequota会以较小值为依赖进行资源控制, 但如果想subns的resourcequota比rootns的大如何限制?
    A: 通过rootns不propagation HierarchicalResourceQuota到subns, subns即可单独设置resourcequota
    经测试发现,无法通过rootns的HierarchicalResourceQuota达到此目的, 但是可以通过原生的控制resourcequota propagation来实现
    HierarchicalResourceQuota无法达到目的原因在于HierarchicalResourceQuota默认是传播的,因此没办法通过annotations进行控制哪些不传播哪些传播,比如要开启resourcequota的传播:

    1
    2
    # 先开启resourcequota实现传播
    # kubectl hns config set-resource resourcequota --mode Propagate

    然后在rootns中创建resourcequota, 可通过在annotations中排除不需要传播的ns.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    apiVersion: v1 
    kind: ResourceQuota
    metadata:
    name: root-rq
    namespace: root-notebook
    annotations:
    propagate.hnc.x-k8s.io/treeSelect: '!notebook-user-zsk' # 这里指定哪些ns不需要传播
    spec:
    hard:
    requests.cpu: "5"
    requests.memory: "5Gi"
    limits.cpu: "5"
    limits.memory: "5G"

    动态修改annotation,会动态生效
    这样即可实现HQR控制所有subns的资源总量,一部分继承rootns的resourcequota,同时不需要继承的subns则可自定义resourcequota
    另外,如果是某些subns的资源比rootns的hrq小的话,则可直接在subns中设置HierarchicalResourceQuota即可覆盖rootns中的quota(以较小值为准)

hnc中使用了mutating webhook的方式拦截了权限的请求,将权限限制在合适的subns中

同时使用策略引擎达到资源可以向下传播,很大程度解决了kubernetes中namespace的诸多限制

在一些其它的开源项目如capsule中看到hnc的思路,相信hnc会成为kubernetes关于资源、权限等维度的标准分层实现

参考文章:

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

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