kubernetes_API_server

深入理解 Kubernetes API Server:访问控制、限流与对象实现

kube-apiserver 是 Kubernetes 集群的”大脑”,负责处理所有请求,是集群管理的核心组件。本文将深入探讨 kube-apiserver 的访问控制机制(认证、鉴权、准入控制)、限流策略以及 APIServer 对象的实现原理。

1. API Server 的核心功能

kube-apiserver 主要提供以下功能:

  • 集群管理的 REST API 接口:提供认证授权、数据校验、集群状态变更等功能。
  • 模块间数据交互枢纽:其他模块通过 API Server 查询或修改数据,只有 API Server 才直接操作 etcd。

2. 访问控制

客户端(例如 kubectl、自定义控制器或其他 K8s 组件)发出的 API 请求首先到达 kube-apiserver。这些请求经过一系列处理步骤,最终被处理并存储到 etcd 中(或从 etcd 中检索)。

  • Panic Recovery: 捕获并处理任何 panic,防止整个 apiserver 崩溃。

  • Request Timeout: 设置请求的超时时间,防止请求无限期挂起。

  • Authentication: 验证请求者的身份。K8s 支持多种认证机制,如 X.509 证书、Service Account Tokens、Bearer Tokens 等。

  • Audit: 记录请求的审计日志,用于安全审计和故障排除。

  • Impersonation: 允许一个用户或服务账户以另一个用户或服务账户的身份执行操作。

  • Max-in-flight: 限制并发处理的请求数量,防止服务器过载。

  • Authorization: 确定经过身份验证的用户是否有权限执行请求的操作。K8s 支持多种授权机制,如 RBAC (Role-Based Access Control)、ABAC (Attribute-Based Access Control) 等。

2.1 认证(Authentication)

在 Kubernetes 中,认证是指对请求的发送者(用户或服务)进行身份识别,以确保只有合法的实体可以访问 Kubernetes API Server。以下是 Kubernetes 支持的多种认证机制的详细说明:


1. X.509 证书

概念
X.509 是一种基于公钥基础设施 (PKI) 的证书标准,通常用于安全通信。Kubernetes 支持通过客户端证书进行身份验证。

工作原理

  1. 用户使用私钥和证书向 API Server 发起 HTTPS 请求。
  2. API Server 使用信任的 CA 证书对客户端证书进行验证。
  3. 若验证通过,则认证成功。

配置方式

  • 生成 CA 和用户证书:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 生成 CA 私钥和证书
    openssl genrsa -out ca.key 2048
    openssl req -x509 -new -nodes -key ca.key -subj "/CN=kube-ca" -days 10000 -out ca.crt

    # 生成用户私钥和 CSR
    openssl genrsa -out user.key 2048
    openssl req -new -key user.key -subj "/CN=my-user/O=my-group" -out user.csr

    # 使用 CA 签发用户证书
    openssl x509 -req -in user.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out user.crt -days 10000 -extensions v3_ext
  • 配置 API Server:

    1
    kube-apiserver --client-ca-file=/path/to/ca.crt

注意事项

  • 用户名(CN)由证书中的 Common Name 字段指定。
  • 组(Group)由证书中的 Organization 字段指定。

2. 静态 Token 文件

概念
静态 Token 是预定义的令牌,用于认证用户。它适合小型测试集群,但不推荐生产环境中使用。

工作原理

  1. 用户请求中携带 Authorization: Bearer <token>
  2. API Server 从配置的 Token 文件中查找匹配的 Token。
  3. 若匹配成功,则认证通过。

配置方式

  • 创建 Token 文件(CSV 格式):

    1
    token1234,my-user,uid1234,"group1,group2"
  • 配置 API Server:

    1
    kube-apiserver --token-auth-file=/path/to/tokens.csv

优缺点

  • 优点:简单易用,易于共享。
  • 缺点:缺乏安全性(Token 没有过期机制)。

3. 引导 Token (Bootstrap Token)

概念
引导 Token 是一种动态令牌,主要用于集群引导阶段(例如 kubeadm join)。Token 生命周期由 kube-controller-manager 管理。

工作原理

  1. Token 以 Kubernetes Secret 的形式存储于 kube-system 命名空间。
  2. 当客户端请求使用 Token 时,API Server 查询对应的 Secret 以验证其合法性。
  3. TokenCleaner 控制器会自动清理过期的 Token。

常见命令

  • 查看引导 Token:

    1
    kubeadm token list
  • 创建引导 Token:

    1
    kubeadm token create

优缺点

  • 优点:动态管理,支持自动过期。
  • 缺点:只适合用于集群引导。

4. 静态密码文件

概念
通过用户名和密码进行认证。这种方式简单但不安全,因此不推荐在生产环境中使用。

配置方式

  • 创建密码文件(CSV 格式):

    1
    password1234,my-user,uid1234,"group1,group2"
  • 配置 API Server:

    1
    kube-apiserver --basic-auth-file=/path/to/passwords.csv

缺点

  • 用户名和密码以明文方式存储。
  • 缺乏强制密码保护机制。

5. Service Account Token

概念
Service Account 是 Kubernetes 原生的认证机制,主要为 Pod 提供身份认证。

工作原理

  1. 每个 Pod 都可以绑定一个 Service Account。
  2. 默认情况下,Service Account 的 Token 会自动挂载到 Pod 的文件系统路径 /run/secrets/kubernetes.io/serviceaccount
  3. Pod 使用 Token 与 API Server 通信。

优点

  • 安全性高,自动管理。
  • 适合 Pod 内部访问 API Server。

6. OpenID Connect (OIDC)

概念
OIDC 是基于 OAuth 2.0 的身份认证协议,用于对接外部身份认证服务(例如 Google, Keycloak)。

工作原理

  1. 用户向 OIDC 提供商请求 Token。
  2. 用户携带 Token 向 API Server 发起请求。
  3. API Server 验证 Token 的签名及有效性。
  4. 验证成功后,返回认证成功。

配置方式

  • 配置 API Server:
    1
    2
    3
    4
    5
    kube-apiserver \
    --oidc-issuer-url=https://issuer.example.com \
    --oidc-client-id=kubernetes \
    --oidc-username-claim=email \
    --oidc-groups-claim=groups

优点

  • 集成第三方身份认证系统。
  • 支持复杂身份和组管理。

7. Webhook Token 认证

概念
通过 Webhook 调用外部服务来验证 Token 的合法性。

工作原理

  1. 用户携带 Token 向 API Server 发起请求。
  2. API Server 将 Token 转发到配置的 Webhook 服务。
  3. Webhook 服务返回认证结果。
  4. API Server 根据认证结果决定是否通过。

配置方式

  • 配置 Webhook:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # webhook-config.yaml
    apiVersion: v1
    kind: Config
    clusters:
    - name: example
    cluster:
    server: https://auth.example.com/authenticate
    users:
    - name: example
    contexts:
    - context:
    cluster: example
    user: example
    name: example-context
    current-context: example-context
  • 启用 Webhook:

    1
    kube-apiserver --authentication-token-webhook-config-file=/path/to/webhook-config.yaml

优点

  • 灵活性高,可以集成复杂的认证逻辑。

8. 匿名请求

概念
当未提供身份凭据时,API Server 将请求识别为匿名请求。匿名请求默认启用,但可以禁用。

配置方式

  • 禁用匿名请求:
    1
    kube-apiserver --anonymous-auth=false

优缺点

  • 优点:允许调试和测试。
  • 缺点:不适合生产环境,可能引发安全问题。

2.1.1 基于 Webhook 的认证服务集成

可以构建符合 Kubernetes 规范的自定义认证服务。以下是构建认证服务的要点:

  • 规范
    • URL:https://authn.example.com/authenticate
    • Method:POST
    • Input:
      1
      2
      3
      4
      5
      {
      "apiVersion": "authentication.k8s.io/v1beta1",
      "kind": "TokenReview",
      "spec": { "token": "(BEARERTOKEN)" }
      }
    • Output:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      {
      "apiVersion": "authentication.k8s.io/v1beta1",
      "kind": "TokenReview",
      "status": {
      "authenticated": true,
      "user": {
      "username": "janedoe@example.com",
      "uid": "42",
      "groups": [
      "developers",
      "qa"
      ]
      }
      }
      }

以下为go代码示例

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
34
//解码认证请求
decoder := json.NewDecoder(r.Body)
var tr authentication.TokenReview
err := decoder.Decode(&tr)
if err != nil {
//...错误处理
return
}

// 转发认证请求至认证服务器(以github为例)
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: tr.Spec.Token},
)
tc := oauth2.NewClient(oauth2.NoContext, ts)
client := github.NewClient(tc)
user, _, err := client.Users.Get(context.Background(), "")
if err != nil {
//...错误处理
return
}
// 认证结果返回给APIServer
w.WriteHeader(http.StatusOK)
trs := authentication.TokenReviewStatus{
Authenticated: true,
User: authentication.UserInfo{
Username: *user.Login,
UID: *user.Login,
},
}
json.NewEncoder(w).Encode(map[string]interface{}{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": trs,
})

2.1.2 keystone认证的陷阱

Keystone 是很多企业的核心认证服务。Kubernetes 中使用 Keystone 作为认证插件可能会导致 Keystone 故障且无法恢复。
原因:gophercloud 针对过期 token 会一直 retry,导致服务无法恢复

解决方案:

  • 熔断
  • 限流

2.2 授权

授权阶段负责确定已认证的用户是否有权限执行请求的操作。Kubernetes 支持以下授权模式:

  • ABAC (Attribute-Based Access Control):基于属性的访问控制,配置复杂,不推荐。
  • RBAC (Role-Based Access Control):基于角色的访问控制,推荐使用。
  • Webhook:将授权决策委托给外部 Webhook 服务。
  • Node:一种特殊用途的授权模式,用于授予 kubelet 访问特定资源的权限。

2.2.1 RBAC

RBAC 的核心概念:

  • Role(角色):定义了一组权限规则。
  • ClusterRole(集群角色):与 Role 类似,但作用于整个集群。
  • RoleBinding(角色绑定):将 Role 或 ClusterRole 与用户、组或 ServiceAccount 绑定。
  • ClusterRoleBinding(集群角色绑定):将 ClusterRole 与用户、组或 ServiceAccount 绑定。
  • 针对群组授权
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io

2.2.2 规划系统角色

在规划 Kubernetes 集群的权限时,需要考虑以下角色:

  • 管理员:拥有集群的最高权限。
  • 普通用户:拥有其创建的命名空间内资源的操作权限,对其他命名空间可能有只读权限。
  • SystemAccount:用于 Kubernetes 组件或自定义应用与 API Server 通信。

2.2.3 实现自定义授权逻辑的方案

  1. 在集群创建时,创建自定义的 Role,例如 namespace-creator,定义用户可操作的对象和读写权限。
  2. 创建自定义的 Namespace 准入控制器,在 Namespace 创建请求被处理时,获取当前用户信息并将其添加到 Namespace 的 Annotation 中。
  3. 创建 RBAC 控制器,监视 Namespace 的创建事件,获取 Namespace 创建者信息,并在当前 Namespace 中创建 RoleBinding 对象,将 namespace-creator 角色与用户绑定。

2.2.4 权限相关的最佳实践

  • ClusterRole 是非命名空间绑定的,针对整个集群生效。
  • 通常需要创建一个管理员角色,并且绑定给开发运营团队成员。
  • ThirdPartyResource 和 CustomResourceDefinition 是全局资源,普通用户创建
    ThirdPartyResource 以后,需要管理员授予相应权限后才能真正操作该对象。
  • 针对所有的角色管理,建议创建 spec,用源代码驱动。
  • 权限是可以传递的,用户 A 可以将其对某对象的某操作,抽取成一个权限,并赋给用户 B。
  • 防止海量的角色和角色绑定对象,因为大量的对象会导致鉴权效率低,同时给 apiserver 增加负担。
  • ServiceAccount 也需要授权的。
  • Tips:SSH 到 master 节点通过 insecure port 访问 apiserver 可绕过鉴权,当需要做管理操作又没有权限时可以使用(不推荐)

授权相关的坑:
研发人员忘记在生产环境更新 rolebinding 导致权限不足

2.3 准入控制

准入控制在授权之后对请求进行进一步的验证或修改。与认证和授权不同,准入控制可以处理请求的内容,并且仅对创建、更新、删除或连接(如代理)等操作有效。

Kubernetes 内置了许多准入控制插件,例如:

  • AlwaysPullImages:强制拉取最新镜像。
  • DenyEscalatingExec:禁止特权容器的 exec 和 attach 操作。
  • ServiceAccount:自动创建默认 ServiceAccount。
  • ResourceQuota:限制 Pod 的资源请求。
  • LimitRanger:为 Pod 设置默认资源请求和限制。
  • NamespaceLifecycle:确保处于 termination 状态的命名空间不再接收新的对象创建请求。
  • PodSecurityPolicy:实施 Pod 安全策略。
  • NodeRestriction:限制 kubelet 仅可访问 node、endpoint、pod、service 以及 secret、
    configmap、PV 和 PVC 等相关的资源

2.3.1 准入控制插件的开发

除了默认的准入控制插件,Kubernetes 还支持自定义准入控制插件:

  • MutatingWebhookConfiguration:修改准入对象。
  • ValidatingWebhookConfiguration:校验准入对象,但不修改。
    准入控制例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion:
admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: ns-mutating.webhook.k8s.io
webhooks:
- clientConfig:
caBundle: {{.serverca_base64}}
url:
https://admission.local.tess.io/apis/admission.k8s.io/v1alpha1/ns-mutating
failurePolicy: Fail
name: ns-mutating.webhook.k8s.io
namespaceSelector: {}
rules:
- apiGroups:
""
apiVersions:
- '*'
operations:
- CREATE
resources:
- nodes
sideEffects: Unknown

2.3.2 配额管理

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

  • 预定义每个Namespace的ResourceQuota,并把spec保存为configmap
  • 创建ResourceQuota Controller
  • apiserver中开启ResourceQuota的admission plugin

3. 限流

限流是保护 API Server 免受过多请求影响的重要机制。

3.1 传统限流算法

  • 计数器固定窗口算法:在固定时间窗口内对请求计数,超过阈值则拒绝。
  • 计数器滑动窗口算法:将固定窗口划分为多个小窗口,分别计数,窗口滑动时更新计数。
  • 漏斗算法:请求进入漏斗,以恒定速率流出,漏斗满时溢出。
  • 令牌桶算法:以恒定速率向令牌桶中放入令牌,请求消耗令牌,桶空时拒绝。

3.2 APIServer 中的限流

kube-apiserver 通过以下参数进行限流:

  • --max-requests-inflight:最大非 mutating 请求数。
  • --max-mutating-requests-inflight:最大 mutating 请求数。
  • 代码: staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go:WithMaxInFlightLimit()

默认值:

节点数 max-requests-inflight max-mutating-requests-inflight
1000-3000 400/1500 200/500
>3000 3000 1000

3.3 传统限流方法的局限性

  • 粒度粗:无法针对不同用户、场景进行精细化限流。
  • 单队列:所有请求共享限流资源,可能导致单个用户的行为影响整个系统。
  • 不公平:正常用户的请求可能被排在队尾,无法及时处理。
  • 无优先级:重要请求可能被限流,导致系统故障难以恢复。

3.4 API Priority and Fairness (APF)

APF 是 Kubernetes 1.18 引入的新特性,提供更细粒度的请求分类和隔离,以及有限的排队机制,避免短暂突发流量导致请求被拒绝。

3.4.1 APF 的核心概念

  • 多等级 (Priority Level):不同优先级的请求拥有独立的并发资源。
  • 多队列 (Multiple Queues):每个优先级内部使用多个队列,通过公平排队算法避免单个 Flow 饿死其他 Flow。

3.4.2 关键概念

  • FlowSchema:将请求分类到不同的 Flow。
  • PriorityLevelConfiguration:定义每个优先级的并发限制和排队参数。
  • Distinguisher:在 FlowSchema 内部进一步区分请求(例如,按用户或命名空间)。
  • Shuffle Sharding:将请求分配到队列的算法,隔离低强度和高强度流量。
  • Fair Queuing:从队列中选择请求的算法,确保同一优先级内不同 Flow 的公平性。

3.4.3 豁免请求

某些特别重要的请求(例如,system:masters 组的请求)不受 APF 限制。

3.4.4 默认配置

Kubernetes 提供了以下默认配置:

  • system:用于 system:nodes 组的请求。
  • leader-election:用于内置控制器的领导者选举请求。
  • workload-high:用于内置控制器的请求。
  • workload-low:用于来自任何服务帐户的请求。
  • global-default:处理所有其他流量。
  • exempt:完全不受流控限制。
  • catch-all:确保每个请求都被分类。

3.4.5 PriorityLevelConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: PriorityLevelConfiguration
metadata:
name: global-default
spec:
limited:
assuredConcurrencyShares: 20
limitResponse:
queuing:
handSize: 6
queueLengthLimit: 50
queues: 128
type: Queue
type: Limited

3.4.6 FlowSchema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: FlowSchema
metadata:
name: kube-scheduler
spec:
distinguisherMethod:
type: ByNamespace
matchingPrecedence: 800
priorityLevelConfiguration:
name: workload-high
rules:
- resourceRules:
- resources:
- '*'
verbs:
- '*'
subjects:
- kind: User
user:
name: system:kube-scheduler

3.4.7 调试

可以使用以下命令调试 APF:

  • /debug/api_priority_and_fairness/dump_priority_levels
  • /debug/api_priority_and_fairness/dump_queues
  • /debug/api_priority_and_fairness/dump_requests

4. 高可用 APIServer

4.1 启动 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

4.2 构建高可用的多副本 apiserver

apiserver是无状态的Rest Server,无状态所以方便Scale Up/down,在多个apiserver实例之上,配置负载均衡,证书可能需要加上Loadbalancer VIP重新生成

4.3 其他最佳实践

  • 预留充足的 CPU、内存资源
  • 善用速率限制(RateLimit)
  • 设置合适的缓存大小
  • 客户端尽量使用长连接
  • 访问 APIServer:
    • 外部客户:通过 LoadBalancer 访问。
    • 内部客户端:优先访问 Cluster IP。

5. 搭建多租户的 Kubernetes 集群

5.1 目标

  • 授信:认证和授权,确保只有可信用户才能访问集群,并防止用户越权操作。
  • 隔离:可见性隔离、资源隔离、应用访问隔离,确保不同租户之间的隔离性。
  • 资源管理:Quota 管理,控制每个租户的资源使用量。

5.2 实现

  • 认证:与企业现有认证系统集成(例如,使用 Webhook 认证插件与 Microsoft Active Directory 集成)。
  • 授权:使用 RBAC 进行细粒度的权限控制。
  • 可见性隔离:通过命名空间对不同租户可见的资源进行隔离
  • 资源隔离:通过专有设备给特定租户使用
  • 应用访问隔离: 通过设置,只允许特定租户访问某些应用
  • Quota 管理:通过 ResourceQuota 控制每个命名空间的资源使用。

6. APIServer 对象的实现

6.1 GKV (Group, Kind, Version)

  • Group:API 资源的分组。
  • Kind:API 资源的类型。
  • Version:API 资源的版本(Internal version 和 External version)。

6.2 定义 Group

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// pkg/apis/core/register.go
package core
const GroupName = "" // core group 的 GroupName 为空
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}

var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
func addKnownTypes(scheme *runtime.Scheme) error {
if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil {
return err
}
scheme.AddKnownTypes(SchemeGroupVersion,
&Pod{},
&PodList{},
)
}

6.3 定义对象类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// types.go
type Pod struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

type PodList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []Pod `json:"items" protobuf:"bytes,2,rep,name=items"`
}

6.4 代码生成 Tags

  • Global Tags:定义在 doc.go 中,例如 // +k8s:deepcopy-gen=package
  • Local Tags:定义在 types.go 中的每个对象里,例如 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

6.5 实现 etcd storage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// pkg/registry/core/configmap/storage/storage.go
func NewREST(optsGetter generic.RESTOptionsGetter) *REST {
store := &genericregistry.Store{
NewFunc: func() runtime.Object { return &api.ConfigMap{} },
NewListFunc: func() runtime.Object { return &api.ConfigMapList{} },
DefaultQualifiedResource: api.Resource("configmaps"),
CreateStrategy: configmap.Strategy,
UpdateStrategy: configmap.Strategy,
DeleteStrategy: configmap.Strategy,
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
}
options := &generic.StoreOptions{RESTOptions: optsGetter}
if err := store.CompleteWithOptions(options); err != nil {
panic(err) // TODO: Propagate error up
}
return &REST{store}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
// pkg/registry/core/configmap/strategy.go
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
_ = obj.(*api.ConfigMap)
}
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
cfg := obj.(*api.ConfigMap)
return validation.ValidateConfigMap(cfg)
}
func (strategy) PrepareForUpdate(ctx context.Context, newObj, oldObj runtime.Object) {
_ = oldObj.(*api.ConfigMap)
_ = newObj.(*api.ConfigMap)
}

6.7 subresource

内嵌在kubernetes对象中,有独立的操作逻辑的属性集合,如podstatus

1
2
3
4
5
6
7
8
9
10
11
12
statusStore.UpdateStrategy = pod.StatusStrategy
var StatusStrategy = podStatusStrategy{Strategy}
func (podStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object)
{
newPod := obj.(*api.Pod)
oldPod := old.(*api.Pod)
newPod.Spec = oldPod.Spec
newPod.DeletionTimestamp = nil
// don't allow the pods/status endpoint to touch owner references since old kubelets corrupt them in a way
// that breaks garbage collection
newPod.OwnerReferences = oldPod.OwnerReferences
}

6.8 注册 APIGroup

  1. 定义 Storage:configMapStorage := configmapstore.NewREST(restOptionsGetter)
  2. 定义对象的 StorageMap:apiGroupInfo.VersionedResourcesStorageMap["v1"] = restStorageMap
  3. 将对象注册至 APIServer(挂载 handler):
1
2
3
4
5
if err :=
m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix,
&apiGroupInfo); err != nil {
klog.Fatalf("Error in registering group versions: %v", err)
}

6.9 代码生成

Kubernetes 使用以下代码生成器:

  • deepcopy-gen:为对象生成 DeepCopy 方法。
  • client-gen:创建 Clientset。
  • informer-gen:创建 Informer 框架。
  • lister-gen:创建 Lister 框架。
  • conversion-gen:创建版本转换方法。

代码生成器位于:https://github.com/kubernetes/code-generator

hack/update-codegen.sh 脚本用于生成代码。
命令示例:

1
2
3
4
${GOPATH}/bin/deepcopy-gen --input-dirs {versioned-package-pach} \
-O zz_generated.deepcopy \
--bounding-dirs {output-package-path} \
--go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt

总结

本文深入探讨了 Kubernetes API Server 的内部机制,包括访问控制、限流策略和 APIServer 对象的实现。理解这些概念对于构建和管理 Kubernetes 集群至关重要。希望这篇博客能帮助你更好地理解 Kubernetes API Server 的工作原理。
apiserver 代码走读可以参考:https://cncamp.notion.site/kube-apiserver-10d5695cbbb14387b60c6d622005583d


kubernetes_API_server
https://mfzzf.github.io/2025/03/17/kubernetes-API-server/
作者
Mzzf
发布于
2025年3月17日
许可协议