前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Kubernetes](五)Kubernetes多租户管理与资源控制

[Kubernetes](五)Kubernetes多租户管理与资源控制

原创
作者头像
baron
发布2019-12-05 15:58:41
1.5K0
发布2019-12-05 15:58:41
举报
namespace设计解读

namespace是Kubernetes进行多租户资源隔离的主要手段,那么它在系统中的表现形式是什么样的?实现原理和使用方法又是怎样的呢?

什么是namespace

namespace是一个将Kubernetes的资源对象进行细分的类似于DNS子域名的概念。namespace能够帮助不同的租户共享一个Kubernetes集群。Kubernetes引人namespace的目的包括以下几点:

  • 建立一种简单易用,能够在逻辑上对Kubernetes资源对象进行隔离的机制。
  • 将资源对象与实际的物理节点解耦,用户只需关注namespace而非工作节点上的资源情况。
  • 随着Kubernetes访问控制代码开发的深人,与Kubernetes认证和授权机制相结合。
  • 通过namespace对Kubernete,资源进行归类,使得APIserver能够建立一套有效的过滤Kubernetes资源请求的机制。
Kubernetes用户认证机制

Kubernetes用以认证用户请求的方式主要有5种,下面将逐一进行简单说明。

基于客户端证书的认证机制

在APIServer启动过程中,通过传入--client-ca-file=SOMEFILE参数可以启用客户端证书认证。上面引用的文件必须包含一个或多个证书颁发机构(CA)用于检验用户传给APIServer的证书的合法性。如果客户端证书提交给APIServer且被认证通过,则SSL证书主题中的共用名(Common Name)将作为客户端发起API请求的用户名。

基于token的认证机制

当客户端向Kubernetes安全端口发起API请求时,Kubernetes还支持使用token来认证用户的合法性。token预先存储在一个token文件中,在APIServer启动过程中传入--token-auth-file=SOMEFILE参数便可启用Kubernetes认证模块。token文件是一个CSV格式的文件(token文件格式目前由package tokenfite实现,具体代码见:plugin/pkg/auth/authenticator/token/token-file/...),至少有3列数据,分别是token, user name和user id,其后可以有选择地加上groupnames。

基于OpenID Connect ID Token的认证机制

OpenID ConnectID Token是一种特殊的认证方式。与其为每个希望访问的服务器都单独构建一个新的账户,不如使用一个通用的OpenID,而该OpenID的签发方来向各个服务器来提供认证服务。

Basic认证机制

Basic认证通过--basic-auth-file参数简单地传入用户名、用户id和密码进行认证。当某个HTTP客户端使用这种认证方式向APIServer发起请求时,应该在Authorization头部附上一个Basic BASE64ENCODED(USER:PASSWORD)的值。事实上,该认证方式在安全方面并不十分可靠,通常只用作其他几种认证方式的补充。

Keystone认证机制

当启用这种认证方式时,用户会从Keystone API中获得一个token,并且将该token作为该用户的密码注入到kubeconfig文件中。当用户向APIServer发送请求时,APIServer会向Keystone校验该用户及其token是否合法,验证通过时则对该请求进行过应答。

Kubernetes用户授权机制

在Kubernetes中,认证和授权是分开的,而且授权发生在认证完成之后,认证过程是检验发起API请求的用户是不是他所声称的那个人,而授权过程则判断此用户是否有执行该API请求的权限,因此授权是以认证的结果作为基础的。Kubernetes授权模块应用于对APIServer安全端口的HTTPS访问请求。

Kubernetes授权模块检查每个HTTP请求并提取请求上下文中的所需属性(例如user,resource, namespace)与访问控制规则进行比较。任何一个API请求在被处理前都需要通过一个或多个访问控制规则的验证。

目前Kubernetes支持并实现了以下的授权模式(authorization mode ),这些授权模式可以通过在APIServer启动时传入参数进行选择:

代码语言:txt
复制
--authorization_mode=AlwaysDeny
--authorization_mode=AlwaysAllow
--authorization_mode=ABAC
--authorization_mode=Webhook
--authorization_mode=RBAC
--authorization_mode=Node
Kubernetes多维资源管理机制admission control

除了上一节介绍的3种相对传统的授权模式之外,Kubernetes还提供了一种多维度可扩展的资源管理机制admission control,方便用户实现资源配额等功能。

与Kubernetes用户认证与授权模块一样,对admission control的调用也是由APIServer来完成的。APIServer启动过程中就进行了3个初始化操作,创建了3个对象:认证、授权和admission control。APIServer会在用户的请求通过认证授权之后调用admission control,对用户请求进行进一步的审核。所以即使用户请求通过了认证授权,也有可能因为申请的资源超过资源配额而被admission control驳回。

需要说明的是,admission control只负责管理API对资源的请求量,一旦pod或容器实际在某台机器上运行后,并不控制它们的行为。因此admission control实际上是一个静态的、运行前的概念,而不是运行时的概念。

admission control是一种多维度可扩展的资源管理机制,每个维度通过一个admission control插件实现。这种插件被称为admission controller或者admission control plugino Kubernetes APIServer接受以下可选参数来启用admission control。

  • admission-control。以逗号作为分割符的admission control插件的列表,在新建、修改和删除Kubernetes对象之前会调用这些插件来检查该操作是否合法。默认是AlwaysAdmit,即永远允许。
  • iadmission-control-config-file。启动admission control插件的配置文件。

下面将会以Kubernetes系统自带的几个admission control插件为例,介绍如何向Kubernetes集群加入用户自定义的admission control插件,以更好地实现对集群资源的定制化管理控制。

admission control插件是以下接口的一个实现:

admission_controller结构体.png
admission_controller结构体.png

Attributes接口被admission control用来获取一个API请求中能够用于帮助进行决策的信息,这些信息包括API请求所处上下文的namespae, API操作的Kubernetes对象类型、API操作类型和实际运行时的Kubernetes对象。

admission_Interface结构体.png
admission_Interface结构体.png

Interface接口是一个抽象的、可插拔的、用于进行资源管理控制决策的admission control接口。Interface接口的Admit则根据一个API请求的实际信息进行实际的管理决策,负责主要逻辑部分。Handles用于指明该admission controller否支持CREATE, UPDATE, DELETE或CONNECT操作,返回值为bool型。

任意一个admission control插件都是admission.Interface,接口的一个实现用户也可以非常容易地实现自定义的插件。在撰写本书时,共有9个推荐使用的系统admission control插件,分别是AlwaysDeny, AlwaysAdmit, AlwaysPullImages, DenyEscalatingExec, ServiceAccount, SecurityContextDeny, ResourceQuota, LimitRanger和NamespaceLifecycle。

NamespaceLifecycle插件

该插件拒绝在终止状态的namespace(即用户发起删除一个namespace的请求后,此时该namespace的.status.phase为Terminating状态,待该namespace下的所有资源全部被删除后,它才会退出)中创建新资源的请求,以及在尚未存在的namespace下创建资源的请求。

NamespaceLifecycle的Admit函数非常直观地展示了该admission controller的策略,它接受CREATE、UPDATE和DELETE操作。在每次接收到API请求之后,执行如下检查:

  • 当接收到的API请求试图删除namespace时,如果该namespace为default,拒绝该请求,否则接收该请求,并且从本地cache中将该namespace的记录删除。
  • 当接收到的API请求为资源相关的请求时,查找其对应的namespace,如果该namespace不存在,拒绝该请求。
  • 当接收到的API请求为创建资源请求时,如果该namespace为Terminating状态,拒绝该请求。
  • 当上述情况均未违反相应规则时,则通过该请求。

LimitRanger插件

LimitRanger插件的作用是判断客户端API请求中的资源需求是否符合系统管理员预设值,包括上限、下限、默认值以及默认比率。为了配合LimitRanger插件的使用,Kubernetes引入了LimitRange对象,用于对特定namespace中的Kubernetes对象设置资源使用的预设值。当前Kubernetes支持以namespace为单位,在pod和容器两个层次对资源使用进行管理。

先来看一下LimitRange的数据结构定义:

limitRanger结构体.png
limitRanger结构体.png

其中,ObjectMeta表示LimitRange对象的元数据(所有Kubernetes资源对象都有元数据),而LimitRangeSpec本质上是一个包含LimitRangeItem类型数组的结构体。LimitRangeItem是对具体Kubernetes对象类型应用其能够使用的资源列表的设定值,其中资源列表是键为资源名值为整型或字符串类型的map结构。

最后,看一个具体的例子:limit-range.yaml。该Kubernetes资源文件描述了一个LimitRange对象(由kind字段指定)。

limitRanger对象yaml样例.png
limitRanger对象yaml样例.png

与定义Kubernetes其他对象(pod等)的资源文件一样,该yaml文件的kind字段表明该资源文件定义的是LimitRange对象。spec.limits.type字段指定应用限制的对象,这里分别是pod和containero spec.limits.max和spec.limits.min字段分别表示资源列表上限与下限,该文件定义的资源列表包含两个资源类型:内存和CPU。该文件表明,应用到namespace中每个pod的资源限制均为:最大内存1 Gi,最小内存6Mi,最大CPU计算资源2,最小CPU计算资源200m(即0.2 );spec.limits.default和spec.limits.defaultRequest字段分别表示资源列表的默认请求上限和默认请求下限,同样包含了CPU和内存两种资源类型。如果用户在创建pod时未指定spec.container[].resources.limits和spec.container[].resources.requests,这两个值将会被启用。此处应用到namespace中每个容器的资源限制为,默认请求下限:CPU200m,内存100Mi ;默认请求上限:CPU300m,内存200Mi。

接下来我们将从代码的角度,简要分析下LimitRanger插件的实现原理:

  • 首先,向admission control注册一个名为LimitRanger的插件。
  • 然后,实现Admit方法。该方法首先获取发起API请求所在的namespace中的LimitRange对象列表。遍历该LimitRange对象列表,执行如下检查:
    • 对于.spec.container.resources.limits和.spec.container.resources.requests字段为空的manifest,填入LimitRange设定的默认值。
    • 对于pod中的每个container,检查其.container.resources.limits和.container.resources.requests是否满足LimitRange的.spec.limits.max, .spec.limits.min和.spec.limits.maxLimitRequestRatio的设定。如果不满足,则拒绝该请求。

LimitRanger插件只适用于Kubernetes对象创建(CREATE)和更新(UPDATE)操作,并不受理删除操作。需要注意的是,一个namespace中可能存在不止一个LimitRange对象,因此,任何一个针对Kubernetes对象的创建和更新操作都要接受该namespace中所有LimitRange对象的限制。

SecurityContextDeny插件

pod manifest中的security context定义了应用于容器的安全设置(如uid. gid, SELinux角色等),包括pod级别和容器级别的限制。SecurityContextDeny插件会拒绝任何定义了其中某些字段的pod。

SecurityContex取在pod创建(CREATE)和更新(UPDATE)时发生作用。它的Admit函数逻辑如下:

  • 检查REST资源类型,如果不是pod,则接受该请求。
  • 检查pod级别的SecurityContext。如果.supplementalGroups, .seLinuxOptions, .runAsUser或.fsGroup不为空,拒绝该API请求。
  • 逐一检查容器级别的SecurityContext。如果.seLinuxOptions, .runAsUser不为空,则拒绝该请求。

ServiceAccount插件

service account为pod中的进程提供id。实际上,当用户试图与APIServer打交道时,往往通过user account来进行身份的认证及授权;类似地,集群中的pod也可能希望与APIServer通信,系统并不为其创建user account,而作为代替的就是service account。

如果用户启用了service account自动生成的功能,controller就会接管这项工作,主要涉及了3个层面,分别对应service account admission controller, token controller和service account controllero这里我们主要关注第一个。

service account插件在pod创建(CREATE)时发挥作用,其Admit函数包括如下检查:

  • 如果创建的pod是mirror pod,且其.spec.serviceAccountName或volumes.VolumeSource.secret不为空,则拒绝该请求。
  • 如果创建的pod的.spec.serviceAccountName为空,则将该字段设为同一namespace下的default service account。
  • 检查pod引用的service account是存在的,如不存在拒绝该请求。
  • 查找service account对应的secret token,如该pod中未存在该volume,则为其挂载。

ResourceQuota插件

ResourceQuota插件的作用是为特定namespace应用资源使用的配额。与LimitRanger插件类似,为了配合ResourceQuota插件的使用,Kubernetes引人了ResourceQuota对象,用于对特定namespace中的Kubernetes对象设置资源配额。

这里先梳理一下Kubernetes资源的概念。直观地,CPU、内存等通用计算机资源也属于Kubernetes资源类型,在Kubernetes的代码中可以找到以下定义:

kubernetes_resource结构体.png
kubernetes_resource结构体.png

而Kubernetes系统定义的对象类型,譬如pod, service, replication controller, resourcequota

等,也属于Kubernetes资源类型,同样可以在Kubernetes的代码中可以找到以下定义:

kubernetes_resource结构体2.png
kubernetes_resource结构体2.png

每种Kubernetes资源对象都对应一组元数据,包括Name, Namespace和ResourceVersion,分别表示该资源对象的名字,所在Namespace和资源版本号,其中资源版本号用于标识该资源的新旧程度,方便进行版本和数据一致性控制。

Resource0uota的数据结构定义如下所示:

ResourceQuota结构体.png
ResourceQuota结构体.png

其中,unversioned.TypeMeta表示ResourceQuota对象的元数据。此外,Resource0uota包含两个数据类型:ResourceQuotaSpec和ResourceQuotaStatus,分别表示特定namespace中预设的资源配额和资源配额的实际使用情况,存储在etcd中的ResourceQuota.Status字段的数据会由controller manager的资源配额管理器根据系统实际的资源使用量而动态更新。

结束了对ResourceQuota对象的讨论后,再来看具体的例子resource-quota.yaml,该资源文件描述了一个ResourceQuota对象(见kind字段)。

resource_quota_yaml样例.png
resource_quota_yaml样例.png

如上所示,spec:hard即资源配额列表,其各字段的含义和单位如表所示。

ResourceQuota资源对象配置各字段含义和单位.png
ResourceQuota资源对象配置各字段含义和单位.png

ResourceQuota插件只检验创建和更新资源的API请求,其一般过程如下所示:

  • 首先检查该API操作对象是否在ResourceQuota资源列表内,及该操作是否会影响资源对象的数量,如不满足,则接受该API请求。
  • 检查该资源对象所在的namespace是否有ResourceQuota对象,如没有,则接受该API请求。
  • 遍历所有与该资源对象相关的ResourceQuota,根据操作资源对象的不同,检查其.spec定义是否符合要求。以pod为例,如果在ResourceQuota对象中对于cpu进行了定量限制,那么则要求所有在该namespace中的pod必须定义.spec.containers.resource下的cpu值。
  • 根据API请求的资源需求量,检查资源请求量总和是否超过.status.hard的限定,如果超过,则拒绝该请求。对于不同的API请求操作,计算资源请求量总和的方法各不相同。
    • 如果请求的类型是CREATE,资源请求量总和为请求的资源需求量与当前.status.used中对应的资源使用量求和。
    • 如果请求的类型是UPDATE,资源请求量总和为请求的资源更新值(请求值减去原先值)与当前.status.used中对应的资源的使用量求和。
  • 对于每个ResourceQuota,更新其对应的资源对象数目及.status.used,并在etcd中持久化该更新。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • namespace设计解读
  • Kubernetes用户认证机制
  • Kubernetes用户授权机制
  • Kubernetes多维资源管理机制admission control
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档