深入理解 Kubernetes API Server:核心机制与实践
深入理解 Kubernetes API Server:核心机制与实践
Kubernetes API Server (kube-apiserver) 是 Kubernetes 控制平面的核心组件,扮演着集群”大脑”的角色。它是所有管理操作的入口点,负责处理 REST 请求、验证请求、执行业务逻辑并将结果持久化到 etcd。理解 API Server 的工作原理对于有效管理和扩展 Kubernetes 集群至关重要。本文将深入探讨其核心功能、访问控制流程、限流机制、高可用性、多租户实现以及 API 对象的内部实现。
1. API Server 核心功能与架构
kube-apiserver 主要承担以下职责:
- 提供统一的 REST API 入口:为集群内外的客户端(如
kubectl
、控制器、调度器等)提供一致的 CRUD (创建、读取、更新、删除) 和 Watch 操作接口。 - 集群状态的网关:作为唯一直接与 etcd 交互的组件,负责集群状态的持久化和读取。
- 请求处理流水线:执行认证、授权、准入控制等一系列检查和处理步骤。
- API 注册与发现:支持 API Group 和 Versioning,允许扩展自定义资源 (CRD)。

图:API Server 在 Kubernetes 架构中的位置
2. API 请求处理流程
当一个请求到达 kube-apiserver
时,它会经过一系列的处理 Handler(过滤器),最终到达具体的 API 资源处理逻辑。

图:API Server 请求处理链
这个流程主要包括:
- Panic Recovery: 捕获处理过程中的 panic,防止 apiserver 崩溃。
- Request Timeout: 为请求设置超时时间。
- Authentication (认证): 验证请求者的身份是谁。
- Audit (审计): 记录请求的详细信息。
- Impersonation (模拟): 允许一个用户临时扮演另一个用户的身份。
- Max-in-flight / Rate Limiting (限流): 限制并发请求数量或速率,防止过载 (APF 机制在此生效)。
- Authorization (授权): 检查认证通过的用户是否有权限执行请求的操作。
- Admission Control (准入控制): 在对象持久化之前,进行最后的验证或修改。

图:访问控制三大环节:认证、授权、准入控制
接下来,我们将详细探讨访问控制的三个关键环节。
3. 认证 (Authentication) - 你是谁?
认证是确定请求来源身份的过程。Kubernetes 支持多种认证机制,API Server 会按顺序尝试配置的认证器,一旦某个认证器成功识别用户身份,后续的认证器就不会再执行。

图:多种认证方式
以下是常见的认证机制:
3.1 X.509 客户端证书
- 原理: 基于 TLS 双向认证。客户端提供证书,API Server 使用配置的 CA (
--client-ca-file
) 验证该证书。证书的Common Name (CN)
字段作为用户名,Organization (O)
字段作为用户组。 - 配置:
- 生成 CA 及客户端证书 (如前文所示)。
- 启动 API Server 时指定
--client-ca-file
。
- 适用场景: 集群组件(如 kubelet, kube-proxy)、管理员用户。
3.2 Service Account Tokens
- 原理: Kubernetes 内部机制,主要用于 Pod 访问 API Server。每个 Namespace 都有一个默认的 ServiceAccount,也可以创建自定义的。Token (JWT 格式) 以 Secret 形式存储,并自动挂载到 Pod 的
/var/run/secrets/kubernetes.io/serviceaccount/token
。API Server 使用--service-account-key-file
指定的公钥验证 Token 签名。 - 优点: Kubernetes 原生集成,自动管理。
- 适用场景: Pod 内应用访问 API Server。
3.3 OpenID Connect (OIDC) Tokens
- 原理: 集成外部身份提供商 (IdP),如 Keycloak, Google, Dex 等。用户通过 IdP 获取 ID Token (JWT),并在请求头
Authorization: Bearer <token>
中提供给 API Server。API Server 使用 IdP 的公钥验证 Token,并从中提取用户信息(用户名、组等)。 - 配置: 需要配置
--oidc-issuer-url
,--oidc-client-id
,--oidc-username-claim
,--oidc-groups-claim
等参数。 - 适用场景: 集成企业 SSO 系统,为人类用户提供认证。
3.4 Webhook Token 认证
- 原理: 将 Token 发送给一个外部 Webhook 服务进行验证。API Server 向配置的 Webhook 端点发送
TokenReview
对象,Webhook 服务返回包含用户信息的TokenReviewStatus
。 - 配置:
- 创建 Webhook 配置文件 (如前文所示)。
- 启动 API Server 时指定
--authentication-token-webhook-config-file
。
- 适用场景: 实现自定义或复杂的认证逻辑,集成现有认证系统。
3.4.1 基于 Webhook 的认证服务集成示例
构建一个符合 TokenReview
API 规范的 Webhook 服务。
- 输入:
TokenReview
对象,包含待验证的 Token。 - 处理: 服务根据 Token 查询用户信息(例如,调用 GitHub API 验证 Personal Access Token)。
- 输出:
TokenReview
对象,status
字段包含认证结果 (authenticated: true/false
) 和用户信息 (user: {username, uid, groups}
).
1 |
|
3.4.2 Keystone 认证集成陷阱
- 问题: 使用某些版本的 gophercloud 库与 Keystone 集成时,当 Keystone 返回 Token 过期错误,gophercloud 可能会无限重试,导致 API Server 持续向 Keystone 发送请求,最终压垮 Keystone。
- 解决方案:
- 熔断: 在 API Server 的 Keystone 认证插件或 Webhook 服务中实现熔断逻辑,当错误率超过阈值时暂时停止向 Keystone 发送请求。
- 限流: 对发往 Keystone 的请求进行限流。
- 更新库: 使用修复了此问题的 gophercloud 版本。
3.5 引导 Token (Bootstrap Token)
- 原理: 用于
kubeadm join
过程,让新节点安全地加入集群。Token 以 Secret 形式存储在kube-system
命名空间,有 TTL,由kube-controller-manager
的tokencleaner
控制器自动清理。 - 适用场景: 集群节点引导。
3.6 静态 Token 文件 & 静态密码文件
- 原理: 将预定义的 Token 或用户名密码存储在 CSV 文件中 (
--token-auth-file
,--basic-auth-file
)。API Server 加载文件内容进行匹配。 - 缺点: 安全性差(明文存储、无过期),管理不便。不推荐用于生产环境。
3.7 匿名请求
- 原理: 如果所有配置的认证器都无法识别请求者身份,且 API Server 启用了匿名认证 (
--anonymous-auth=true
,默认启用),则请求被视为匿名用户 (system:anonymous
),属于system:unauthenticated
组。 - 注意: 需要配合授权策略(如 RBAC)限制匿名用户的权限。生产环境通常建议禁用 (
--anonymous-auth=false
) 或严格限制其权限。
4. 授权 (Authorization) - 你能做什么?
认证之后,授权环节决定用户是否有权限对目标资源执行请求的操作(如 GET, POST, DELETE)。API Server 支持多种授权模式,通过 --authorization-mode
参数指定,可以指定多个模式,按顺序检查,只要有一个模式授权通过即可。

图:授权流程
常见的授权模式:
- Node: 特殊模式,用于授权 Kubelet 发出的 API 请求。它根据 Kubelet 自身注册的 Node 对象,限制其只能访问与自身节点相关的资源(如 Pods, Secrets, ConfigMaps 等)。
- RBAC (Role-Based Access Control): 推荐使用。基于角色的访问控制,通过 Role/ClusterRole 定义权限,通过 RoleBinding/ClusterRoleBinding 将角色绑定到用户、组或 ServiceAccount。
- Webhook: 将授权决策委托给外部 Webhook 服务。API Server 发送
SubjectAccessReview
对象,Webhook 服务返回授权结果。 - ABAC (Attribute-Based Access Control): 基于属性的访问控制,通过策略文件定义规则。配置复杂,管理困难,已不推荐。
- AlwaysAllow / AlwaysDeny: 测试模式,允许或拒绝所有请求。
4.1 RBAC 详解
RBAC 是 Kubernetes 中最常用且推荐的授权机制。
核心概念:
- Subject (主体): User, Group, ServiceAccount。
- Role (角色): 定义在一组 Namespace 范围 内的权限(允许对哪些资源执行哪些操作)。
- ClusterRole (集群角色): 定义 集群范围 的权限(适用于所有 Namespace 的资源或集群级别的资源,如 Node, Namespace)。
- RoleBinding (角色绑定): 将 Role 绑定到一个或多个 Subject,使其在 特定 Namespace 内拥有该 Role 定义的权限。
- ClusterRoleBinding (集群角色绑定): 将 ClusterRole 绑定到一个或多个 Subject,使其在 整个集群 拥有该 ClusterRole 定义的权限。
示例:为用户组授权读取 Secrets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# ClusterRole 定义读取 Secret 的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""] # "" 表示 core API group
resources: ["secrets"]
verbs: ["get", "watch", "list"]
---
# ClusterRoleBinding 将 'secret-reader' 角色绑定到 'manager' 组
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 组名区分大小写
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
4.2 规划系统角色与权限
设计 RBAC 策略时,应遵循最小权限原则。常见角色划分:
- Cluster Admin: 拥有集群所有权限 (绑定到
cluster-admin
ClusterRole)。 - Namespace Admin: 拥有特定 Namespace 内所有资源的完全控制权。
- Developer: 在特定 Namespace 内创建、更新、删除工作负载(Deployments, Pods 等)的权限,可能有限制地访问 Secrets, ConfigMaps。
- Viewer: 对特定 Namespace 或整个集群有只读权限。
- CI/CD System (ServiceAccount): 部署应用所需的权限。
4.3 实现自定义授权逻辑 (Namespace Owner 示例)
有时需要更动态的授权逻辑,例如让 Namespace 的创建者自动拥有该 Namespace 的管理权限。
- 创建基础角色: 定义一个
namespace-admin
Role (或 ClusterRole,如果权限需要在所有 Namespace 中一致)。 - 准入控制器 (Mutating Webhook): 创建一个 Mutating Admission Webhook。当创建 Namespace 的请求 (
CREATE Namespace
) 到达时,该 Webhook 自动将请求用户的身份信息(用户名或组)添加到 Namespace 的 Annotation 中,例如owner: user-a
。 - RBAC 控制器 (自定义 Controller): 创建一个自定义控制器,监听 Namespace 的创建和更新事件。当检测到新的 Namespace 或
owner
Annotation 变化时,该控制器:- 读取
owner
Annotation 获取用户信息。 - 在对应的 Namespace 中创建或更新一个 RoleBinding,将步骤 1 中定义的
namespace-admin
Role 绑定到该用户。
- 读取
4.4 授权最佳实践与陷阱
- 最小权限原则: 只授予必要的权限。
- 使用 Role 和 RoleBinding 优先于 ClusterRole 和 ClusterRoleBinding,以限制权限范围。
- 定期审计: 定期检查 RoleBinding 和 ClusterRoleBinding,移除不再需要的权限。
- 管理 ServiceAccount 权限: 不要给 ServiceAccount 过高的权限,特别是
default
ServiceAccount。 - 避免使用
default
Namespace: 为不同应用或团队创建独立的 Namespace。 - 源代码管理 RBAC 配置: 将 RBAC YAML 文件纳入版本控制。
- 注意权限传递: 用户 A 可以创建 RoleBinding 将自己拥有的权限授予用户 B。
- 避免大量 Role/Binding: 过多的 RBAC 对象会影响鉴权性能。
- 绕过鉴权 (不推荐): SSH 到 Master 节点通过 insecure port (如果启用) 访问 apiserver 可以绕过认证和授权,仅用于紧急情况。
5. 准入控制 (Admission Control) - 规则检查与修改
准入控制是请求处理流程的最后一道关卡,发生在请求通过认证和授权之后、对象持久化到 etcd 之前。它用于执行更复杂的验证逻辑、强制实施策略或在对象创建/更新时自动进行修改。
准入控制器只对 CREATE
, UPDATE
, DELETE
, CONNECT
操作生效,对 GET
, LIST
, WATCH
无效。
API Server 通过 --enable-admission-plugins
参数启用一系列内置的准入控制器,并通过 --disable-admission-plugins
禁用某些默认启用的插件。执行顺序很重要。
常见的内置准入控制器:
- NamespaceLifecycle: 防止在正在被删除的 Namespace 中创建新对象,防止删除包含活跃资源的
kube-system
,kube-public
,kube-node-lease
Namespace。 - LimitRanger: 读取 Namespace 下的 LimitRange 对象,为 Pod 设置默认的资源请求 (Request) 和限制 (Limit),并校验 Pod 的资源设置不超过 LimitRange 的限制。
- ServiceAccount: 为 Pod 自动挂载 ServiceAccount Token,如果 Pod 没有指定 ServiceAccount,则使用
default
ServiceAccount。 - ResourceQuota: 读取 Namespace 下的 ResourceQuota 对象,确保创建或更新资源不会超出 Namespace 的配额限制(如 CPU, Memory, 对象数量等)。
- PodSecurityPolicy (Deprecated in 1.21, Removed in 1.25) / PodSecurity (Stable in 1.25+): 强制实施 Pod 安全标准(如禁止特权容器、限制 HostPath 挂载等)。PodSecurity 通过 Namespace Label 控制策略级别 (privileged, baseline, restricted)。
- MutatingAdmissionWebhook: 调用外部 Webhook 服务来修改对象。
- ValidatingAdmissionWebhook: 调用外部 Webhook 服务来验证对象。
- NodeRestriction: 限制 Kubelet 只能修改其自身注册的 Node 对象,以及只能获取/修改运行在自身节点上的 Pod 对象。
5.1 自定义准入控制 (Webhooks)
可以通过创建 MutatingWebhookConfiguration
和 ValidatingWebhookConfiguration
对象来注册自定义的准入逻辑。
- Mutating Webhook: 在内置的修改逻辑之后、对象模式校验之前执行。可以修改请求中的对象。常用于自动注入 Sidecar 容器、设置默认标签等。
- Validating Webhook: 在对象模式校验之后、持久化之前执行。只能验证对象,不能修改。常用于强制实施自定义策略、检查资源规范等。
Webhook 配置示例:
1 |
|
- Webhook 服务需要实现一个 HTTPS 端点,接收
AdmissionReview
请求,并返回包含决策 (allowed: true/false
,patch
(for mutating),status
(for validating)) 的AdmissionReview
响应。
5.2 配额管理 (ResourceQuota)
- 目的: 防止单个 Namespace 或用户耗尽集群资源。
- 实现:
- 在 API Server 中启用
ResourceQuota
准入控制器 (--enable-admission-plugins=...,ResourceQuota,...
)。 - 在需要限制的 Namespace 中创建
ResourceQuota
对象,定义资源限制(计算资源、存储资源、对象数量)。1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: my-namespace
spec:
hard:
requests.cpu: "4"
requests.memory: 16Gi
limits.cpu: "8"
limits.memory: 32Gi
pods: "10"
secrets: "20" - 可选: 创建一个控制器或 Webhook,在 Namespace 创建时自动为其创建默认的 ResourceQuota 对象(可以从 ConfigMap 读取模板)。
- 在 API Server 中启用
6. 限流 (Rate Limiting) 与 API 优先级和公平性 (APF)
为了保护 API Server 不被过量请求压垮,需要进行限流。
6.1 传统限流 (Max-in-flight)
早期 Kubernetes 版本主要通过两个参数进行全局限流:
--max-requests-inflight
: 同时处理的最大非变更性请求数 (GET, LIST, WATCH)。默认 400。--max-mutating-requests-inflight
: 同时处理的最大变更性请求数 (POST, PUT, DELETE, PATCH)。默认 200。
局限性:
- 粒度粗: 无法区分请求来源或重要性。
- 不公平: 一个行为异常的客户端可能耗尽所有并发额度,影响其他正常客户端。
- 无优先级: 关键系统组件(如控制器)的请求可能被普通用户请求阻塞。
6.2 API 优先级和公平性 (API Priority and Fairness - APF)
APF (GA in 1.20) 引入了更精细化的限流机制,旨在解决传统限流的不足。

图:APF 架构示意图
核心概念:
- PriorityLevelConfiguration (PLC): 定义一个优先级级别。每个 PLC 拥有独立的并发份额 (
assuredConcurrencyShares
) 和排队机制。可以配置多个 PLC,代表不同的重要程度。type: Limited
: 受限流控制。assuredConcurrencyShares
: 保证的并发执行单元数。API Server 总并发数按比例分配给各 PLC。limitResponse
: 当并发达到限制时的行为。type: Queue
: 请求进入队列等待。queues
: 队列数量。queueLengthLimit
: 每个队列的最大长度。handSize
: 用于 Shuffle Sharding 的参数。
type: Reject
: 直接拒绝请求 (HTTP 429)。
type: Exempt
: 不受限流控制。
- FlowSchema (FS): 定义规则,将传入的请求分类 (match) 到某个
PriorityLevelConfiguration
。匹配规则可以基于用户、组、ServiceAccount、请求的 Verb (GET, POST)、资源类型 (pods, deployments) 等。matchingPrecedence
: 多个 FlowSchema 可能匹配同一个请求,优先级高的先生效。distinguisherMethod
: 如何在同一个 FlowSchema 内进一步区分请求流 (Flow)。type: ByUser
: 按请求用户区分。type: ByNamespace
: 按请求资源的 Namespace 区分。
- Request (请求): 每个到达的 API 请求。
- Flow (流): 根据 FlowSchema 的
distinguisherMethod
划分的一组请求,例如来自同一个用户的所有请求,或针对同一个 Namespace 的所有请求。 - Queue (队列): 每个
Limited
类型的 PLC 内部包含多个队列。 - Shuffle Sharding: 一种将 Flow 分配到 Queue 的算法。它确保高流量的 Flow 不会完全阻塞低流量的 Flow。每个 Flow 会被哈希到
handSize
个可能的队列中,然后选择当前最不繁忙的一个队列加入。 - Fair Queuing: 从队列中选择下一个要执行的请求的算法。确保同一个 PLC 内的不同 Flow 能够公平地获得执行机会,防止某个 Flow 饿死其他 Flow。
默认配置: Kubernetes 自带了一些默认的 PLC 和 FS,用于区分系统组件、领导者选举、高优先级工作负载、普通工作负载和默认流量。
- PLC 示例 (
global-default
):1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: flowcontrol.apiserver.k8s.io/v1beta1 # 或 v1
kind: PriorityLevelConfiguration
metadata:
name: global-default
spec:
type: Limited
limited:
assuredConcurrencyShares: 20 # 保证的并发份额
limitResponse:
type: Queue # 超出并发时排队
queuing:
queues: 128 # 队列数量
queueLengthLimit: 50 # 每个队列长度
handSize: 6 # Shuffle Sharding 参数 - FS 示例 (
kube-scheduler
):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19apiVersion: flowcontrol.apiserver.k8s.io/v1beta1 # 或 v1
kind: FlowSchema
metadata:
name: kube-scheduler
spec:
priorityLevelConfiguration:
name: workload-high # 关联到高优先级 PLC
matchingPrecedence: 800 # 匹配优先级
distinguisherMethod:
type: ByUser # 按用户区分流
rules:
- subjects: # 匹配来自 kube-scheduler 用户的请求
- kind: User
user:
name: system:kube-scheduler
resourceRules: # 匹配所有资源和操作
- verbs: ["*"]
apiGroups: ["*"]
resources: ["*"]
调试 APF: 可以通过 API Server 的 /debug/api_priority_and_fairness/
端点查看当前的 PLC 状态、队列信息和请求统计。
7. 高可用 API Server
由于 API Server 是控制平面的核心,其高可用性至关重要。
- 无状态设计: API Server 本身是无状态的 REST 服务,状态存储在 etcd 中。这使得横向扩展(运行多个实例)变得容易。
- 多副本部署: 运行至少 3 个 API Server 实例,分布在不同的物理节点或可用区。
- 负载均衡: 在多个 API Server 实例前放置一个负载均衡器(如 Nginx, HAProxy, 或云厂商提供的 LB 服务)。
- 所有客户端(包括集群内部组件如 Kubelet, Controller Manager, Scheduler)都应配置为访问负载均衡器的 VIP 或 DNS 名称。
- 证书: API Server 的 TLS 证书需要包含负载均衡器的 VIP 和 DNS 名称,以及各个 API Server 实例的 IP 和主机名。
- etcd 集群: API Server 依赖高可用的 etcd 集群来存储状态。确保 etcd 集群也是高可用的(通常 3 或 5 个成员)。
启动参数示例 (部分):
1 |
|
其他最佳实践:
- 为 API Server Pod 配置足够的 CPU 和 Memory 资源请求和限制。
- 监控 API Server 的请求延迟、错误率、资源使用情况。
- 客户端(尤其是控制器)应使用长连接 (Watch) 而不是频繁轮询 (List)。
- 内部客户端(如 Controller Manager, Scheduler)优先通过 Service Cluster IP 访问 API Server,减少对外部负载均衡器的依赖。
8. 构建多租户 Kubernetes 集群
多租户是指在单个 Kubernetes 集群中支持多个独立的租户(用户或团队),同时保证它们之间的隔离和安全性。API Server 的访问控制机制是实现多租户的基础。
核心目标:
- 授信 (Authentication & Authorization):
- 认证: 对接企业身份系统 (如 AD, LDAP, OIDC Provider),确保只有授权用户能登录。可使用 OIDC 或 Webhook 认证。
- 授权: 使用 RBAC 精确控制每个租户在其指定 Namespace 内的权限。避免使用 ClusterRoleBinding 授予租户用户集群级别的权限。
- 隔离:
- 命名空间 (Namespace): 最基本的隔离单元。每个租户分配一个或多个专属 Namespace。RBAC 规则主要基于 Namespace 进行限制。
- 网络策略 (NetworkPolicy): 控制不同 Namespace 之间以及 Pod 之间的网络流量,实现网络隔离。
- 资源配额 (ResourceQuota): 限制每个 Namespace 的资源使用量,防止租户间资源争抢。
- 节点隔离 (Node Selectors/Affinity/Taints/Tolerations): 可以将特定节点分配给特定租户使用(硬隔离),但这会降低资源利用率。
- 运行时隔离 (RuntimeClass, gVisor, Kata Containers): 使用沙箱容器技术增强 Pod 间的内核级隔离。
- 可见性隔离: 通过 RBAC 限制用户只能看到其有权限访问的 Namespace 中的资源。
- 资源管理 (Quota Management):
- 使用 ResourceQuota 限制计算资源、存储资源和 API 对象数量。
- 使用 LimitRanger 设置默认资源请求和限制。
实现要点:
- 租户 onboarding: 需要自动化流程来创建 Namespace、设置 RBAC (RoleBindings)、配置 ResourceQuota 和 NetworkPolicy。
- 自定义控制器/Operator: 可以开发 Operator 来管理租户生命周期和相关资源的配置。
- 监控与审计: 对各租户的资源使用和 API 访问进行监控和审计。
9. API Server 对象实现原理
Kubernetes API 基于 “资源 (Resource)” 的概念构建。理解 API 对象的内部表示和处理方式有助于进行扩展开发(如 CRD)。
9.1 GKV 模型 (Group, Kind, Version)
Kubernetes API 使用 GKV 来唯一标识一个 API 对象类型。
- Group (组): 相关 API 功能的集合。例如
apps
,batch
,rbac.authorization.k8s.io
。核心 API (如 Pod, Service, Namespace) 属于空字符串""
组 (core group)。Group 使得 API 可以独立演进和扩展。 - Version (版本): 代表 API 的成熟度和稳定性。例如
v1
,v1beta1
,v2alpha1
。版本允许 API 随时间演进,同时保持向后兼容性。- External Version: 暴露给客户端使用的版本 (如
apps/v1
)。 - Internal Version: API Server 内部处理和存储时使用的统一版本。所有外部版本在内部都会转换成内部版本进行处理。
- External Version: 暴露给客户端使用的版本 (如
- Kind (类型): 具体的资源类型。例如
Deployment
,Pod
,RoleBinding
。Kind 在同一个 GroupVersion 内必须是唯一的。

图:GKV 示例
9.2 定义 API Group 和类型 (Go 代码示例)
在 Kubernetes 代码库中 (或自定义 API Server/CRD 控制器中),通常这样定义 GKV 和对象类型:
注册 Group 和 Version (
pkg/apis/{group}/register.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
35package core // 假设是 core group
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName 是 API Group 的名称,core group 为空字符串
const GroupName = ""
// SchemeGroupVersion 是此包定义的 Group 和内部 Version
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// SchemeBuilder 用于向 Scheme 注册类型
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// addKnownTypes 将此 GroupVersion 下的类型注册到 Scheme
func addKnownTypes(scheme *runtime.Scheme) error {
// 注册 Pod 和 PodList 类型到内部版本
scheme.AddKnownTypes(SchemeGroupVersion,
&Pod{},
&PodList{},
// ... 其他 core 类型 ...
)
// 注册外部版本 (例如 v1)
metav1.AddToGroupVersion(scheme, schema.GroupVersion{Group: GroupName, Version: "v1"})
// 需要一个 v1 包来定义 v1.Pod, v1.PodList 并实现转换逻辑
return nil
}定义对象类型 (
pkg/apis/{group}/{version}/types.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
35
36
37
38
39
40package v1 // 假设是 v1 版本
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient // Tag: 生成 client 代码
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Tag: 生成 DeepCopy 方法
// Pod 是 v1 版本的 Pod 对象定义
type Pod struct {
metav1.TypeMeta `json:",inline"` // 包含 Kind 和 APIVersion
metav1.ObjectMeta `json:"metadata,omitempty"` // 包含 Name, Namespace, Labels, Annotations 等元数据
Spec PodSpec `json:"spec,omitempty"` // Pod 的期望状态
Status PodStatus `json:"status,omitempty"` // Pod 的实际状态
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PodList 是 Pod 对象的集合
type PodList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"` // 包含 resourceVersion 等列表元数据
Items []Pod `json:"items"` // Pod 列表
}
// --- PodSpec 和 PodStatus 的定义 ---
type PodSpec struct {
Containers []Container `json:"containers"`
// ... 其他字段 ...
}
type PodStatus struct {
Phase PodPhase `json:"phase,omitempty"`
// ... 其他字段 ...
}
// ... Container, PodPhase 等类型的定义 ...
9.3 代码生成 Tags
Kubernetes 大量使用代码生成来自动创建客户端、Informer、Lister、DeepCopy 方法等。通过在 Go 代码中添加特定格式的注释 (Tags) 来指导代码生成器。
- Global Tags: 通常在包的
doc.go
文件中定义,作用于整个包。// +k8s:deepcopy-gen=package
: 为包中所有需要深拷贝的类型生成DeepCopy()
方法。// +groupName=example.com
: 指定 API Group 名称。
- Local Tags: 定义在具体类型或字段上方。
// +genclient
: 为该类型生成对应的 ClientSet 代码。// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
: 明确指示该类型需要实现runtime.Object
接口的DeepCopyObject()
方法。// +optional
: 标记字段为可选。
9.4 实现存储接口 (etcd Storage)
API Server 需要将对象持久化到 etcd。每个 API 资源都需要一个实现了 registry.Store
接口的存储后端。Kubernetes 提供了通用的存储实现 genericregistry.Store
。
1 |
|
9.5 定义业务逻辑 (Strategy)
Strategy
对象封装了特定资源类型在 Create, Update, Delete 操作时的业务逻辑和验证规则。
1 |
|
9.6 子资源 (Subresource)
子资源是附属在主资源下的特定部分,拥有独立的 API 端点和操作逻辑。例如 Pod 的 /status
, /log
, /exec
。
- 实现: 通常为子资源定义一个独立的
Strategy
(如podStatusStrategy
) 和一个独立的REST
存储对象 (如StatusREST
)。 - Status 子资源: 特别常见,用于更新对象的状态字段。其
PrepareForUpdate
逻辑通常会阻止对Spec
字段的修改,只允许更新Status
。
1 |
|
9.7 注册 APIGroup 到 API Server
定义好类型、存储和策略后,需要将它们注册到 API Server 的 HTTP Handler 中。
- 创建 Storage Map: 为每个 API Version 创建一个映射,将资源名称 (如 “pods”) 映射到其 REST Storage 对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// pkg/master/master.go (示例简化)
restStorageMap := map[string]rest.Storage{
"pods": podStorage.Pod, // Pod 主资源
"pods/attach": podStorage.Attach,
"pods/status": podStorage.Status,
"pods/log": podStorage.Log,
"pods/exec": podStorage.Exec,
"pods/portforward": podStorage.PortForward,
"pods/proxy": podStorage.Proxy,
"pods/binding": podStorage.Binding,
"bindings": podStorage.Binding, // Binding 也可以作为顶级资源访问
"pods/eviction": podStorage.Eviction,
// ... 其他 core v1 资源 ...
"services": serviceRest.Service,
"services/status": serviceRest.Status,
"services/proxy": serviceRest.Proxy,
// ...
} - 创建 APIGroupInfo: 包含 GroupVersion 信息、Scheme、参数编解码器以及 VersionedResourcesStorageMap。
1
2
3
4// pkg/master/master.go (示例简化)
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(core.GroupName, Scheme, ParameterCodec, Codecs)
// 将 v1 版本的 Storage Map 关联到 APIGroupInfo
apiGroupInfo.VersionedResourcesStorageMap["v1"] = restStorageMap - 安装 APIGroup: 调用
InstallLegacyAPIGroup
(用于 core group) 或InstallAPIGroup
(用于命名 group) 将 Handler 挂载到 API Server。1
2
3
4
5// pkg/master/master.go (示例简化)
// m 是 *Master 对象,包含 GenericAPIServer
if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {
klog.Fatalf("Error in registering group versions: %v", err)
}
9.8 代码生成工具
Kubernetes 社区维护了一套用于生成客户端、Informer、Lister、DeepCopy 方法等的代码生成工具: k8s.io/code-generator
。
deepcopy-gen
: 生成DeepCopy()
和DeepCopyObject()
方法。client-gen
: 生成类型化的客户端 (ClientSet)。informer-gen
: 生成 Informer,用于高效地监听资源变化。lister-gen
: 生成 Lister,用于从 Informer 缓存中读取资源。conversion-gen
: 生成不同 API 版本之间的转换函数。
通常使用 hack/update-codegen.sh
脚本来调用这些生成器。
1 |
|
总结
Kubernetes API Server 是集群的中枢神经系统,理解其访问控制流程(认证、授权、准入控制)、限流机制(特别是 APF)、高可用部署方式以及 API 对象的内部实现原理,对于深入掌握 Kubernetes、进行集群管理、故障排查和二次开发都至关重要。希望本文的梳理能帮助你构建更清晰的知识体系。
若想深入了解 apiserver 源码,可以参考:https://cncamp.notion.site/kube-apiserver-10d5695cbbb14387b60c6d622005583d