2.1. 架构与对象模型
Kubernetes 不是「一堆 Docker 容器」,而是一台把期望状态不断收敛为现实状态的机器。理解这句话,后面所有对象、控制器和排错都会变得有迹可循。
- 层级:
L2 · 核心
- 难度:
基础
- 预计:
45 分钟
- 前置:
集群部署、第一个应用
2.1.1. 你将学到
控制平面与工作节点各自负责什么,边界在哪里
一次
kubectl apply从提交到 Pod 运行的完整路径声明式 API、期望状态、协调循环(reconcile)的含义
一个 Kubernetes 对象的通用结构,以及 labels / annotations / ownerReferences 的区别
如何用
kubectl explain和 API 发现命令自学任意资源
2.1.2. 从「期望状态」开始
你写下的 YAML 不是「操作指令」,而是「期望状态」:
spec:
replicas: 3
这句话的含义不是「帮我启动 3 个容器」,而是「无论发生什么,请让这个 Deployment 始终有 3 个可用的 Pod」。某个 Pod 挂了,控制器会补一个;节点宕机了,调度器会在别的节点重建。这个「不断比较期望状态与实际状态,并采取行动」的过程,叫 协调循环(reconciliation loop)。
图:控制器是「水平触发」的:它不关心事件本身,只关心当前状态与期望状态的差异。
这也解释了一个常见疑问:为什么删除了一个 Pod,它又回来了?因为删除 Pod 只是改变了实际状态,而 Deployment 的期望状态仍然是 3 个副本。
2.1.3. 控制平面
控制平面是集群的「大脑」,通常运行在 control-plane 节点上。
组件 |
职责 |
关键事实 |
|---|---|---|
kube-apiserver |
所有 API 请求的入口 |
唯一直接读写 etcd 的组件;无状态,可水平扩展 |
etcd |
保存集群全部状态 |
强一致 KV;必须备份;磁盘延迟直接影响 API 性能 |
kube-scheduler |
决定 Pod 跑在哪个节点 |
只负责「绑定」,不负责启动容器 |
kube-controller-manager |
运行各类控制器 |
Deployment、Node、Job、Endpoint 等控制循环 |
cloud-controller-manager |
对接云厂商 |
负载均衡、节点生命周期、路由 |
图:所有组件都通过 API Server 通信,组件之间不直接对话。
2.1.3.1. API Server 不只是「转发」
每个请求进入 API Server 后,大致经过:
认证(Authentication):你是谁?客户端证书、Bearer Token、OIDC……
授权(Authorization):你能做什么?RBAC、ABAC、Webhook。
准入(Admission):请求是否合规?Mutating Webhook 先改,Validating Webhook 后校验。
持久化:写入 etcd,并通知 watch 的客户端。
这也是为什么很多「Pod 创建不出来」的问题,根因在准入控制器或配额,而不是镜像。
2.1.3.2. etcd 的边界
etcd 保存的是「集群状态」,不是容器日志或业务数据。
默认数据目录
/var/lib/etcd,生产环境应使用独立 SSD。etcd 挂掉时,已有 Pod 可能继续运行,但 API 不可用,控制器无法收敛。
备份 etcd 是集群灾备的底线,参见 备份与恢复。
2.1.4. 工作节点
组件 |
职责 |
关键事实 |
|---|---|---|
kubelet |
节点上的「代理人」 |
watch 分配到本节点的 Pod,调用 CRI 启动容器 |
容器运行时 |
真正运行容器 |
containerd / CRI-O,通过 CRI 接口对接 |
kube-proxy |
实现 Service 转发 |
iptables / IPVS 模式;Cilium 可替换它 |
CNI 插件 |
Pod 网络 |
分配 IP、配置路由、实现 NetworkPolicy |
CSI 插件 |
存储挂载 |
把 PV 挂到 Pod 的 volumeMounts |
kubelet 不直接创建 Pod,它只是「让实际状态靠近 spec」:拉镜像、建沙箱、挂卷、启动容器、上报状态。容器运行时只认 CRI,不认 Kubernetes API。
2.1.5. 一次 apply 的完整路径
图:一次部署的简化时序。真实链路还包括 CNI 分配 IP、CSI 挂载卷、探针上报等。
2.1.6. 对象模型
2.1.6.1. 通用结构
apiVersion: apps/v1 # API 组 + 版本
kind: Deployment # 资源类型
metadata:
name: demoapp # 命名空间内唯一
namespace: demo # 命名空间级资源才需要
labels: # 用于选择、分组
app: demoapp
annotations: # 用于附加信息,不参与选择
owner: platform-team
spec: # 期望状态(你写)
replicas: 2
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
- name: app
image: nginx:1.27
status: # 实际状态(控制器写)
readyReplicas: 2
字段 |
谁写 |
用途 |
|---|---|---|
|
你 |
决定资源类型与版本 |
|
你 |
资源标识 |
|
你 / 控制器 |
被 selector 选中,参与调度与策略 |
|
你 / 控制器 |
存放非标识性元数据,可被工具读取 |
|
控制器 |
表达所有权,级联删除的依据 |
|
你 |
期望状态 |
|
控制器 |
实际状态,只读 |
2.1.6.2. 命名空间级 vs 集群级
# 查看资源是否属于命名空间
kubectl api-resources --namespaced=true | head
kubectl api-resources --namespaced=false | head
命名空间级:Pod、Deployment、Service、ConfigMap、PVC……
集群级:Node、Namespace、ClusterRole、StorageClass、CustomResourceDefinition……
命名空间不是「文件夹」,它影响:
名称作用域(同名资源可在不同 namespace 共存)
RBAC 授权范围
资源配额与限制
NetworkPolicy 的选择范围
DNS 名称:
svc.namespace.svc.cluster.local
2.1.6.3. labels、annotations、ownerReferences
机制 |
是否参与选择 |
典型用途 |
|---|---|---|
labels |
是 |
Service 选 Pod、Deployment 选 ReplicaSet、节点亲和 |
annotations |
否 |
Ingress 配置、证书签发、变更原因、监控抓取 |
ownerReferences |
否 |
级联删除、控制器所有权 |
一个常见的排错场景:Service 的 selector 写错一个标签,Endpoints 就为空,访问直接失败。标签不是注释,它是「连接对象的线」。
2.1.7. 声明式与命令式
方式 |
示例 |
适用 |
|---|---|---|
命令式 |
|
临时调试、一次性操作 |
声明式 |
|
可重复、可版本化、生产推荐 |
apply 会根据 last-applied-configuration 或服务端 managedFields 做三方合并。多人协作时,建议统一使用 Server-Side Apply:
kubectl apply --server-side -f demoapp.yaml
不要混用 kubectl edit 与 Git 中的 YAML,否则下一次 apply 可能覆盖手工修改,或者产生字段冲突。
2.1.8. 实验:追踪一次对象创建
2.1.8.1. 1. 打开详细日志
kubectl apply -f demoapp.yaml -v=6
观察输出中的请求 URL、请求体、响应码。-v=8 会打印完整的请求与响应,适合排查准入或序列化问题。
2.1.8.2. 2. 观察事件
kubectl get events -n demo --sort-by=.lastTimestamp
kubectl describe deploy demoapp -n demo
describe 的 Events 段会显示 Deployment → ReplicaSet → Pod 的创建过程,以及调度、拉镜像、探针结果。
2.1.8.3. 3. 查看所有权
kubectl get pod -n demo -l app=demoapp -o jsonpath='{range .items[*]}{.metadata.name}{" owner="}{.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}{end}'
预期看到 Pod 的 owner 是 ReplicaSet,ReplicaSet 的 owner 是 Deployment。
2.1.8.4. 4. 查看 API 资源与字段文档
kubectl api-resources | grep -E 'deployments|pods|services'
kubectl explain deployment.spec.strategy
kubectl explain pod.spec.containers.livenessProbe --recursive | head -40
kubectl explain 是最被低估的学习工具。它给出的是当前集群 API 版本的真实字段,而不是某篇博客的旧版本。
2.1.8.5. 5. 观察控制器自愈
kubectl delete pod -n demo -l app=demoapp --wait=false
kubectl get pods -n demo -w
你会看到旧 Pod 进入 Terminating,新 Pod 很快被创建。删除 Pod 不会改变 Deployment 的期望副本数。
2.1.9. 常见问题
现象 |
可能原因 |
排查入口 |
|---|---|---|
|
API 版本不存在 / CRD 未安装 |
|
对象创建成功但无 Pod |
selector 不匹配 / 控制器未运行 |
|
Pod 一直 Pending |
调度失败 / 资源不足 / 污点 |
|
删除对象后子对象残留 |
ownerReferences 丢失 / finalizer 阻塞 |
|
|
API Server / etcd 异常 |
|
字段被「改回去」 |
多个控制器 / GitOps 同时写 |
查 |
2.1.10. 进阶挑战
用
kubectl get deploy demoapp -o yaml找到metadata.managedFields,解释每个 manager 改了什么。创建一个 CRD,再用
kubectl explain查看它的字段。给 Deployment 加一个不存在的
serviceAccountName,观察 Pod 创建在哪一步失败。用
kubectl auth can-i验证当前用户对deployments的权限。画出你自己的集群架构图,标注每个组件的故障影响。
2.1.11. 小结
Kubernetes 的核心是「期望状态 + 控制器协调」,不是容器编排命令的集合。
所有组件通过 API Server 通信,etcd 是唯一的状态源。
对象由
apiVersion / kind / metadata / spec / status构成,labels 负责选择,annotations 负责附加信息。排错先问「期望状态是什么、实际状态是什么、哪个控制器没有收敛」。