2.1 API Server:一切声明的唯一受理窗口


2.1 API Server:一切声明的唯一受理窗口

kube-apiserver 是控制平面的前端组件:以 REST 风格对外暴露资源对象的增删改查与 watch 接口,对内唯一有权读写 etcd。kubectl、调度器、控制器、kubelet 全都是它的客户端。本节讲清资源模型与星型拓扑,这是读懂一切 kubectl 行为与报错的底层语法。

上一章我们把声明写好、这一章把它送进门。进门这一步的所有规矩——资源怎么命名、请求怎么组织、组件怎么对话——都由 API Server 制定。先把它的地位置准,后面两节的安检与账本才有落脚点。

一扇只认声明的窗口

API Server 最容易被低估的属性是:它是整个集群唯一的大门。你可以把它想象成一座大楼的总服务台,任何访客(kubectl、Dashboard、CI 系统)要办事都得排队取号;楼内各部门(调度器、控制器、kubelet)之间也不串门,所有的信息交换都通过服务台的公告板完成。

这种星型拓扑带来三个工程收益:

  • 一致性有保障:所有状态变更都经同一扇门校验、写入同一本账,不存在多方直写造成的数据分叉;
  • 权限有单一落点:认证授权只需在大门处实施一次,楼内不必重复设卡;
  • 演进有缓冲:API 版本化(下一小节)让新老客户端可以共存,升级组件不必齐步走。

kubectl 的每个动作都对应一次对 API Server 的 HTTP 请求。get 是读、apply 是写、watch 是订阅,verbs 与资源的组合构成权限模型,2.2 节的 RBAC 就是按这个组合授权的。

资源模型:apiVersion 与 kind 的来历

写 YAML 时开头的两行,其实是在查一张全局目录。Kubernetes 把资源按"组"分类:核心组(Pod、Service、ConfigMap 等,apiVersion 写 v1)、apps 组(Deployment、StatefulSet 等)、networking 组(Ingress、NetworkPolicy 等)。组之下再分版本,v1、v1beta1 之类,表示成熟度。用一个命令可以看到集群支持的整张目录:

# 列出集群全部资源类型(输出很长,节选) kubectl api-resources # NAME SHORTNAMES APIVERSION NAMESPACED KIND # pods po v1 true Pod # services svc v1 true Service # deployments deploy apps/v1 true Deployment # ingresses ing networking.k8s.io/v1 true Ingress

四列各有讲究:SHORTNAMES 是命令行缩写(po、deploy),日常敲命令能省一半字符;APIVERSION 就是 YAML 第一行要写的内容,写错了这扇门不认;NAMESPACED 决定资源属于某个命名空间还是全集群;KIND 是资源类型的正式名称,YAML 第二行的 kind 从这里取。

kubectl 本质上是这台 HTTP 服务的客户端,绕开它直接看原始应答能加深理解:

# 以原始接口读取一个资源对象(--raw 直接走 HTTP) kubectl get --raw /api/v1/namespaces/production/pods/orders-with-sidecar # 应答节选(JSON): # {"kind":"Pod","apiVersion":"v1", # "metadata":{"name":"orders-with-sidecar","namespace":"production", # "resourceVersion":"184553", "uid":"5c1a..."}, # "spec":{"containers":[...]}, # "status":{"phase":"Running","podIP":"10.244.1.5"}}

应答比 YAML 多出两块:metadata 里的 resourceVersion 与 uid(账本页码与唯一指纹,2.3 节的主角),以及整个 status 段。这里藏着资源模型的第二个关键认知:spec 是你的声明,status 是集群陈述的现状,两者同存于一个对象中,正是"差值驱动"得以实现的数据基础。

💡 关键直觉:读 kubectl 输出时心里默念"我在读一本账的某一页"。get 读页、apply 改页、watch 盯页的变更,整本账的名字叫 etcd。

一次受理的完整往返

把 1.2 节的 apply 动作拆开看往返细节。kubectl 并非盲目提交,它会先读后写:

# 提交前加 --dry-run=server 预演:走完全部安检但不落账 kubectl apply -f orders-deploy.yaml --dry-run=server # deployment.apps/orders-api created (server dry run) # 括号注明 dry run:声明合法,但账本未变 # 观察一次真实写入的详细过程 kubectl apply -f orders-deploy.yaml -v=6 # ... GET /apis/apps/v1/namespaces/production/deployments/orders-api (先查旧账) # ... respond 404:不存在,走创建分支 # ... POST /apis/apps/v1/namespaces/production/deployments (提交新账) # ... respond 201:受理成功 # deployment.apps/orders-api created

日志里的三步往返——先 GET 查旧账、404 确认不存在、再 POST 创建——就是 apply 与 create 的本质区别:apply 是"对账式提交",create 是"开户式提交"。这也解释了为什么重复 apply 是安全的:有旧账就打补丁,没旧账就开户,两种路径殊途同归。

案例:一次跨命名空间的误会

背景:新同事把 orders-api 的声明提交到默认空间,找不到自己的 Deployment,怀疑集群坏了。

操作:先看当前上下文与目标空间的账:

# 看当前客户端上下文:命名空间是客户端状态 kubectl config view --minify --output 'jsonpath={..namespace}' # production # 分别查两个空间 kubectl get deployments -n production # NAME READY UP-TO-DATE AVAILABLE AGE # orders-api 3/3 3 3 2d kubectl get deployments -n default # No resources found in default namespace.

结果:声明一直好好地在 production 空间,客户端当时指向了 default 才什么都看不见。

解读:命名空间是资源模型中的逻辑分区,客户端的当前空间决定了"你在哪个房间找东西"。跨空间检索要么写明 -n,要么用 --all-namespaces。这类误会占新手"资源丢失"类问题的大头。

变式:团队协作时建议在 kubeconfig 里为每个人配好默认空间,或在命令别名里固定 -n 参数,把"记着切空间"这种人力负担交给配置;多环境(开发、测试、生产)则常用空间隔离,配合 2.2 节的 RBAC 做到"测试同学看不见生产空间"。

本节要点回顾

  • 唯一大门:所有组件都是 API Server 的客户端,星型拓扑保证一致性、权限单一落点与平滑演进;
  • 资源目录:apiVersion 是组与版本,kind 是类型名,kubectl api-resources 可查全表;
  • spec 与 status 分居:声明与现状共存一个对象,是差值驱动的数据基础;
  • apply 是对账式提交:先 GET 后 POST,重复执行幂等;server dry-run 可全程预演安检;
  • 命名空间是检索分区:找不到资源先查客户端当前空间,别急着怀疑集群。

窗口的门规清楚了,下一节把安检流水线拆开:认证确认你是谁、授权决定你能动什么、准入决定这份声明要不要被改——三道关卡一道都少不了。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U