LabHub
学习 学习路径 课程

KCNA — Kubernetes 与云原生入门

控制平面为什么被这样拆开

在 LabHub 中继续学习

一句话总结

Kubernetes 不是“执行命令的系统”,而是**“写下期望状态后,由控制器不断让现实趋近该状态的系统”**。 控制平面之所以由多个部分组成,是因为执行这种循环的主体按职责进行了拆分。

概念图: “写下期望状态后,由控制器不断让现实趋近该状态的系统” · 保存 · reconciliation loop · 唯一入口

为什么需要它

命令式系统执行“启动 3 个 Pod”后就结束了。如果一个节点随后死亡呢?没人会在意, 因为命令早已执行完毕。

声明式系统会保存“希望保持 3 个 Pod 的状态”。随后会有主体不断读取当前状态, 与期望状态比较,并在不同的时候缩小差距。这个循环称为 reconciliation loop, 它就是 Kubernetes 的全部。其余机制都是为了让这个循环安全且可扩展。

从这个角度看,组件拆分便很自然:状态写在哪里(etcd),由谁允许读写该状态(kube-apiserver), 由谁运行循环(kube-controller-manager),由谁运行决定把 Pod 放到哪个节点的特殊循环(kube-scheduler), 以及由谁在节点上真正启动容器(kubelet)。

它如何运作

控制平面

组件 职责 消失后会怎样
etcd 保存集群全部状态的唯一存储 集群失去记忆
kube-apiserver 通往 etcd 的唯一入口。认证、授权、准入和验证 任何人都无法读写任何内容
kube-controller-manager Deployment/ReplicaSet/Node/Endpoint 等数十种控制器循环 声明会被保存,但什么也不会发生
kube-scheduler 为 Pending Pod 分配节点 Pod 会被创建,却永远保持 Pending

**任何组件都不会直接操作 etcd。**scheduler、controller manager 和 kubelet 全部通过 apiserver。 这样认证、授权、准入和审计日志才能集中在同一处生效。这是通向 KCSA 的安全设计起点。

了解 etcd 中的键结构也很有帮助。所有资源都位于 /registry/ 下, 命名空间资源采用 /registry/<종류>/<네임스페이스>/<이름>,集群资源采用 /registry/<종류>/<이름>。值默认使用 protobuf 序列化。

节点

API 由资源组成

与 Kubernetes 对话只有一种方式——对 REST 资源执行 CRUD。创建 Deployment、删除 Pod, 采用的都是同一种语法。用 kubectl api-resources 可以查看本集群已知的全部资源, 用 kubectl explain 可以查看每个字段的含义。养成不打开文档网站,直接询问集群的习惯, 无论考试还是现场工作都会最快。

标签选择器——松耦合的黏合剂

Kubernetes 中几乎没有“此 Service 直接指向那 3 个 Pod”这样的直接引用。 它会添加标签,再通过 selector 选择。Service、ReplicaSet、NetworkPolicy 全都通过 selector 寻找目标。 所以一个 selector 拼写错误就会造成无声故障——对象能正常创建,只是什么也匹配不到。

在实际工作中会遇到的情况

这是作者的家庭实验室真实发生过的事情。某天集群停止响应,并出现 dial tcp 10.0.0.111:6443: connect: no route to host。原因是 DHCP—— 控制平面节点的 IP 从 .111 更新成了 .120

这次事件让组件拆分以可见的方式显现出来:**etcd 与 kube-apiserver 因尝试绑定已经不存在的地址 .111 而失败,陷入 CrashLoopBackOff;kube-scheduler 和 controller-manager 因绑定 127.0.0.1, 进程仍然正常存活。**它们虽然活着,却什么也做不了,因为没有 apiserver,控制器就无从读取或写入。

决定性证据在证书中。apiserver.crt 的 Subject Alternative Name 里没有 .120。 所以只修改 IP 无法恢复——使用 SAN 中不存在的地址连接时,TLS 验证会失败。

后来把同一集群扩展到 7 个节点(3 个控制平面 + 4 个 GPU worker)时,又得到了更惨痛的教训。 即使建立 3 个 etcd 成员并形成 quorum,controlPlaneEndpoint 填写的却不是 VIP 或 DNS, 而是 cp-1 的物理 IP(10.0.0.120:6443)。cp-1 一旦死亡,etcd quorum 仍以 2/3 正常工作, 另外两个节点上的 apiserver 进程也都正常,但 kubectl 与 7 个 kubelet 会全部无法连接。 这就是“控制平面仍活着,却没人能找到入口”的状态。 这次事故可以归纳为一句话:数据可用性与访问可用性是完全不同的问题。

后续实验要做什么

紧接着的实验会创建 kcna-arch 命名空间、列出节点,并通过 kubectl api-resourceskubectl explain 直接向集群询问 API。然后用标签选择器筛选 Pod, 最后分别以命令式与声明式两种方式创建同一个 Deployment,确认两者的区别。