文章目录

  • API Server
  • 访问控制概览
  • 访问控制细节
  • 认证
  • 认证插件
  • 基于webhook的认证服务集成
  • 鉴权
  • RBAC vs ABAC
  • binding
  • 账户/组的管理
  • 针对群租授权
  • 规划系统角色
  • 实现方案
  • 与权限相关的其他最佳实践
  • 运营过程中出现的陷阱
  • 准入
  • 准入控制
  • 准入控制插件
  • 准入控制插件的开发
  • 配额管理
  • 实践操作
  • 限流
  • 计数器固定窗口算法
  • 计数器滑动窗口算法
  • 漏斗算法
  • 令牌桶算法
  • APIServer中的限流
  • 传统限流方法的局限性
  • API Priority and Fairness
  • 实践分析
  • 概念
  • 优先级
  • 排队
  • 豁免请求
  • 默认配置
  • PriorityLevelConfiguration
  • FlowSchema
  • 调试
  • 高可用APIServer
  • 构建高可用的多副本apiserver
  • 预留充足的CPU、内存资源
  • 善用速率限制(RateLimit)
  • 设置合适的缓存大小
  • 客户端尽量使用长连接
  • 如何访问APIServer
  • 搭建多租户的Kubernetes集群
  • 认证
  • 注册APIService
  • apimachinery
  • 如何定义Group
  • 定义对象类型 types.go
  • 代码生成Tags
  • 实现etcd storage
  • 创建和更新对象时的业务逻辑-Strategy
  • subresource
  • 注册APIGroup
  • 代码生成
  • hack/update-codegen.sh
  • APIServer代码


k8s环境-Test

平台:腾讯云-TKE

kubernetes安装 apiserver 2379端口 kube-apiserver_Server

API Server

kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能
• 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
• 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd)

访问控制概览

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

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_02

apiserver本身是一个rust server,首先要有一个http handler来处理不同版本的请求,接收到请求之后要做认证、鉴权,然后到转变,对应两个webhook(可以自定义开发,在到达mutating步骤时,apiserver会校验有没有对应的webhook,有的话则会被调用,改变对象的值webhook会进行回转),接下来到schema步骤,apiserver会继续校验这个对象是不是有效的(主要是k8s内嵌的逻辑),

访问控制细节

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_03

红色箭头为整个apiserver细节调用链:
首先会做request-timeout的检查,然后做认证相关的校验,接下来到audit,主要记录k8s的日志审计(谁在哪个时间点修改了对象?)
inpersonation(不太常用),在请求的handler里边模拟用户请求(a用户代替b用户)
max-in-flight(用作限流),可以设置多少个请求发到apiserver,但是还没有返回,可以理解为在整个调用过程中设置上限值
authorization 做鉴权
kube-aggregator(抽象为多个apiserver汇总),本身是一个api gateway,大概可以理解为它可以分配多个apiserver来进行任务处理,把其中的一部分请求转到其他apiserver做处理
resource handler,首先会解码——》做准入——》校验——》存储etcd中

认证

开启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”
参考资料:https://github.com/cncamp/101/blob/master/module6/basic-auth/static-token.csv

## Static token
### Put static-token to target folder

mkdir -p /etc/kubernetes/auth
cp static-token /etc/kubernetes/auth

### Backup your orginal apiserver

cp /etc/kubernetes/manifests/kube-apiserver.yaml ~/kube-apiserver.yaml

### Override your kube-apiserver with the one with static-token config

cp ./kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml

### Get kubernetes object with static token

curl https://192.168.34.2:6443/api/v1/namespaces/default -H "Authorization: Bearer cncamp-token" -k

引导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目录中。
创建ns默认都会创建一个,自动会mount到容器里边。

~]# kubectl get sa -oyaml
apiVersion: v1
items:
- apiVersion: v1
  kind: ServiceAccount
  metadata:
    creationTimestamp: "2022-01-06T12:12:13Z"
    name: default
    namespace: default
    resourceVersion: "383"
    selfLink: /api/v1/namespaces/default/serviceaccounts/default
    uid: ba297c44-2a92-4c17-9db2-9e804e76d4b1
  secrets:
  - name: default-token-zj56s	#同时k8s会创建一个secret
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

~]# kubectl get secret default-token-zj56s -oyaml
。。。
这个文件中会带有ns、ca文件、token,是apiserver给颁发的

echo "token的值" |base64 -d 
是一个标准的gwt token,apiserver颁发的——》解码
用这个token文件去访问apiserver,就会知道是哪个用户访问的?

1、当开发k8s组件时,例如写operator,理论上要监听集群apiserver来获取数据,有没有权限读/写 完全要基于身份
2、团队希望每个人有自己的sa,来单独做调试

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_04

OpenID
• OAuth 2.0的认证机制

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

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

基于webhook的认证服务集成

参考资料:https://github.com/cncamp/101/tree/master/module6/authn-webhook

构建符合Kubernetes规范的认证服务
需要依照Kubernetes规范,构建认证服务,用来认证tokenreview request
认证服务需要满足如下Kubernetes的规范

URL: https://authn.example.com/authenticate
Method: POST
Input:
Output:

kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_05

鉴权

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

Kubernetes授权仅处理以下的请求属性:
• user, group, extra
• API、请求方法(如get、post、update、patch和delete)和请求路径(如/api) • 请求资源和子资源
• Namespace
• API Group
目前,Kubernetes支持以下授权插件:
• ABAC
• RBAC
• Webhook
• Node

RBAC vs ABAC

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

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

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_06


kubernetes安装 apiserver 2379端口 kube-apiserver_后端_07

k8s设计了一系列对象,例如:Role(代表角色),里边定义了一些resources资源和verb(动作),称为一组对象的操作权限聚合成一个角色,subject(抽象为主体)分为user(外部用户)和serviceaccount(内部用户)两种,subject和role通过rolebinding产生关联,最终rbac的定位是谁对哪些对象做什么样的操作;
clusterrole和role的区别:
有时候角色(clusterrole)是一个全局的,role跟namespace是关联的,可以在某一个ns下创建role,clusterrole在整个集群下可以授权给其他用户权限,带clusterrole均为全局性的。

专业术语:

Role(角色)是一系列权限的集合,例如一个角色可以包含读取 Pod 的权限和列出 Pod 的权限。

Role只能用来给某个特定namespace中的资源作鉴权,对多namespace和集群级的资源或者是非资源类的API(如/healthz)使用ClusterRole。

kubernetes安装 apiserver 2379端口 kube-apiserver_API_08

binding

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_09

账户/组的管理

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

组的概念:

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

kubernetes安装 apiserver 2379端口 kube-apiserver_API_10

规划系统角色

User
• 管理员
所有资源的所有权限??
• 普通用户
是否有该用户创建的namespace下的所有object的操作权限?
对其他用户的namespace资源是否可读,是否可写?
SystemAccount
• SystemAccount是开发者(kubernetes developer或者domain developer)创建应用后,应用于apiserver通讯需要的身份
• 用户可以创建自定的ServiceAccount,kubernetes也为每个namespace创建default ServiceAccount
• Default ServiceAccount通常需要给定权限以后才能对apiserver做写操作

实现方案

在cluster创建时,创建自定义的role,比如namespace-creator
Namespace-creator role定义用户可操作的对象和对应的读写操作。
创建自定义的namespace admission controller
• 当namespace创建请求被处理时,获取当前用户信息并annotate到namespace
创建RBAC controller
• Watch namespace的创建事件
• 获取当前namespace的创建者信息
• 在当前namespace创建rolebinding对象,并将namespace-creator 角色和用户绑定

与权限相关的其他最佳实践

ClusterRole是非namespace绑定的,针对整个集群生效
通常需要创建一个管理员角色,并且绑定给开发运营团队成员
ThirdPartyResource和CustomResourceDefinition是全局资源,普通用户创建
ThirdPartyResource以后,需要管理员授予相应权限后才能真正操作该对象
针对所有的角色管理,建议创建spec,用源代码驱动

  • 虽然可以通过edit操作来修改权限,但后期会导致权限管理混乱,可能会有很多临时创建出来的角色和角色绑定对象,重复绑定某一个资源权限
    权限是可以传递的,用户A可以将其对某对象的某操作,抽取成一个权限,并赋给用户B防止海量的角色和角色绑定对象,因为大量的对象会导致鉴权效率低,同时给apiserver增加负担
    ServiceAccount也需要授权的,否则你的component可能无法操作某对象
    Tips:SSH到master节点通过insecure port访问apiserver可绕过鉴权,当需要做管理操作又没有权限时可以使用(不推荐)
运营过程中出现的陷阱

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_11

准入

准入控制

为资源增加自定义属性

  • 作为多租户集群方案中的一环,我们需要在namespace的准入控制中,获取用户信息,并将用户信息更新的namespace的annotation
    只有当namespace中有有效用户信息时,我们才可以在namespace创建时,自动绑定用户权限,namespace即可使用。
  • 准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数。不同于授权和认证只关心请求的用户和操作,准入控制还处理请求的内容,并且仅对创建、更新、删除或连接(如代理)等有效,而对读操作无效
  • 准入控制支持同时开启多个插件,它们依次调用,只有全部插件都通过的请求才可以放过进入系统。
准入控制插件

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:校验插件,只能对准入对象合法性进行校验,不能修改

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_12

配额管理

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

方案:

  • 预定义每个Namespace的ResourceQuota,并把spec保存为configmap
  • 用户可以创建多少个Pod
  • BestEffortPod
  • QoSPod
  • 用户可以创建多少个service
  • 用户可以创建多少个ingress
  • 用户可以创建多少个service VIP
  • 创建ResourceQuota Controller
  • 监控namespace创建事件,当namespace创建时,在该namespace创建对应的ResourceQuota 对象
  • apiserver中开启ResourceQuota的admission plugin
实践操作
场景:在认证、授权之后使用webhook来做准入控制。
~]# git clone https://github.com/cncamp/admission-controller-webhook-demo.git
[root@VM-0-16-centos ~]# kubectl get mutatingwebhookconfiguration
NAME                       WEBHOOKS   AGE
base-operator              3          16d
cert-manager-webhook-new   1          16d
cluster-transformer        2          16d
courier                    4          16d
metis                      8          16d
spark-webhook-config       1          16d
ti-admission-webhook       6          16d
validateimage              1          16d
vpa-webhook-config         1          16d
warlock                    1          16d

[root@VM-0-16-centos ~/p_ywcheng/admission-controller-webhook-demo]# bash deploy.sh 
Generating TLS keys ...
Generating a 2048 bit RSA private key
...................................................+++
...............+++
writing new private key to 'ca.key'
-----
Generating RSA private key, 2048 bit long modulus
.........+++
................................................+++
e is 65537 (0x10001)
Signature ok
subject=/CN=webhook-server.webhook-demo.svc
Getting CA Private Key
Creating Kubernetes objects ...
namespace/webhook-demo created
secret/webhook-server-tls created
deployment.apps/webhook-server created
service/webhook-server created
mutatingwebhookconfiguration.admissionregistration.k8s.io/demo-webhook created
The webhook server has been deployed and configured!

kubectl get mutatingwebhookconfiguration.admissionregistration.k8s.io/demo-webhook -oyaml
.....
caBundle参数:相信webhook启的https证书
    service:
      name: webhook-server
      namespace: webhook-demo
      path: /mutate
      port: 443
.....
kubectl get svc -nwebhook-demo
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
webhook-server   ClusterIP   10.106.194.34   <none>        443/TCP   4m56s

kubectl get deploy/webhook-server -nwebhook-demo
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
webhook-server   1/1     1            1           27m

kubectl get pod -nwebhook-demo
NAME                             READY   STATUS    RESTARTS   AGE
webhook-server-988f9f4f9-gcc9z   1/1     Running   0          27m

#测试访问webhook-demo
curl https://10.106.194.34/mutate -k
invalid method GET, only POST requests are allowed
#说明已经开启了mutatingwebhook

kubectl create -f examples/pod-with-defaults.yaml
kubectl get po  pod-with-defaults -oyaml
kubectl logs -f pod-with-defaults

kubernetes安装 apiserver 2379端口 kube-apiserver_API_13

Pod启动失败!
 kubectl get pod nginx-demo -oyaml
  securityContext:
    runAsNonRoot: true
    runAsUser: 1234		#需要以userid为1234的用户来运行此程序

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_14

限流

计数器固定窗口算法

kubernetes安装 apiserver 2379端口 kube-apiserver_API_15

计数器滑动窗口算法

kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_16

漏斗算法

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_17

令牌桶算法

kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_18

APIServer中的限流

max-requests-inflight: 在给定时间内的最大 non-mutating 请求数

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

代码

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

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_19

传统限流方法的局限性

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_20

API Priority and Fairness

k8s 1.18以后 组件:顾忌到公平和优先级

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_21


kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_22


flowschema用来定义一个个flow,prioritylevelconfiguration定义队列优先级

实践分析
➜ ~ kubectl get flowschema
NAME                           PRIORITYLEVEL     MATCHINGPRECEDENCE   DISTINGUISHERMETHOD   AGE   MISSINGPL
exempt(豁免)                         exempt            1                    <none>                66d   False
probes(健康检测)                         exempt            2                    <none>                66d   False
system-leader-election         leader-election   100                  ByUser                66d   False
workload-leader-election       leader-election   200                  ByUser                66d   False
system-node-high               node-high         400                  ByUser                66d   False
system-nodes                   system            500                  ByUser                66d   False
kube-controller-manager        workload-high     800                  ByNamespace           66d   False
kube-scheduler                 workload-high     800                  ByNamespace           66d   False
kube-system-service-accounts   workload-high     900                  ByNamespace           66d   False
service-accounts               workload-low      9000                 ByUser                66d   False
global-default                 global-default    9900                 ByUser                66d   False
catch-all(以上都没有占到的话才用)                      catch-all         10000                ByUser                66d   False

➜ ~ kubectl get flowschema service-accounts -oyaml
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: FlowSchema	#如何定义一个flow
metadata:
  annotations:
    apf.kubernetes.io/autoupdate-spec: "true"
  creationTimestamp: "2021-12-10T09:11:25Z"
  generation: 1
  name: service-accounts
  resourceVersion: "66"
  uid: 2bb0d2a3-563c-4d7b-b4c4-53cd708c258b
spec:
  distinguisherMethod:	#标识一个flow的唯一性
    type: ByUser	#类型为byuser,不同的service-account flow是不一样的
  matchingPrecedence: 9000	#规则的优先级,数字越小优先级越高
  priorityLevelConfiguration:	#这个flow请求最终由哪个队列去处理
    name: workload-low
  rules:	#规则,什么样的操作会被限流
  - nonResourceRules:
    - nonResourceURLs:	#例如:kubectl get ns default -v 9获得的结果:/api/v1/namespaces/cyw
      - '*'
      verbs:
      - '*'
    resourceRules:
    - apiGroups:
      - '*'
      clusterScope: true
      namespaces:
      - '*'
      resources:
      - '*'
      verbs:
      - '*'
    subjects:
    - group:
        name: system:serviceaccounts
      kind: Group
status:
  conditions:
  - lastTransitionTime: "2021-12-10T09:11:25Z"
    message: This FlowSchema references the PriorityLevelConfiguration object named
      "workload-low" and it exists
    reason: Found
    status: "False"
    type: Dangling

查看当前集群所有的优先队列
➜ ~ kubectl get PriorityLevelConfiguration
NAME              TYPE      ASSUREDCONCURRENCYSHARES   QUEUES   HANDSIZE   QUEUELENGTHLIMIT   AGE
catch-all         Limited   5                          <none>   <none>     <none>             66d
exempt            Exempt    <none>                     <none>   <none>     <none>             66d
global-default    Limited   20                         128      6          50                 66d
leader-election   Limited   10                         16       4          50                 66d
node-high         Limited   40                         64       6          50                 66d
system            Limited   30                         64       6          50                 66d
workload-high     Limited   40                         128      6          50                 66d
workload-low      Limited   100                        128      6          50                 66d

➜ ~ kubectl get PriorityLevelConfiguration workload-low -oyaml
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: PriorityLevelConfiguration
metadata:
  annotations:
    apf.kubernetes.io/autoupdate-spec: "true"
  creationTimestamp: "2021-12-10T09:11:25Z"
  generation: 1
  name: workload-low
  resourceVersion: "21"
  uid: b8110060-368b-45e1-981c-31891e259d6a
spec:
  limited:
    assuredConcurrencyShares: 100
    limitResponse:
      queuing:
        handSize: 6
        queueLengthLimit: 50
        queues: 128
      type: Queue
  type: Limited
status: {}


➜ ~ kubectl get flowschema exempt -oyaml
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: FlowSchema
metadata:
  annotations:
    apf.kubernetes.io/autoupdate-spec: "true"
  creationTimestamp: "2021-12-10T09:11:25Z"
  generation: 1
  name: exempt
  resourceVersion: "61"
  uid: 89953d28-4f0a-4949-bbbd-b14c26082664
spec:
  matchingPrecedence: 1		#优先级最高的
  priorityLevelConfiguration:
    name: exempt
  rules:
  - nonResourceRules:
    - nonResourceURLs:
      - '*'
      verbs:
      - '*'
    resourceRules:
    - apiGroups:
      - '*'
      clusterScope: true
      namespaces:
      - '*'
      resources:
      - '*'
      verbs:
      - '*'
    subjects:
    - group:
        name: system:masters	#这个角色具备豁免权
      kind: Group
status:
  conditions:
  - lastTransitionTime: "2021-12-10T09:11:25Z"
    message: This FlowSchema references the PriorityLevelConfiguration object named
      "exempt" and it exists
    reason: Found
    status: "False"
    type: Dangling

➜ ~ kubectl get priorityLevelConfiguration exempt  -oyaml
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: PriorityLevelConfiguration
metadata:
  annotations:
    apf.kubernetes.io/autoupdate-spec: "true"
  creationTimestamp: "2021-12-10T09:11:25Z"
  generation: 1
  name: exempt
  resourceVersion: "26"
  uid: 0b9fd349-384b-4fad-8e03-795aacb50c38
spec:
  type: Exempt	#对于最重要的请求,都会豁免
status: {}
概念

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_23

优先级

kubernetes安装 apiserver 2379端口 kube-apiserver_API_24

排队

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_25

豁免请求

某些特别重要的请求不受制于此特性施加的任何限制。这些豁免可防止不当的流控配置完全禁用API 服务器。

默认配置

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_26


kubernetes安装 apiserver 2379端口 kube-apiserver_Server_27

PriorityLevelConfiguration

一个 PriorityLevelConfiguration 表示单个隔离类型。

每个 PriorityLevelConfigurations 对未完成的请求数有各自的限制,对排队中的请求数也有限制。

kubernetes安装 apiserver 2379端口 kube-apiserver_API_28

FlowSchema

FlowSchema 匹配一些入站请求,并将它们分配给优先级。

每个入站请求都会对所有 FlowSchema 测试是否匹配, 首先从 matchingPrecedence 数值最低的匹配开始(我们认为这是逻辑上匹配度最高), 然后依次进行,直到首个匹配出现。

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_29

调试

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_30

➜ ~ kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
PriorityLevelName, ActiveQueues, IsIdle, IsQuiescing, WaitingRequests, ExecutingRequests
workload-high,     0,            true,   false,       0,               0
workload-low,      0,            true,   false,       0,               0
catch-all,         0,            true,   false,       0,               0
exempt,            <none>,       <none>, <none>,      <none>,          <none>
global-default,    0,            true,   false,       0,               0
leader-election,   0,            true,   false,       0,               0
node-high,         0,            true,   false,       0,               0
system,            0,            true,   false,       0,               0

#集群所有队列查看
➜ ~ kubectl get --raw /debug/api_priority_and_fairness/dump_queues
PriorityLevelName, Index,  PendingRequests, ExecutingRequests, VirtualStart
exempt,            <none>, <none>,          <none>,            <none>
global-default,    0,      0,               0,                 0.0000
global-default,    1,      0,               0,                 0.0000
global-default,    2,      0,               0,                 0.0000
global-default,    3,      0,               0,                 0.0000
global-default,    4,      0,               0,                 0.0000
global-default,    5,      0,               0,                 0.0000
global-default,    6,      0,               0,                 0.0000
global-default,    7,      0,               0,                 0.0000
global-default,    8,      0,               0,                 0.0000
global-default,    9,      0,               0,                 0.0000
global-default,    10,     0,               0,                 0.0000
global-default,    11,     0,               0,                 0.0000
global-default,    12,     0,               0,                 0.0000
global-default,    13,     0,               0,                 0.0000

#集群所有等待的请求队列
➜ ~ kubectl get --raw /debug/api_priority_and_fairness/dump_requests
PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher, ArriveTime
#当前为空

高可用APIServer

构建高可用的多副本apiserver

apiserver是无状态的Rest Server
无状态所以方便Scale Up/down

负载均衡

  • 在多个apiserver实例之上,配置负载均衡
  • 证书可能需要加上Loadbalancer VIP重新生成
预留充足的CPU、内存资源

随着集群中节点数量不断增多,APIServer对CPU和内存的开销也不断增大。过少的CPU资源会降低其处理效率,过少的内存资源会导致Pod被OOMKilled,直接导致服务不可用。在规划APIServer资源时,不能仅看当下需求,也要为未来预留充分。

善用速率限制(RateLimit)

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)功能,以提供更细粒度地客户端请求控制。该功能支持将不同用户或不同类型的请求进行优先级归类,保证高优先级的请求总是能够更快得到处理,从而不受低优先级请求的影响。

设置合适的缓存大小

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的压力。

如何访问APIServer

对外部客户(user/client/admin),永远只通过LoadBalancer访问

只有当负载均衡出现故障时,管理员才切换到apiserver IP进行管理

内部客户端,优先访问cluster IP?(是否一定如此?)

kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_31

搭建多租户的Kubernetes集群

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_32

认证

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_33

注册APIService

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_34

apimachinery

回顾GKV
Group
Kind
Version

  • Internel version 和External version
  • 版本转换
如何定义Group

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_35

定义对象类型 types.go

List
单一对象数据结构

  • TypeMeta
  • ObjectMeta
  • Spec
  • Status
代码生成Tags

kubernetes安装 apiserver 2379端口 kube-apiserver_Pod_36

实现etcd storage

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_37

创建和更新对象时的业务逻辑-Strategy

kubernetes安装 apiserver 2379端口 kube-apiserver_开发语言_38

subresource

kubernetes安装 apiserver 2379端口 kube-apiserver_API_39

注册APIGroup

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_40

代码生成

kubernetes安装 apiserver 2379端口 kube-apiserver_后端_41


https://github.com/kubernetes/code-generator

hack/update-codegen.sh

kubernetes安装 apiserver 2379端口 kube-apiserver_Server_42

APIServer代码

https://cncamp.notion.site/kube-apiserver-10d5695cbbb14387b60c6d622005583d