### 🏨 顶层抽象(集群的大脑)
– **Cluster(集群)**:整个酒店大楼,包含所有硬件资源(服务器)和软件系统。
– **Master(控制平面/管理节点)**:酒店总经理办公室。负责调度、决策、监控状态(API Server、Scheduler、Controller Manager 等)。**它不直接接待客人,只发号施令**。
– **Node(工作节点/宿主机)**:具体干活的服务员(物理机或虚拟机)。Master 下达命令,Node 负责执行并运行实际的应用。
—
### 👷 工作负载(具体干什么活)
– **Pod(豆荚)**:**K8s 中最小的部署单元**。可以理解为**一个标间**(或一个共享卫生间的套房)。里面住着 1 个或多个容器(Container),它们共享网络和存储。**通常一个 Pod 只跑一个主容器**。
– **Controller(控制器)**:**“监工”**。它确保 Pod 始终处于你想要的状态。主要有几种类型:
– **Deployment(无状态部署)**:最常用。像**连锁酒店前台**——客人来了随时开房,退房就关,临时坏了直接换个新房间,IP 变了也无所谓(适合 Web 服务、API)。
– **StatefulSet(有状态部署)**:像**专属 VIP 包间**。每个房间有固定编号(稳定的网络标识)和固定衣柜(持久化存储),坏了也得修好原样还给原客人(适合数据库、Redis、Kafka)。
– **DaemonSet(守护进程集)**:**每个楼层必须配备的消防员**。在每个 Node 上且只跑一个 Pod,用于日志收集、监控(如 Prometheus 的 node exporter)。
– **Job/CronJob(任务)**:**临时工**。一次性跑完就结束(Job),或者每天定时打扫卫生(CronJob,定时任务)。
—
### 🌐 网络与访问(怎么找到房间)
– **Service(服务)**:**酒店总机号码**。Pod 是动态的(经常重启换 IP),Service 提供一个固定的 VIP(虚拟IP)和 DNS 名字,帮你做负载均衡。类型包括:
– **ClusterIP**:内部总机(仅集群内访问)。
– **NodePort**:给每个服务员(Node)开个固定窗口(端口),让外部能敲门。
– **LoadBalancer**:对接云厂商的“酒店大堂总闸”(云负载均衡器),真正把流量引进来。
– **Ingress(入口)**:**酒店大堂的前台接待**。它不是 Service,而是七层(HTTP/HTTPS)路由规则。比如访问 `api.xxx.com` 转到 Service A,访问 `web.xxx.com` 转到 Service B,且负责 SSL 证书卸载。
—
### 💾 存储(数据放哪里)
– **Volume(卷)**:**行李箱**。Pod 挂了,里面的数据就没了,所以要把数据放在 Volume 里。
– **PersistentVolume(PV,持久卷)**:**酒店的大仓库**(实际存储,如 NFS、云硬盘)。
– **PersistentVolumeClaim(PVC,持久卷申领)**:**仓库租用申请单**。Pod 不需要知道仓库在哪,只要提申请(比如“我要 10G 存储”),系统会自动分配最匹配的 PV 给它。
—
### 📦 配置管理(环境变量怎么配)
– **ConfigMap(配置映射)**:**酒店的服务手册**。存非敏感配置(如日志级别、超时时间)。Pod 启动时把手册内容挂进去,改手册不用重建镜像,只需重启 Pod。
– **Secret(密钥)**:**保险柜**。存敏感数据(密码、Token、证书),内容会做 Base64 编码,比 ConfigMap 更安全。
—
### ⚙️ 调度与策略(怎么安排资源)
– **Scheduler(调度器)**:**客房分配专员**。新 Pod 来了,它根据资源余量、亲和性(是否跟别的 Pod 靠近)、污点/容忍度等,决定把这个 Pod 放到哪个 Node 上。
– **Resource(Requests/Limits)**:**房间预定和上限**。Requests 是“至少要多大空间”,Limits 是“最多不能超过多大”,防止一个 Pod 吃光所有 CPU/内存。
这个问题问得非常深入,直接触及了K8s运作的**灵魂**。很多人知道Pod生命周期,但不太清楚**控制平面(API Server/Controller)**和**数据平面(kubelet/Service)**在背后是如何“打配合”的。
要理解这个交互,你必须把Pod的生命周期从“静态阶段图”升级为**“事件驱动+控制器循环”**的视角。
我用一个**“智能酒店中央系统”**的比喻,把**API Server(前台总机)、Controller(部门经理)、Scheduler(调度主管)、kubelet(客房服务员)**和**Service(外部电话交换机)**串起来,给你拆解完整流程:
—
### 核心前提:K8s 的“心脏”机制(控制循环)
K8s的一切交互都基于 **List-Watch(监听-回调)** 机制。
– **API Server** 是唯一的数据源(ETCD数据库的入口)。
– **所有组件(Controller、Scheduler、kubelet)** 绝不轮询,而是**长连接长驻**,死死盯着API Server。一旦ETCD里Pod的状态发生变化,API Server会立即“广播”给所有监听的组件。
—
### 第一阶段:创建交互(从 YAML 到 Running)
这个阶段是 **“声明式API”** 的完美体现——你只管说“我要什么”,系统自动帮你“实现”。
1. **提交(你 -> API Server)**
– 你执行 `kubectl apply -f deploy.yaml`。这个命令只做一件事:**把YAML内容通过HTTP POST请求,发给API Server**。
– API Server做两件事:**认证鉴权**(你是谁?有没有权限?) + **数据校验**(字段写对没?)。通过后,**存入ETCD**。此时Pod在ETCD里的状态是 `Pending`。
2. **监听与创建(Controller -> API Server -> Scheduler)**
– **Deployment Controller(部门经理)** 一直通过List-Watch盯着API Server。它“看”到ETCD里新增了一个ReplicaSet的期望状态(比如“我要3个Pod”),但它**不直接创建Pod**。
– 它只是调API Server的接口,创建出3个**空白Pod模板**(只有元数据,没有Node名称)。这3个Pod在ETCD里的`spec.nodeName`字段是**空**的。
– **Scheduler(调度主管)** 一直盯着所有 `nodeName` 为空的Pod。它“抢”到这3个Pod,通过打分算法,把选中的Node名字**写回**到Pod的 `spec.nodeName` 字段(依然是调API Server更新ETCD)。
3. **拉取与运行(API Server -> kubelet)**
– 在选中的Node上,**kubelet(客房服务员)** 一直盯着API Server。它发现自己Node上被分配了新Pod。
– kubelet拿到Pod定义,开始调本地的Container Runtime(如Docker/containerd)去拉镜像、创建容器。
– 容器启动后,kubelet把Pod状态**回写**给API Server(更新为 `Running`),API Server存进ETCD。
—
### 第二阶段:运行期交互(探针、重启与Controller的“纠偏”)
这个阶段是 **“自愈能力”** 的体现,核心在于 **Controller 和 kubelet 各司其职**。
**1. 健康检查与状态上报(kubelet <-> API Server)**
– Pod运行期间,**kubelet** 负责执行你在YAML里定义的 `livenessProbe` 和 `readinessProbe`。
– 探针结果怎么通知系统?kubelet不直接发消息给Controller,而是**修改Pod的Status字段**(比如把`ready`条件设为False),并**通过API Server更新到ETCD**。
– 同时,kubelet会把Pod的实时日志、CPU内存指标(通过cAdvisor)也一并上报给API Server(或Metrics Server)。
**2. 控制器纠偏(Controller <-> API Server)**
– **ReplicaSet Controller** 一直盯着API Server里的Pod列表。如果它发现当前Pod数量(比如2个)不等于期望数量(3个),它就会调用API Server**再创建一个新Pod**。这就是**控制器循环**。
– **重点:Controller 从不直接操作 Pod 或 Node,它只操作 API Server 里的 ETCD 数据。** 真正的物理操作(杀容器、启容器)只由 Node 上的 **kubelet** 执行。
**3. 故障自愈的完整闭环**
假设一个Node宕机了(网络断连):
– kubelet无法上报心跳(Lease)给API Server。
– Node Controller(专门管节点的经理)发现节点心跳超时(默认40秒),将Node标记为 `NotReady`。
– 又过了5分钟(Pod驱逐阈值),Node Controller调用API Server,将这台Node上的所有Pod标记为 `DeletionTimestamp`(删除时间戳)。
– ReplicaSet Controller监听到Pod被标记删除,调用API Server,在**其他健康的Node**上创建新的替代Pod。
– Scheduler监听到新Pod(nodeName为空),调度到健康Node -> kubelet拉起来。**自愈完成**。
—
### 第三阶段:访问交互(Pod 与 Service 的动态绑定)
Service 不是一块固定的“网络配置”,而是一个**动态的、随时刷新的“负载均衡名单”**。它和Pod的交互完全依赖 **Endpoints(端点)** 控制器。
**1. Endpoints Controller(端点控制器)**
– 当你创建Service时,Endpoints Controller会持续**监听(Watch)** API Server里**符合Service标签选择器(Selector)** 的所有Pod。
– 只要Pod的IP变了、Pod被重建了、或者Pod的 `readinessProbe` 失败了,Endpoints Controller会立刻收到API Server的事件推送。
– 它立即更新对应的 **Endpoints对象**(就是一个存着IP+Port列表的ETCD记录)。
**2. kube-proxy(流量转发器)**
– 每个Node上的 **kube-proxy** 一直盯着API Server里的 **Service** 和 **Endpoints** 对象。
– 一旦发现Endpoints列表变了(比如某个Pod的IP被剔除),kube-proxy会立刻修改本地的 **iptables 或 IPVS 规则**。
– **效果**:当你访问Service的ClusterIP时,Linux内核根据这些规则,瞬间把流量转发到**最新的、健康的Pod IP**上。
—
### 🎯 一张图总结交互逻辑
– **控制面(Control Plane)**:你(YAML)-> API Server(认证存库)-> Controller(调API调Scheduler)-> Scheduler(调API绑定Node)。
– **数据面(Data Plane)**:API Server(通知)-> kubelet(拉镜像运行)-> kubelet(探针结果回写API Server)。
– **纠偏机制**:Controller(监听API Server,发现偏差)-> 改ETCD -> kubelet(监听API Server,执行物理变更)。
– **网络交互**:Service Controller(监听Pod状态)-> 生成Endpoints -> kube-proxy(监听Endpoints)-> 改本地内核路由表。
—
### 💡 两个最颠覆认知的交互细节
1. **API Server 是唯一的“总线”**:kubelet和Controller绝不直接通信,甚至Scheduler和kubelet也绝无直接RPC。所有信息交换都必须经过API Server中转。这就保证了**幂等性**——即使kubelet离线重启,它只需重新List-Watch一遍API Server,就能拿到最新指令。
2. **Service的ClusterIP其实不存在于任何网卡上**:它只是一个**虚拟的、存在iptables规则里的标识符**。你Ping不通ClusterIP是正常的,因为它没有真实网络设备。流量走到Node内核时,按规则DNAT(目标地址转换)后直接丢给Pod。
—
如果你是想深入源码层面或者排查实际故障,**强烈建议记住一个调试命令**:
“`bash
kubectl get events –watch
“`
这个命令能让你实时看到API Server里所有事件流——你会发现刚才讲的所有交互,都在这里以“事件”形式真实发生。