APIServer 全貌、关键对象与生产经验复盘

前言:为什么要做章节总结?

啃完第五章的 4 篇,你应该能感受到——APIServer 是个怪兽

它既是 REST API 网关、又是认证授权中心、还是准入控制网关、还是存储抽象层、最后还要做限流——一个组件包了五个角色,源码十几万行。

我自己第一次啃完时也是懵的,零散的细节记一堆,全局图却画不出来——直到一次面试问"画出 kubectl create pod 的完整链路",我才发现自己学过等于没学

这篇就是把整章的细节串成一张图,让你能在脑子里跑通一次完整请求——这才算真正掌握了 APIServer。


本节重点

  • APIServer 内部三个 Server 的职责(核心 / 扩展 / 聚合
  • 一次请求的完整生命周期(Authn → Authz → Admission → Storage
  • 关键对象总览:GenericAPIServer / Scheme / RESTStorage / Storage Backend
  • 上手 APIServer 源码的实战路线图

一、APIServer 的核心定位

一句话定义:APIServer 是 K8s 控制面唯一直接读写 etcd 的组件,所有其他组件(scheduler、controller-manager、kubelet)全部通过 APIServer 间接访问数据。

这个"唯一中介"设计带来三个关键效果:

  1. etcd 不直接对外——所有客户端只能走 APIServer,APIServer 在前面做认证/鉴权/限流
  2. 统一数据视图——所有组件看到的是同一份经过 strategy 处理后的对象(status 字段、QoS class 这些都是 APIServer 加的)
  3. 可观测的总入口——所有变更都经过 APIServer,audit log 能看到一切

💡 生产建议:千万别让运维工具直接连 etcd(哪怕"只是读")——绕过 APIServer 就绕过了 RBAC、绕过了 audit、绕过了 strategy 处理。我们公司内部有条死规矩:直连 etcd 的 PR 一律拒绝


二、整体架构:三个 Server + 一个通用基座

                  ┌──────────────────────────────────┐
                  │      用户 / 客户端                 │
                  │  kubectl / controller / kubelet  │
                  └──────────────┬───────────────────┘
                                 │ HTTPS
                                 ▼
        ┌────────────────────────────────────────────────┐
        │              kube-apiserver 进程                │
        │  ┌──────────────────────────────────────────┐  │
        │  │  AggregatorServer (聚合层 / 最外层)        │  │
        │  │  └─ 转发 metrics-server、custom apiservice│  │
        │  │     ├─ 委托链 ──┐                         │  │
        │  └─────────────────┼─────────────────────────┘  │
        │  ┌─────────────────▼─────────────────────────┐  │
        │  │  KubeAPIServer (核心 API)                  │  │
        │  │  └─ Pod / Service / Deployment / ...      │  │
        │  │     ├─ 委托链 ──┐                         │  │
        │  └─────────────────┼─────────────────────────┘  │
        │  ┌─────────────────▼─────────────────────────┐  │
        │  │  APIExtensionsServer (CRD)                 │  │
        │  │  └─ CustomResourceDefinitions             │  │
        │  └───────────────────────────────────────────┘  │
        │              全部依赖 ▼                          │
        │  ┌──────────────────────────────────────────┐  │
        │  │       GenericAPIServer (通用基座)          │  │
        │  │   go-restful + 通用路由 + handler chain   │  │
        │  └──────────────────┬───────────────────────┘  │
        └─────────────────────┼──────────────────────────┘
                              ▼
                  ┌──────────────────────┐
                  │  etcd v3 (分布式存储)│
                  └──────────────────────┘

三个 Server 的分工

Server负责什么典型资源失败影响
AggregatorServer转发到外部 APIServicemetrics.k8s.iocustom.metrics.k8s.iokubectl top 不可用
KubeAPIServerK8s 原生资源Pod、Service、Deployment、ConfigMap整个集群挂
APIExtensionsServerCRD 资源CRD 定义 + 所有 CR 实例所有 CRD 不可用

💡 委托链 (Delegation Chain) 的执行顺序:请求先到 Aggregator → 它处理不了就委托给 KubeAPIServer → 还处理不了就委托给 APIExtensions → 都没匹配返回 404。详见 5.1 启动流程。


三、一次完整请求的生命周期

kubectl create -f pod.yaml 为例:

 ┌─────────────────────────────────────────────────────────────┐
 │                       请求生命周期                            │
 ├─────────────────────────────────────────────────────────────┤
 │                                                             │
 │  1️⃣  HTTP 入口                                               │
 │     POST /api/v1/namespaces/default/pods                    │
 │                       │                                     │
 │                       ▼                                     │
 │  2️⃣  限流 (Throttle)                                         │
 │     ├─ MaxInFlight (chan 信号量) 或                          │
 │     └─ APF (优先级 + 公平队列)                                │
 │                       │                                     │
 │                       ▼                                     │
 │  3️⃣  Authentication (认证: 你是谁?)                          │
 │     ├─ X.509 客户端证书                                       │
 │     ├─ ServiceAccount Token                                 │
 │     ├─ Bootstrap Token                                      │
 │     └─ OIDC / Webhook Token                                 │
 │                       │                                     │
 │                       ▼                                     │
 │  4️⃣  Authorization (鉴权: 你能干吗?)                          │
 │     ├─ RBAC (最常见)                                         │
 │     ├─ ABAC                                                 │
 │     ├─ Node (kubelet 专用)                                  │
 │     └─ Webhook                                              │
 │                       │                                     │
 │                       ▼                                     │
 │  5️⃣  Mutating Admission (变更准入)                            │
 │     ├─ DefaultIngressClass                                  │
 │     ├─ DefaultStorageClass                                  │
 │     ├─ ServiceAccount (注入默认 SA)                          │
 │     └─ MutatingAdmissionWebhook (自定义,比如 sidecar 注入)  │
 │                       │                                     │
 │                       ▼                                     │
 │  6️⃣  Schema Validation (OpenAPI 校验)                        │
 │                       │                                     │
 │                       ▼                                     │
 │  7️⃣  Validating Admission (校验准入)                          │
 │     ├─ PodSecurity                                          │
 │     ├─ ResourceQuota                                        │
 │     ├─ LimitRanger                                          │
 │     └─ ValidatingAdmissionWebhook                           │
 │                       │                                     │
 │                       ▼                                     │
 │  8️⃣  RESTStorage.Create()                                   │
 │     └─ genericregistry.Store.Create                         │
 │         ├─ BeforeCreate                                     │
 │         │   ├─ Strategy.PrepareForCreate                    │
 │         │   │   ├─ Status = Pending                         │
 │         │   │   ├─ QOSClass = GetPodQOS                     │
 │         │   │   └─ DropDisabledPodFields                    │
 │         │   ├─ EnsureObjectMeta (UID)                       │
 │         │   ├─ Validate                                     │
 │         │   └─ Canonicalize                                 │
 │         ├─ Storage.Create (写 etcd)                          │
 │         │   ├─ Encode (protobuf)                            │
 │         │   ├─ Transformer (加密)                            │
 │         │   └─ Txn().If(notFound).Put()                     │
 │         └─ Decorator / AfterCreate                          │
 │                       │                                     │
 │                       ▼                                     │
 │  9️⃣  Audit (审计)                                            │
 │     └─ 写 audit log                                          │
 │                       │                                     │
 │                       ▼                                     │
 │  🔟  Response                                                │
 │     └─ 返回 201 Created + 完整 Pod 对象 (含 RV)              │
 │                                                             │
 └─────────────────────────────────────────────────────────────┘

🚨 顺序非常关键

  • 限流在认证之前 → 即使匿名请求也能被限流(防 DDoS)
  • Mutating Admission 在 Schema Validation 之前 → webhook 可以加字段
  • Mutating Admission 在 Strategy.PrepareForCreate 之后 → 这就是 5.3 里那个 status 被改空的坑的根源

四、关键对象总览

4.1 GenericAPIServer(通用基座)

位置:staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go

职责

  • go-restful 注册路由
  • 装配 handler chain(认证 / 鉴权 / 准入 / 限流 / 存储)
  • 管理 PostStartHook 生命周期

为什么有它? 因为三个 Server 大部分逻辑(HTTP、限流、认证、handler chain)都是一样的——把通用部分抽出来,三个 Server 各自只关心自己的资源注册。这是教科书级别的模板方法模式。

4.2 Scheme(类型注册中心)

位置:staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go

type Scheme struct {
    gvkToType         map[schema.GroupVersionKind]reflect.Type
    typeToGVK         map[reflect.Type][]schema.GroupVersionKind
    converter         *conversion.Converter
    versionPriority   map[string][]string
    ...
}

Scheme 是 K8s 类型系统的"通讯录",干三件事:

  1. 类型注册:每个资源类型(Pod、Deployment)都要在 Scheme 里注册其 GVK(GroupVersionKind)
  2. 版本转换v1.Pod ↔ internal.Podv1beta1.Deployment ↔ v1.Deployment
  3. 序列化/反序列化:JSON、YAML、protobuf 互转

💡 K8s 多版本机制的核心:客户端用 v1,etcd 存内部版本(internal),转换全靠 Scheme。这就是为什么 K8s 能"兼容老 API 又能演进"——内部存 internal,对外提供多版本视图。

4.3 RESTStorage(REST 与存储的桥梁)

每种资源都有一个 RESTStorage,长这样:

type REST struct {
    *genericregistry.Store
    proxyTransport http.RoundTripper
}

genericregistry.Store 是个通用 CRUD 引擎,资源专属逻辑通过 Strategy 注入:

字段作用
NewFunc怎么创建空对象(func() runtime.Object { return &Pod{} }
CreateStrategyCreate 时的预处理 + 校验
UpdateStrategyUpdate 时的预处理 + 校验
DeleteStrategyDelete 时的预处理
Storage底层存储后端(DryRunnableStorage → etcd3)

Strategy 模式的精髓:通用 Store 处理 90% 的 CRUD,每个资源只写自己那 10% 的特殊逻辑。详见 5.2。

4.4 Storage Backend(存储后端)

podStorage.Storage
    │
    ▼
DryRunnableStorage  (拦截 dryRun)
    │
    ▼
CacherStorage       (内存 watch cache,加速 list)
    │
    ▼
etcd3.store         (真正的 etcd 客户端)
    │
    ▼
etcd v3 集群

几个关键层

  • CacherStorage:内存 watch cache——所有 watch 请求不直接打 etcd,而是命中这个 cache。这就是为什么大量 watch 不会把 etcd 拖死
  • DryRunnableStorage:拦截 --dry-run=server——上面跑完所有逻辑,到这一层直接返回
  • etcd3.store:序列化 + 加密 + Txn 写入

🚨 CacherStorage 是性能关键:如果它和 etcd 失联(resourceVersion 严重落后),就会触发 relist——一次 list 整个资源的全部对象。生产中如果看到 apiserver_storage_consistency_checks_total 异常,赶紧排查,否则可能引发 list 风暴。

4.5 关键对象关系图

              ┌──────────────────┐
              │  GenericAPIServer│  通用基座
              └────────┬─────────┘
                       │ 持有
                       ▼
              ┌──────────────────┐
              │  go-restful路由   │
              └────────┬─────────┘
                       │ 注册资源
                       ▼
              ┌──────────────────┐
              │   RESTStorage    │  每个资源一个
              │   (Pod/SVC/...)  │
              └────────┬─────────┘
              ┌────────┴────────┐
              ▼                 ▼
        ┌──────────┐      ┌──────────┐
        │ Strategy │      │  Storage │
        │ (业务逻辑)│      │ (存储链)  │
        └────┬─────┘      └────┬─────┘
             │                 │
             ▼                 ▼
       ┌──────────┐      ┌──────────┐
       │  Scheme  │      │ Cacher → │
       │ (类型注册)│      │  etcd3   │
       └──────────┘      └──────────┘

五、Authentication / Authorization / Admission 三道关

5.1 Authentication(你是谁?)

目的:识别请求来源,确定 user.Info(含 username、groups、UID)。

常见 authn 方式(按生产使用频率):

方式用途生产建议
X.509 Client Certkubelet、kubectl admin、kube-controller-manager默认 + 必备
ServiceAccount TokenPod 内访问 APIServer必备
Bootstrap Token新 Node 注册kubeadm 默认
OIDC公司 SSO 接入强烈推荐
Webhook Token自定义认证高度定制需求
静态 Token File内网测试⚠️ 生产禁用

🚨 生产坑:用了静态 token file 然后忘记轮换——token 一旦泄露就是永久后门。OIDC + 短期 token + RBAC 才是 SOTA。

5.2 Authorization(你能干吗?)

K8s 支持多种 authz 模式,按顺序执行——任意一个允许就放行:

--authorization-mode=Node,RBAC,Webhook
                     │    │      │
                     │    │      └─ 自定义 webhook
                     │    └─ 角色绑定(最常用)
                     └─ kubelet 专用(限制 kubelet 只能读自己节点的资源)

💡 Node 模式很重要:它限制 kubelet 只能 get/list 自己节点上的 Pod、Secret 等——防止一个被攻陷的 Node 横向窃取整个集群的 Secret。1.13+ 默认开启。

5.3 Admission(合规检查 + 改写)

Admission 分两类:

  • MutatingAdmission:可以改 object(注入 sidecar、补默认值)
  • ValidatingAdmission:只能 yes/no(PodSecurity、ResourceQuota)

执行顺序Mutating → Schema 校验 → Validating

K8s 内置的关键 admission plugin:

Plugin类型作用
NamespaceLifecycleV不允许操作正在删除的 namespace
ServiceAccountM自动绑定默认 SA、挂载 token
LimitRangerM根据 LimitRange 补默认 requests/limits
ResourceQuotaV检查是否超过 namespace 配额
PodSecurityV替代旧的 PodSecurityPolicy
DefaultStorageClassM给 PVC 自动选默认 StorageClass
MutatingAdmissionWebhookM用户自定义(如 Istio sidecar 注入)
ValidatingAdmissionWebhookV用户自定义(如 OPA Gatekeeper)

🚨 第 4 章学过的 sidecar 注入就是 MutatingAdmissionWebhook——所有 service mesh(Istio、Linkerd)都靠这个机制实现自动注入。


六、限流策略快速回顾

详见 5.4。这里只放精华表:

方案场景实现建议
client-go RateLimiter客户端自限速令牌桶默认 QPS=5 太低,必调
MaxInFlightLimitserver 整体粗限流chan 信号量APF 未启用时的兜底
EventRateLimitevent 资源专用多桶令牌桶event 多的集群必开
APF优先级 + 公平队列Shuffle Sharding + 并发预算生产首选

记住三个关键源码模式:

  1. chan + select default = 非阻塞信号量(MaxInFlight)
  2. Shuffle Sharding = 隔离吵闹邻居(APF)
  3. watermark = 滑动指标平滑(throttle metrics)

七、上手 APIServer 源码的实战路线图

阶段一:跑通最小请求(半天)

  1. clone kubernetes/kubernetes,切到 stable tag(如 v1.30)
  2. 在 IDE 里打开 cmd/kube-apiserver/apiserver.go,找到 main 函数
  3. 一路跟到 app.RunCreateServerChain(5.1 讲的入口)
  4. 用 IDE 的 “Call Hierarchy” 工具向下钻,画一张调用图

阶段二:找一个资源跟到底(一天)

挑一个简单资源(比如 ConfigMap),通过断点 + 日志跟踪:

HTTP handler → REST.Create → genericregistry.Store.Create
  → BeforeCreate → Strategy.PrepareForCreate
  → Storage.Create → etcd3.store.Create

跟完一次你就永远忘不了这条链路。

阶段三:尝试加一个字段(两天)

给某个 K8s 资源(用自定义 fork)加个字段。你会被迫接触:

  • types.go(定义结构)
  • defaults.go(默认值)
  • validation.go(校验)
  • strategy.go(PrepareForCreate)
  • conversion(多版本转换)
  • protobuf 生成(make update)

走完这套你就是半个 K8s 贡献者了。

阶段四:写一个 Admission Webhook(一周)

参考 4.3、4.4 的 sidecar 注入实战。把 webhook 部署到集群、生效、捕获请求、改写、放行——这是 APIServer 扩展能力的实战。

阶段五:调 APF(一周)

模拟流量(用 kube-burnerk6),观察 APF 各 priority level 的指标,调整 nominalConcurrencyShares——这是真正的 SRE 实战。

💡 关键工具

  • dlv(Go 调试器)+ vscode-go:源码断点
  • kube-burner:APIServer 压测利器
  • Prometheus + 官方 dashboardskubernetes/kubernetes 仓库带的 mixin

八、生产经验复盘:第五章学到的核心教训

#教训来自
1永远不要直连 etcd——绕过所有保护全章
2mutating webhook 不要改 status——会被信任并保留5.3
3client-go 默认 QPS=5,生产必须调高5.4
4--max-requests-inflight=0 是关闭限流不是无限5.4
5system:masters 永远豁免限流——业务别用 cluster-admin5.4
6feature gate 关了字段会被静默丢弃——排查必查5.3
7加密 key 一定要备份——丢了等于数据丢5.3
8watch 不受 MaxInFlight 控制,切到 APF5.4
9三个 Server 委托链顺序:Aggregator → Kube → Extension5.1
10Strategy 模式是 K8s 处理资源多样性的核心抽象5.2

九、章节思考题

回答这些问题,验证你是否真懂了:

  1. 同一个 Pod 对象在内存、etcd、kubectl 三处的形态分别是什么?经过哪些转换?
  2. 为什么 K8s 选 Strategy 模式而不是给每个资源写独立 handler?
  3. APF 完全替代得了 MaxInFlight 吗?什么场景下还会用 MaxInFlight?
  4. 如果你要为某种新资源(比如自定义 GPU 资源)加 APIServer 支持,最少要改哪些文件?
  5. 一个 Pod 创建后,scheduler 是怎么"知道"它的?这背后的机制是什么?

十、本节小结

APIServer 是 K8s 控制面的核心枢纽,理解它的关键是抓住几条主线:

  • 架构主线:三个 Server(Aggregator/Kube/Extension)+ 一个通用基座(GenericAPIServer)
  • 请求主线:限流 → Authn → Authz → Admission → Storage → Audit
  • 数据主线:Scheme 注册 → RESTStorage 路由 → Strategy 处理 → Storage 写 etcd
  • 保护主线:四层限流(client/MaxInFlight/EventRateLimit/APF)+ 三道关(Authn/Authz/Admission)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加倍巴巴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值