文章目录
- 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
API Server
kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能
• 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
• 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd)
访问控制概览
Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及准入控制(Admission Control)等。
apiserver本身是一个rust server,首先要有一个http handler来处理不同版本的请求,接收到请求之后要做认证、鉴权,然后到转变,对应两个webhook(可以自定义开发,在到达mutating步骤时,apiserver会校验有没有对应的webhook,有的话则会被调用,改变对象的值webhook会进行回转),接下来到schema步骤,apiserver会继续校验这个对象是不是有效的(主要是k8s内嵌的逻辑),
访问控制细节
红色箭头为整个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,来单独做调试
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:
鉴权
授权主要是用于对集群资源的访问控制,通过检查请求包含的相关属性值,与相对应的访问策略相比较,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 资源和操作。
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。
binding
账户/组的管理
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。
它包含若干 主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。
组的概念:
- 当与外部认证系统对接时,用户信息(UserInfo)可包含Group信息,授权可针对用户群组
- 当对ServiceAccount授权时,Group代表某个Namespace下的所有ServiceAccount
针对群租授权
规划系统角色
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可绕过鉴权,当需要做管理操作又没有权限时可以使用(不推荐)
运营过程中出现的陷阱
准入
准入控制
为资源增加自定义属性
- 作为多租户集群方案中的一环,我们需要在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:校验插件,只能对准入对象合法性进行校验,不能修改
配额管理
背景:资源有限,如何限定某个用户有多少资源?
方案:
- 预定义每个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
Pod启动失败!
kubectl get pod nginx-demo -oyaml
securityContext:
runAsNonRoot: true
runAsUser: 1234 #需要以userid为1234的用户来运行此程序
限流
计数器固定窗口算法
计数器滑动窗口算法
漏斗算法
令牌桶算法
APIServer中的限流
max-requests-inflight: 在给定时间内的最大 non-mutating 请求数
max-mutating-requests-inflight: 在给定时间内的最大 mutating 请求数,调整 apiserver 的流控 qos
代码
staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go:WithMaxInFlightLimit()
传统限流方法的局限性
API Priority and Fairness
k8s 1.18以后 组件:顾忌到公平和优先级
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: {}
概念
优先级
排队
豁免请求
某些特别重要的请求不受制于此特性施加的任何限制。这些豁免可防止不当的流控配置完全禁用API 服务器。
默认配置
PriorityLevelConfiguration
一个 PriorityLevelConfiguration 表示单个隔离类型。
每个 PriorityLevelConfigurations 对未完成的请求数有各自的限制,对排队中的请求数也有限制。
FlowSchema
FlowSchema 匹配一些入站请求,并将它们分配给优先级。
每个入站请求都会对所有 FlowSchema 测试是否匹配, 首先从 matchingPrecedence 数值最低的匹配开始(我们认为这是逻辑上匹配度最高), 然后依次进行,直到首个匹配出现。
调试
➜ ~ 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集群
认证
注册APIService
apimachinery
回顾GKV
Group
Kind
Version
- Internel version 和External version
- 版本转换
如何定义Group
定义对象类型 types.go
List
单一对象数据结构
- TypeMeta
- ObjectMeta
- Spec
- Status
代码生成Tags
实现etcd storage
创建和更新对象时的业务逻辑-Strategy
subresource
注册APIGroup
代码生成
https://github.com/kubernetes/code-generator
hack/update-codegen.sh
APIServer代码
https://cncamp.notion.site/kube-apiserver-10d5695cbbb14387b60c6d622005583d