APIServer

API Server 介绍

kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能

  • 提供集群管理的REST API接口,包括认证授权数据校验以及集群状态变更
  • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd)

访问控制流程概览

Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及
准入控制(Admission Control)等。

1696855554237

mutating: 可以修改对象的值

Validating: 不可以对对象的值进行修改

认证

开启TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。

如果认证成功,则用户的username会传入授权模块做进一步授权验证;而对于认证失败的请求则返回HTTP 401。

认证插件

  • X509证书

    • 使用X509客户端证书只需要API Server启动时配置–client-ca-file=SOMEFILE。在证书认证时,其CN域用作用户名,而组织
      机构域则用作group名。
  • 静态Token文件

    • 使用静态Token文件认证只需要API Server启动时配置–token-auth-file=SOMEFILE。
    • 该文件为csv格式,每行至少包括三列token,username,user id,token,user,uid,”group1,group2,group3”
  • 引导Token

    • 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型, 称作启动引导令牌(Bootstrap
      Token)。
    • 这些令牌以Secret 的形式保存在kube-system 名字空间中,可以被动态管理和创建。
    • 控制器管理器包含的TokenCleaner 控制器能够在启动引导令牌过期时将其删除。
    • 在使用kubeadm部署Kubernetes时,可通过kubeadm token list命令查询。
  • 静态密码文件

    • 需要API Server启动时配置–basic-auth-file=SOMEFILE,文件格式为csv,每行至少三列password, user, uid,后面是可选
      的group名
      password,user,uid,”group1,group2,group3”
  • ServiceAccount

    • ServiceAccount是Kubernetes自动生成的,并会自动挂载到容器的/run/secrets/kubernetes.io/serviceaccount目录中。

    • 在 Kubernetes 中,每个 namespace 下都有一个默认的 ServiceAccount,原因如下:

      简化配置:默认的 ServiceAccount 使得用户无需为每个 Pod 创建一个新的 ServiceAccount,从而简化了配置。如果 Pod 没有指定 ServiceAccount,它将自动关联到默认的 ServiceAccount。

      容器运行时身份:ServiceAccount 提供了一种将身份信息(如 API 访问凭据)与 Pod 关联的方法。默认的 ServiceAccount 为 Pod 提供了基本的身份信息,以便它们可以与 Kubernetes API 交互。

  • OpenID

    • OAuth 2.0的认证机制
  • Webhook 令牌身份认证

    • –authentication-token-webhook-config-file 指向一个配置文件,其中描述如何访问远程的Webhook 服务。
    • –authentication-token-webhook-cache-ttl 用来设定身份认证决定的缓存时间。默认时长为2 分钟。
  • 匿名请求

    • 如果使用AlwaysAllow以外的认证模式,则匿名请求默认开启,但可用–anonymous-auth=false禁止匿名请求。

kubernetes证书

数字证书

根证书与证书

通常我们配置https服务时需要到”权威机构”申请证书。

过程是这样的:

  1. 网站创建一个密钥对,提供公钥和组织以及个人信息给权威机构
  2. 权威机构颁发证书
  3. 浏览网页的朋友利用权威机构的根证书公钥解密签名,对比摘要,确定合法性
  4. 客户端验证域名信息有效时间等(浏览器基本都内置各大权威机构的CA公钥)

这个证书包含如下内容:

  1. 申请者公钥
  2. 申请者组织和个人信息
  3. 签发机构CA信息,有效时间,序列号等
  4. 以上信息的签名

根证书又名自签名证书,也就是自己给自己颁发的证书。CA(Certificate Authority)被称为证书授权中心,k8s中的ca证书就是根证书。

token验证的token传递方式, 请求头加:Authorization: Bearer $token

证书的分类

  • Service Account 密钥对

    sa.key sa.pub , 提供给kube-controller-manager 用于签署 ServiceAccount Token时使用的密钥对, 通过sa.key 对 token 进行签名, api server 通过公钥sa.pub 进行签名验证; 如 kube-proxy 是以 pod 形式运行的, 在 pod 中, 直接使用 service account 与 kube-apiserver 进行认证, 此时就不需要再单独为 kube-proxy 创建证书了, 会直接使用token校验

  • 根证书

    pki/apiserver.crt
    pki/apiserver.key

  • kubelet 证书
    pki/apiserver-kubelet-client.crt
    pki/apiserver-kubelet-client.key

    kubelet要主动访问kube-apiserver, kube-apiserver也需要主动向kubelet发起请求,
    所以双方都需要有自己的根证书以及使用该根证书签发的服务端证书和客户端证书.

  • 代理根证书
    pki/front-proxy-ca.crt
    pki/front-proxy-ca.key

  • 由代理根证书签发的客户端证书
    pki/front-proxy-client.crt
    pki/front-proxy-client.key
    比如使用kubectl proxy代理访问时,kube-apiserver使用这个证书来验证客户端证书是否是自己签发的证书。

  • etcd 根证书
    pki/etcd/ca.crt
    pki/etcd/ca.key

  • etcd peer 之间的通信证书, 由根证书签发
    pki/etcd/peer.crt
    pki/etcd/peer.key

  • pod中Liveness探针客户端证书
    pki/etcd/healthcheck-client.crt
    pki/etcd/healthcheck-client.key

  • 挨批server 访问etcd 的证书
    pki/apiserver-etcd-client.crt
    pki/apiserver-etcd-client.key

认证 - 基于weekhook

需要依照Kubernetes规范,构建认证服务,用来认证 tokenreview request

构建认证服务

  • 认证服务需要满足如下Kubernetes的规范

    • URL: https://authn.example.com/authenticate

    • Method: POST

    • Input: 认证服务签发的token

      1
      2
      { "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview",
      "spec": { "token": "(BEARERTOKEN)" } }
    • Output: 认证结果返回

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      {
      "apiVersion": "authentication.k8s.io/v1beta1",
      "kind": "TokenReview",
      "status": {
      "authenticated": true,
      "user": {
      "username": "janedoe@example.com",
      "uid": "42",
      "groups": [
      "developers",
      "qa"
      ]}}
      }

认证服务的开发具体不进行延伸

配置认证服务到 apiserver

  1. 认证系统的token创建与配置

    • 但在用户认证完成后,生成代表用户身份的token
    • 该token通常是有失效时间的
    • 用户获取该token以后以后,将token配置进kubeconfig
  2. 修改apiserver设置,开启认证服务,apiserver保证将所有收到的请求中的token信息,发给认证服务进行验证

    • –authentication-token-webhook-config-file,该文件描述如何访问认证服务
    • –authentication-token-webhook-cache-ttl,默认2分钟
  3. 配置文件需要mount进Pod

  4. 配置文件中的服务器地址需要指向authService

webhook-config-file 文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"kind":"Config",
"apiVersion":"v1",
"preferences":{

},
"clusters":[
{
"name":"github-authn",
"cluster":{
"server":"http://localhost:3000/authenticate"
}
}
],
"users":[
{
"name":"authn-apiserver",
"user":{
"token":"secret"
}
}
],
"contexts":[
{
"name":"webhook",
"context":{
"cluster":"github-authn",
"user":"authn-apiserver"
}
}
],
"current-context":"webhook"
}

鉴权

授权主要是用于对集群资源的访问控制,通过检查请求包含的相关属性值,与相对应的访问策略相比较,API请求必须满足某些策略才能被处理。跟认证类似,Kubernetes也支持多种授权机制,并支持同时开启多个授权插件(只要有一个验证通过即可)。如果授权成功,则用户的请求会发送到准入控制模块做进一步的请求验证;对于授权失败的请求则返回HTTP 403。

Kubernetes授权仅处理以下的请求属性:

  • user, group, extra
  • API、请求方法(如get、post、update、patch和delete)和请求路径(如/api)
  • 请求资源和子资源
  • Namespace
  • API Group

目前,Kubernetes支持以下授权插件:

  • ABAC: 基于配置的权限控制
  • RBAC: 基于角色的权限控制
  • Webhook: 基于webhook服务的外部权限控制
  • Node:控制不同Node节点的权限范围

Kubenetes RBAC vs ABAC

ABAC(Attribute Based Access Control)本来是不错的概念,但是在Kubernetes 中的实现比较难于管理和理解,而且需要对Master 所在节点的SSH 和文件系统权限,要使得对授权的变更成功生效,还需要重新启动API Server。

而RBAC 的授权策略可以利用kubectl 或者Kubernetes API 直接进行配置。RBAC 可以授权给用户,让用户有权进行授权管理,这样就可以无需接触节点,直接进行授权管理。RBAC 在Kubernetes中被映射为API 资源和操作。

k8s RBAC

1696944997330

注: RoleBinding 可以绑定clusterRole, 但是会限定权限在namespace下

Role与ClusterRole

Role(角色)是一系列权限的集合,例如一个角色可以包含读取Pod 的权限和列出Pod 的权限。Role只能用来给某个特定namespace中的资源作鉴权,对多namespace和集群级的资源或者是非资源类的API(如/healthz)使用ClusterRole。

1696945205437

Binding

1696946224850

账户/组的管理

角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。
它包含若干主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。

组的概念:

  • 当与外部认证系统对接时,用户信息(UserInfo)可包含Group信息,授权可针对用户群组
  • 当对ServiceAccount授权时,Group代表某个Namespace下的所有ServiceAccount

Group 方式的binding

1696946618776

Kubernetets API总览

REST API 是 Kubernetes 的基础架构。组件之间的所有操作和通信,以及外部用户命令都是 API Server 处理的 REST API 调用。因此,Kubernetes 平台中的所有资源被视为 API 对象,并且在 API 中都有对应的定义项。

API 版本控制

为了消除字段或重组资源表示形式,Kubernetes 支持多个 API 版本,每个版本在不同的 API 路径下。例如:/api/v1 或者 /apis/extensions/v1beta1。

版本是在 API 级别而非资源或字段级别配置的:

  • 确保 API 呈现出清晰一致的系统资源和行为视图。
  • 允许控制对已寿终正寝的 API 和/或实验性 API 的访问。 JSON 和 Protobuf 序列化模式在出现模式变更时均遵循这些准则。以下说明同时适用于这两种格式。

API 结构组成

1
`https:``//127``.0.0.1:6443``/api/v1/pods`

解释 组成

API Server address https://127.0.0.1:6443/

Core API group api/v1

API Object pods

1
`https:``//127``.0.0.1:6443``/apis/extensions/v1beta/deployments`

解释 组成

API Server address https://127.0.0.1:6443/

Core API group apis

API Group name extensions

API Version v1beta

API Object deployments

规划系统角色

User

  • 管理员
    • 所有资源的所有权限?? 不应该包含secret
  • 普通用户
    • 是否有该用户创建的namespace下的所有object的操作权限?
    • 对其他用户的namespace资源是否可读,是否可写?

SystemAccount

  • SystemAccount是开发者(kubernetes developer或者domain developer)创建应用后,应用于apiserver通讯需要的身份
  • 用户可以创建自定的ServiceAccount,kubernetes也为每个namespace创建default ServiceAccount
  • Default ServiceAccount通常需要给定权限以后才能对apiserver做写操作

准入

准入控制

准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数。不同于授权和认证只关心请求的用户和操作,准入控制还处理请求的内容,并且仅对创建、更新、删除或连接(如代理)等有效,而对读操作无效。

准入控制支持同时开启多个插件,它们依次调用,只有全部插件都通过的请求才可以放过进入系统。

举例:为资源增加自定义属性

  • 作为多租户集群方案中的一环,我们需要在namespace的准入控制中,获取用户信息,并将用户信息更新到namespace的annotation
  • 只有当namespace中有有效用户信息时,我们才可以在namespace创建时,自动绑定用户权限,namespace才可用。

准入控制插件

可以通过kube-apiserver --help 可以看到--enable-admmision-plugins 参数, 它可以指定额外的插件, 并可以看到默认init的插件,下方为常用插件

  • AlwaysAdmit: 接受所有请求。
  • AlwaysPullImages: 总是拉取最新镜像。在多租户场景下非常有用。
  • DenyEscalatingExec: 禁止特权容器的exec和attach操作。
  • ImagePolicyWebhook: 通过webhook决定image策略,需要同时配置–admission-controlconfig-file
  • ServiceAccount:自动创建默认ServiceAccount,并确保Pod引用的ServiceAccount已经存在
  • SecurityContextDeny:拒绝包含非法SecurityContext配置的容器
  • ResourceQuota:限制Pod的请求不会超过配额,需要在namespace中创建一个ResourceQuota对象
  • LimitRanger:为Pod设置默认资源请求和限制,需要在namespace中创建一个LimitRange对象
  • InitialResources:根据镜像的历史使用记录,为容器设置默认资源请求和限制
  • NamespaceLifecycle:确保处于termination状态的namespace不再接收新的对象创建请求,并拒绝请求不存在的namespace
  • DefaultStorageClass:为PVC设置默认StorageClass
  • DefaultTolerationSeconds:设置Pod的默认forgiveness toleration为5分钟
  • PodSecurityPolicy:使用Pod Security Policies时必须开启
  • NodeRestriction:限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源

准入插件开发

除默认的准入控制插件以外,Kubernetes预留了准入控制插件的扩展点,用户可自定义准入控制插件实现自定义准入功能

  • MutatingWebhookConfiguration:变形插件,支持对准入对象的修改
  • ValidatingWebhookConfiguration:校验插件,只能对准入对象合法性进行校验,不能修改

1697033914305

创建控制配置对象

案例:为资源增加自定义属性

  • 作为多租户集群方案中的一环,我们需要在namespace的准入控制中,获取用户信息,并将用户信息更新的namespace的annotation
  • 只有当namespace中有有效用户信息时,我们才可以在namespace创建时,自动绑定用户权限,namespace才可用。

先编写准入控制器的服务端代码- 可以修改 admission 对象

![image-20231013120616282](../../../img/控制平面组件 APIServer/image-20231013120616282.png)

创建 MutatingWebhookConfiguration

通过 kubectl apply -f 创建对象

1697034148760

  • url: apiserver 访问的地址
  • rules: 什么样的对象什么样的操作, 需要访问webhook

准入控制场景-配额管理

配额管理

原因:资源有限,如何限定某个用户有多少资源?

方案:

  • 预定义每个Namespace的ResourceQuota,并把spec保存为configmap
    • 用户可以创建多少个Pod
      • BestEffortPod
      • QoSPod
    • 用户可以创建多少个service
    • 用户可以创建多少个ingress
    • 用户可以创建多少个service VIP
  • 创建ResourceQuota Controller
    • 监控namespace创建事件,当namespace创建时,在该namespace创建对应的ResourceQuota 对象
    • apiserver中开启ResourceQuota的admission plugin

限流

常用限流算法

  • 计数器固定窗口算法
  • 滑动窗口算法
  • 漏斗算法:适合限制平均流量
  • 令牌桶算法: 适合限制峰值流量

APISERVER的限流

  • max-requests-inflight: 在给定时间内的最大non-mutating 请求数
  • max-mutating-requests-inflight: 在给定时间内的最大mutating 请求数,调整apiserver 的流控qos

代码:staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go:WithMaxInFlightLimit()

1697115665586

传统限流方法的局限性

  • 粒度粗
    • 无法为不同用户,不同场景设置不通的限流
  • 单队列
    • 共享限流窗口/桶,一个坏用户可能会将整个系统堵塞,其他正常用户的请求无法被及时处理
  • 不公平
    • 正常用户的请求会被排到队尾,无法及时处理而饿死
  • 无优先级
    • 重要的系统指令一并被限流,系统故障难以恢复

API Priority and Fairness

为了防止不同用户和使用方对资源的竞争和不公平

  • APF 以更细粒度的方式对请求进行分类和隔离。
  • 它还引入了空间有限的排队机制,因此在非常短暂的突发情况下,API 服务器不会拒绝任何请求。
  • 通过使用公平排队技术从队列中分发请求,这样, 一个行为不佳的控制器就不会饿死其他控制器(即使优先级相同)。

APF的核心

  • 多等级: 不同颜色代表不同等级
  • 多队列: 不同颜色Flow代表不同优先级队列

1697116031202

  • APF 的实现依赖两个非常重要的资源FlowSchema:定义Flow限流信息, PriorityLevelConfiguration:定义队列优先级
    • 可以通过 kubenetes get flowsschema 获取FlowSchema信息
    • 通过 kubenetes get prioritylevelconfiguration 查看优先级队列
  • APF 对请求进行更细粒度的分类,每一个请求分类对应一个FlowSchema (FS)
  • FS 内的请求又会根据distinguisher 进一步划分为不同的Flow.
  • FS 会设置一个优先级(Priority Level, PL),不同优先级的并发资源是隔离的。所以不同优先级的资源不会相互排挤。特定优先级的请求可以被高优处理。
  • 一个PL 可以对应多个FS,PL 中维护了一个QueueSet,用于缓存不能及时处理的请求,请求不会因为超出PL 的并发限制而被丢弃。
  • FS 中的每个Flow 通过shuffle sharding 算法从QueueSet 选取特定的queues 缓存请求。
  • 每次从QueueSet 中取请求执行时,会先应用fair queuing 算法从QueueSet 中选中一个queue,然后从这个queue中取出oldest 请求执行。所以即使是同一个PL 内的请求,也不会出现一个Flow 内的请求一直占用资源的不公平现象。

APF概念

  • 传入的请求通过FlowSchema 按照其属性分类,并分配优先级。
  • 每个优先级维护自定义的并发限制,加强了隔离度,这样不同优先级的请求,就不会相互饿死。
  • 在同一个优先级内,公平排队算法可以防止来自不同flow 的请求相互饿死。
  • 该算法将请求排队,通过排队机制,防止在平均负载较低时,通信量突增而导致请求失败。

如何配置

FlowSchema 配置示例

1697118736414

PriorityLevelConfiguration 配置示例

1697118761511

优先级

  • 如果未启用APF,API 服务器中的整体并发量将受到kube-apiserver 的参数–maxrequests-inflight 和–max-mutating-requests-inflight 的限制。
  • 启用APF 后,将对这些参数定义的并发限制进行求和,然后将总和分配到一组可配置的优先级中。每个传入的请求都会分配一个优先级;
    • 分配方式是根据 PriorityLevelConfiguration.Spec.Limited.AssuredConcurrencyShares 的数值按比例分配,PL 的 AssuredConcurrencyShare 越大,分配到的并发份额越大。
  • 每个优先级都有各自的配置,设定允许分发的并发请求数。
  • 例如,默认配置包括针对领导者选举请求、内置控制器请求和Pod 请求都单独设置优先级。这表示即使异常的Pod 向API 服务器发送大量请求,也无法阻止领导者选举或内置控制器的操作执行成功。

排队

  • 即使在同一优先级内,也可能存在大量不同的流量源。
  • 在过载情况下,防止一个请求流饿死其他流是非常有价值的(尤其是在一个较为常见的场景中,一个有故障的客户端会疯狂地向kube-apiserver 发送请求, 理想情况下,这个有故障的客户端不应对其他客户端
    产生太大的影响)。
  • 公平排队算法在处理具有相同优先级的请求时,实现了上述场景。
  • 每个请求都被分配到某个流中,该流由对应的FlowSchema 的名字加上一个流区分项(FlowDistinguisher) 来标识。
  • 这里的流区分项可以是发出请求的用户、目标资源的名称空间或什么都不是。
  • 系统尝试为不同流中具有相同优先级的请求赋予近似相等的权重。
  • 将请求划分到流中之后,APF 功能将请求分配到队列中。
  • 分配时使用一种称为混洗分片(Shuffle-Sharding) 的技术。该技术可以相对有效地利用队列隔离低强度流与高强度流。
  • 排队算法的细节可针对每个优先等级进行调整,并允许管理员在内存占用、公平性(当总流量超标时,各
    个独立的流将都会取得进展)、突发流量的容忍度以及排队引发的额外延迟之间进行权衡。

默认flow配置

  • system
    • 用于system:nodes 组(即kubelets)的请求; kubelets 必须能连上API 服务器,以便工作负载能够调度到其上。
  • eader-election
    • 用于内置控制器的领导选举的请求(特别是来自kube-system 名称空间中system:kubecontroller-manager 和system:kube-scheduler 用户和服务账号,针对endpoints、configmaps 或leases 的请求)。
    • 将这些请求与其他流量相隔离非常重要,因为领导者选举失败会导致控制器发生故障并重新启动,这反过来会导致新启动的控制器在同步信息时,流量开销更大。
  • workload-high
    • 优先级用于内置控制器的请求。
  • workload-low
    • 优先级适用于来自任何服务帐户的请求,通常包括来自Pods 中运行的控制器的所有请求。
  • global-default
    • 优先级可处理所有其他流量,例如:非特权用户运行的交互式kubectl 命令。
  • exempt
    • 优先级的请求完全不受流控限制:它们总是立刻被分发。特殊的exempt FlowSchema把system:masters 组的所有请求都归入该优先级组。
  • catch-all
    • 优先级与特殊的catch-all FlowSchema 结合使用,以确保每个请求都分类。
    • 一般不应该依赖于catch-all 的配置,而应适当地创建自己的catch-all FlowSchema 和PriorityLevelConfigurations(或使用默认安装的global-default 配置)。
    • 为了帮助捕获部分请求未分类的配置错误,强制要求catch-all 优先级仅允许5个并发份额,并且不对请求进行排队,使得仅与catch-all FlowSchema 匹配的流量被拒绝的可能性更高,并显示HTTP 429 错误。

调试命令

  • /debug/api_priority_and_fairness/dump_priority_levels —— 所有优先级及其当前状态的列表

    kubectl get –raw /debug/api_priority_and_fairness/dump_priority_levels

  • /debug/api_priority_and_fairness/dump_queues —— 所有队列及其当前状态的列表

    kubectl get –raw /debug/api_priority_and_fairness/dump_queues

  • /debug/api_priority_and_fairness/dump_requests ——当前正在队列中等待的所有请求的列表

    kubectl get –raw /debug/api_priority_and_fairness/dump_requests

高可用apiserver

启动apiserver 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kube-apiserver --feature-gates=AllAlpha=true --runtime-config=api/all=true \
--requestheader-allowed-names=front-proxy-client \
--client-ca-file=/etc/kubernetes/pki/ca.crt \
--allow-privileged=true \
--experimental-bootstrap-token-auth=true \
--storage-backend=etcd3 \
--requestheader-username-headers=X-Remote-User \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--service-account-key-file=/etc/kubernetes/pki/sa.pub \
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt \
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key \
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt \
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt \
--enabled-hooks=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota \
--requestheader-group-headers=X-Remote-Group \
--kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key \
--secure-port=6443 \
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \
--service-cluster-ip-range=10.96.0.0/12 \
--advertise-address=192.168.0.20 --etcd-servers=http://127.0.0.1:2379

构建高可用的多副本apiserver

apiserver 的特性

apiserver是无状态的Rest Server

无状态所以方便Scale Up/down

实现apiserver高可用核心办法–负载均衡

  • 在多个apiserver实例之上,配置负载均衡
  • 证书可能需要加上Loadbalancer VIP重新生成

预留充足的CPU、内存资源

随着集群中节点数量不断增多,APIServer对CPU和内存的开销也不断增大。过少的CPU资源会降低其处理效率,过少的内存资源会导致Pod被OOMKilled,直接导致服务不可用。

在规划APIServer资源时,不能仅看当下需求,也要为未来预留充分。

善用速率限制(RateLimit)

新版本的kubenetes APF是默认开启打的

APIServer的参数“–max-requests-inflight”和“–max-mutating-requests-inflight”支持在给定时间内限制并行处理读请求(包括Get、List和Watch操作)和写请求(包括Create、Delete、Update和Patch操作)的最大数量。

当APIServer接收到的请求超过这两个参数设定的值时,再接收到的请求将会被直接拒绝。通过速率限制机制,可以有效地控制APIServer内存的使用。

如果该值配置过低,会经常出现请求超过限制的错误,如果配置过高,则APIServer可能会因为占用过多内存而被强制终止,因此需要根据实际的运行环境,结合实时用户请求数量和APIServer的资源配置进行调优。

客户端在接收到拒绝请求的返回值后,应等待一段时间再发起重试,无间隔的重试会加重APIServer的压力,导致性能进一步降低。针对并行处理请求数的过滤颗粒度太大,在请求数量比较多的场景,重要的消息可能会被拒绝掉,自1.18版本开始,社区引入了优先级和公平保证(Priority and Fairness)功能,以提供更细粒度地客户端请求控制。该功能支持将不同用户或不同类型的请求进行优先级归类,保证高优先级的请求总是能够更快得到处理,从而不受低优先级请求的影响。

设置合适的缓存大小

读的请求量比较大的时候, 合理的设置cache-size, 并尽量避免使用指定resourceVersion查询

APIServer与etcd之间基于gRPC协议进行通信,gRPC协议保证了二者在大规模集群中的数据高速传输。gRPC基于连接复用的HTTP/2协议,即针对相同分组的对象,APIServer和etcd之间共享相同的TCP连接,不同请求由不同的stream传输。

一个HTTP/2连接有其stream配额,配额的大小限制了能支持的并发请求。APIServer提供了集群对象的缓存机制,当客户端发起查询请求时,APIServer默认会将其缓存直接返回给客户端。缓存区大小可以通过参数“–watch-cache-sizes”设置。针对访问请求比较多的对象,适当设置缓存的大小,极大降低对etcd的访问频率,节省了网络调用,降低了对etcd集群的读写压力,从而提高对象访问的性能。

但是APIServer也是允许客户端忽略缓存的,例如客户端请求中ListOption中没有设置resourceVersion,这时APIServer直接从etcd拉取最新数据返回给客户端。客户端应尽量避免此操作,应在ListOption中设置resourceVersion为0,APIServer则将从缓存里面读取数据,而不会直接访问etcd。

客户端尽量使用长连接

当查询请求的返回数据较大且此类请求并发量较大时,容易引发TCP链路的阻塞,导致其他查询操作超时。

因此基于Kubernetes开发组件时,例如某些DaemonSet和Controller,如果要查询某类对象,应尽量通过长连接ListWatch监听对象变更,避免全量从APIServer获取资源。如果在同一应用程序中,如果有多个Informer监听APIServer资源变化,可以将这些Informer合并,减少和APIServer的长连接数,从而降低对APIServer的压力。

访问APIServe

  • 对外部客户(user/client/admin),永远只通过LoadBalancer访问
  • 只有当负载均衡出现故障时,管理员才切换到apiserver IP进行管理
  • 内部客户端,优先访问cluster IP(default namespace 下的一个Service)

搭建多租户的Kubernetes集群(总结)

授信

  • 认证:
    • 禁止匿名访问,只允许可信用户做操作。
  • 授权:
    • 基于授信的操作,防止多用户之间互相影响,比如普通用户删除Kubernetes核心服务,或者A用户删除或修改B用户的应用。

隔离

  • 可见行隔离:
    • 用户只关心自己的应用,无需看到其他用户的服务和部署。
  • 资源隔离:
    • 有些关键项目对资源需求较高,需要专有设备,不与其他人共享。
  • 应用访问隔离:
    • 用户创建的服务,按既定规则允许其他用户访问。

资源管理

  • Quota管理
    • 谁能用多少资源?
刘小恺(Kyle) wechat
如有疑问可联系博主