📦 Pod 是什么
Pod 是 Kubernetes 中最小的部署和调度单元,也是一组容器的集合。
📌 核心定义
Pod 是 Kubernetes 中最小的可部署单元,封装了一个或多个容器、共享存储和网络命名空间。同一个 Pod 内的容器共享:
- 网络命名空间:共享 IP 和端口空间,可通过 localhost 通信
- 存储卷:可挂载共享的 Volume
- 生命周期:一起创建、一起销毁
🏗️ Pause 沙箱容器
Pod 的核心是 Pause 容器(Infrastructure Container),它在 Pod 创建时第一个启动,负责:
- 持有 Pod 的 Network Namespace、PID Namespace、IPC Namespace
- 其他业务容器通过加入 Pause 容器的命名空间来实现网络和存储共享
- Pause 容器极其轻量,几乎不消耗资源
理解 Pause 容器 可以把 Pause 容器理解为一个”插座”,业务容器是”插头”,都插到这个插座上共享电力(网络/存储)。
下面把 Pod 从概念、底层原理、生命周期、探针、InitContainer、QoS、Hook 到常见故障做一次完整、深入、可直接用于面试/生产的详解。
Pod 是 K8s 最小调度单元,是一个或多个容器的“逻辑主机”,这些容器:
- 共享 Network、UTS、IPC 命名空间
- 共享 存储卷(Volume)
- 拥有 独立 PID 命名空间
- 被原子调度:同 Pod 容器永远在同一节点
- 生命周期一致:一起启动、一起终止、一起被调度/驱逐
类比:
- Pod ≈ 一台虚拟机
- 容器 ≈ 虚拟机里的进程
每个 Pod 里默认有个 pause 容器(镜像很小,几十 KB),作用:
- 创建共享网络栈:所有业务容器加入 pause 的 network namespace,共享同一个 IP、端口空间
- 共享生命周期:pause 不退出,Pod 不销毁
- 简化网络/存储绑定:kubelet 只需要管理 pause,再把业务容器“挂靠”进来
网络流程:
- Pod IP → pause 网卡 → 所有容器共享 localhost
- 容器间通信:直接 localhost:port,无需 NAT
📊 Phase(五大阶段)
- Pending:已创建未调度 / 调度中 / 拉镜像
- Running:调度成功,至少一个容器启动
- Succeeded:所有容器正常退出(Job 完成)
- Failed:至少一个容器异常退出
- Unknown:kubelet 失联,状态未知
🔄 详细流程(从创建到销毁)
- 创建 Pod 对象(API Server → etcd)
- 调度:Scheduler 选节点 → 绑定 NodeName
- 拉镜像:kubelet → 容器运行时(containerd)
- 启动 InitContainer(串行,必须全成功)
- 启动 Pause 容器(创建网络/存储)
- 启动主容器
- 执行 postStart Hook
- 健康检查:liveness/readiness/startup
- 运行
- 删除/驱逐:
- 执行 preStop Hook
- 发 SIGTERM(默认 30s 宽限期)
- 超时发 SIGKILL
- 销毁网络/存储
🔁 重启策略 restartPolicy
- Always(默认):任何容器退出都重启
- OnFailure:仅异常退出(非0码)重启
- Never:不自动重启(Job 常用)
🔍 三种探针区别
- livenessProbe(存活):容器卡死/无响应 → 重启 Pod
- readinessProbe(就绪):未准备好 → 从 Service 摘除,不转发流量
- startupProbe(启动):慢启动应用(Java)→ 避免启动阶段被误杀
🛠️ 探测方式
- exec:执行命令,退出码0为正常
- httpGet:请求 URL,2xx/3xx 正常
- tcpSocket:TCP 端口连通性
- grpc:gRPC 健康检查
⚙️ 关键参数
initialDelaySeconds: 5 # 启动后多久开始检查
periodSeconds: 10 # 检查频率
timeoutSeconds: 5 # 超时时间
failureThreshold: 3 # 失败多少次判定异常
successThreshold: 1 # 成功多少次判定正常
⚠️ 常见坑
- 只配 liveness,不配 readiness:启动时流量直接进来 → 503
- 超时太短、周期太小:频繁误杀
- 端口写死、路径错误:一直失败 → CrashLoopBackOff
🎯 作用
- 主容器启动前执行一次性初始化任务
- 串行执行,必须全部成功,主容器才启动
📋 典型场景
- 等待依赖服务(MySQL、Redis)就绪
- 下载配置文件、脚本
- 目录授权、权限初始化
- 预处理数据
⚡ 特性
- 共享网络/存储
- 资源隔离(可单独配 requests/limits)
- 不参与服务发现、不对外提供服务
1. requests vs limits
- requests:调度依据,保证最低资源
- limits:硬上限,防止资源溢出
2. QoS 三类(OOM 被杀优先级)
- Guaranteed:requests = limits → 最后被 OOM 杀
- Burstable:requests < limits → 中间优先级
- BestEffort:无 requests/limits → 最先被 OOM 杀
3. 生产建议
- 核心应用:Guaranteed,稳定优先
- 普通应用:Burstable,弹性+稳定平衡
- 日志/监控:BestEffort,资源紧张时优先牺牲
1. postStart
- 容器启动后立即执行
- 不阻塞容器启动,但失败会重启容器
- 用途:初始化配置、注册服务
2. preStop
- 容器终止前执行(优雅停机核心)
- 配合
terminationGracePeriodSeconds(默认30s) - 用途:关闭连接、保存数据、注销服务、通知依赖方
🌐 网络
- 每个 Pod 唯一 IP(集群内可直接互通)
- 容器共享 localhost:127.0.0.1:port 互访
- hostNetwork: true:共享节点网络(慎用,端口冲突)
💾 存储 Volume
- emptyDir:临时空卷,Pod 生命周期,可内存挂载
- hostPath:节点本地目录,绑定节点,漂移数据丢失
- PVC:持久化存储,StatefulSet 必备
- ConfigMap/Secret:配置/密钥挂载
⏳ Pending
- 原因:资源不足、PVC 未绑定、污点/亲和性不匹配、镜像拉取失败
- 排查:
kubectl describe pod看 Events
🔄 CrashLoopBackOff
- 原因:配置错误、依赖缺失、权限不足、探针失败、OOM
- 排查:
kubectl logs、kubectl describe、dmesg看 OOM
📥 ImagePullBackOff
- 原因:镜像名错、私有仓库权限、网络不通、镜像不存在
- 排查:镜像地址、Secret、节点网络
❌ Running 但无法访问
- 原因:探针失败、端口错误、网络策略拦截、路由异常
- 排查:
kubectl get ep、calicoctl get networkpolicy、iptables -L
- 一个 Pod 一个主容器,辅助容器用 Sidecar(日志、监控)
- 必须配资源限制:避免节点资源耗尽
- 同时配 liveness + readiness:启动不丢流量、异常自动恢复
- 用 InitContainer 做前置依赖,避免主容器逻辑复杂化
- 重要业务用 Guaranteed QoS,保障稳定性
- 优雅停机:preStop + 合理宽限期,避免数据丢失
如果你愿意,我可以把以上内容整理成一份 可直接打印的 Pod 深度详解文档(含 YAML 示例+面试题),你直接复制就能用。需要我整理吗?
结合 K8s 组件调用链路、内核容器技术、生命周期、钩子、探针、终止逻辑、源码级流转,分两大阶段:创建流程、销毁流程,附带关键组件、配置、异常场景、面试考点,适配运维/SRE 学习与面试。
前置说明:
集群组件:kube-apiserver、etcd、kube-scheduler、kubelet、容器运行时(containerd/runc)、CNI 网络插件
默认容器运行时:containerd + runc;Pod 包含 pause 沙箱容器 + 业务容器/Init 容器
📋 生命周期总阶段
创建 → 调度 → 拉取镜像 → 初始化容器(InitContainer) → 启动沙箱(pause) → 启动主容器 → 运行&健康检查 → 接收删除指令 → 优雅终止 → 强制销毁
👥 核心角色分工
- apiserver:集群唯一入口,接收请求、鉴权、数据写入 etcd
- etcd:集群状态持久化存储,保存所有资源对象
- scheduler:调度器,为未绑定节点的 Pod 筛选最优节点
- kubelet:节点代理,本节点所有 Pod 生命周期实际执行者
- CRI(containerd):容器运行时,创建/启动/停止容器、管理镜像
- CNI:网络插件,配置 Pod 网卡、IP、路由
📋 Pod 完整创建流程
步骤1:提交 Pod 资源请求(用户/控制器发起)
- 用户通过
kubectl apply、YAML、UI、API 等方式提交 Pod 配置; - 请求发送至 kube-apiserver;
- apiserver 执行:认证 → 授权 → 准入控制器(校验规则、资源策略、安全策略);
- 校验通过后,将 Pod 资源数据序列化写入 etcd;
- etcd 完成持久化,返回成功;此时集群中已存在该 Pod 对象,状态为
Pending。
关键点:此时 Pod 还未被调度、节点上无任何容器。
步骤2:调度器筛选节点(Scheduler 工作流程)
- kube-scheduler 持续监听 apiserver,发现 未绑定 NodeName 的 Pod;
- 执行标准调度二阶段:
- 预选(Predicate):过滤不符合条件的节点
校验:资源是否充足、节点污点、Pod 亲和/反亲和、节点标签、端口占用等;不满足直接剔除。 - 优选(Priority):对剩余节点打分,选出最优节点。
- 调度器将
NodeName写入 Pod 定义,再次提交 apiserver; - apiserver 更新 etcd 中 Pod 的节点绑定信息;
- Pod 状态仍为
Pending,但已确定运行节点。
步骤3:目标节点 kubelet 感知 Pod 变更
- 每个节点的
kubelet通过 Watch 机制 监听 apiserver; - kubelet 发现:本机需要新增一个 Pod;
- kubelet 开始执行本地创建逻辑,正式接管该 Pod 全生命周期。
步骤4:前置校验 & 镜像拉取
- kubelet 校验 Pod 配置:权限、卷、资源配额、安全上下文等;
- 调用 CRI 容器运行时(containerd):
- 检查本地是否存在对应镜像;
- 本地无镜像 → 按照镜像地址 + Secret 配置,从镜像仓库拉取镜像;
- 镜像拉取失败 → Pod 状态变为
ImagePullBackOff/ErrImagePull。
步骤5:创建并启动 Init 初始化容器(串行执行)
InitContainer 是前置一次性任务,必须全部成功,才会启动主容器。
- kubelet 按 YAML 定义,串行逐个创建 Init 容器;
- 为 Init 容器配置:卷挂载、安全上下文、资源限制、命名空间;
- 启动 Init 容器,执行内部脚本/程序;
- 单个 Init 容器正常退出(退出码0),才会执行下一个;
- 若 Init 容器异常退出:
- 根据 Pod
restartPolicy决定是否重启 Init 容器; - 反复失败 → Pod 进入
CrashLoopBackOff。
- 所有 Init 容器全部执行成功并退出,进入下一阶段。
步骤6:创建 Pause 沙箱容器(Pod 网络/命名空间核心)
这是 Pod 最关键的底层步骤,同 Pod 所有容器共享的命名空间由此创建。
- kubelet 调用 containerd 创建 pause 容器(沙箱);
- runc 基于 Linux 内核创建一组命名空间:
- 共享:NET、UTS、IPC、Mount
- 独立:PID(默认)
- 调用 CNI 网络插件:
- 创建虚拟网卡 veth pair、分配 Pod IP;
- 配置路由、DNS、防火墙、网络策略;
- pause 容器启动并常驻,作为整个 Pod 的网络/命名空间基座;
只要 pause 不退出,Pod 网络栈就不会销毁。
步骤7:启动主业务容器
- 基于 pause 已创建的命名空间,逐个启动 Pod 内主容器;
- 挂载 Volume、ConfigMap、Secret、hostPath 等存储;
- 应用容器进程启动;
- 容器启动瞬间,执行 postStart 生命周期钩子:
- 钩子执行失败:根据重启策略重启容器;
- 钩子执行不阻塞容器主进程运行。
步骤8:启动健康探针(Probe)
容器启动完成后,kubelet 按照配置时序开启三类探针检测:
- startupProbe 启动探针(优先执行):针对慢启动应用,启动阶段独占检测;
失败 → 重启容器。 - livenessProbe 存活探针:持续检测容器是否卡死、无响应;
连续失败 → 判定容器异常,重启容器。 - readinessProbe 就绪探针:检测应用是否可对外提供服务;
- 检测成功:Pod 状态变为
Ready,Endpoint 控制器将此 Pod 加入 Service 后端,开始接收流量; - 检测失败:Pod 标记为未就绪,Service 不再转发流量。
步骤9:Pod 进入正常 Running 运行状态
- 所有容器启动完成、就绪探针通过;
- etcd 中 Pod 状态更新为
Running; - kubelet 持续循环:监控容器状态 + 执行探针检测;
- 业务正常对外提供服务,创建流程结束。
🗑️ Pod 完整销毁流程
Pod 销毁分为两类场景:手动删除、节点驱逐/资源压力驱逐,底层流程完全一致。
- 核心参数:
terminationGracePeriodSeconds(优雅终止宽限期,默认 30s) - 终止信号:
SIGTERM(15)优雅关闭 → 超时后SIGKILL(9)强制杀死
步骤1:发起删除请求
- 执行命令
kubectl delete pod <pod-name>/ 控制器缩容 / 节点驱逐; - 请求发送至 apiserver,鉴权校验后,标记 Pod 为删除状态,并添加
deletionTimestamp时间戳; - apiserver 不会立刻删除 etcd 数据,进入优雅终止倒计时。
步骤2:kubelet 感知删除事件,开始终止流程
- 节点 kubelet 通过 Watch 发现 Pod 标记删除;
- 立刻执行第一步:将 Pod 从 Service Endpoints 中摘除;
作用:不再向该 Pod 转发新流量,避免请求丢失。
步骤3:执行 preStop 生命周期钩子(优雅停机核心)
- kubelet 触发容器的
preStop钩子; - 执行提前定义的脚本/命令:关闭连接、刷盘、注销服务、保存临时数据等;
- preStop 执行期间会计入优雅宽限期。
步骤4:发送 SIGTERM 信号(优雅关闭)
- preStop 执行完成(或无 preStop),kubelet 向每个主容器 PID=1 进程发送
SIGTERM信号; - 应用程序收到信号后,执行内部优雅逻辑:
- 停止接收新请求
- 处理完存量连接
- 释放资源、关闭线程、正常退出
- 此阶段仍在
terminationGracePeriodSeconds倒计时内。
步骤5:宽限期超时判断 & 强制杀死
分两种情况:
情况A:容器在宽限期内正常退出
- 所有业务容器主动退出;
- kubelet 继续停止 pause 沙箱容器;
- 销毁网络命名空间、网卡、路由、挂载卷;
情况B:容器卡住、无法正常退出(超时)
- 超过
terminationGracePeriodSeconds设定时间; - kubelet 直接发送 SIGKILL(9) 强制杀死 所有容器进程(不可被应用捕获,强行终止);
- 强制销毁容器、网络、挂载资源。
步骤6:资源回收 & 数据清理
- 销毁 Pod 对应的所有容器、网络栈、虚拟网卡;
- 临时卷
emptyDir数据全部删除; - 持久化卷(PVC/hostPath)根据回收策略保留数据。
步骤7:etcd 最终清理,Pod 完全消失
- 节点 kubelet 确认本地 Pod 资源全部销毁;
- 通知 apiserver 彻底删除 etcd 中该 Pod 资源记录;
- 集群视角:Pod 彻底消失,销毁流程完成。
🔄 补充关键分支场景 & 异常流转
🔄 1. Pod 重启流程
Pod 内单个容器异常退出,触发 restartPolicy 重启:
- 容器进程退出 → kubelet 检测到异常;
- 按照策略判断是否重启;
- 仅重建该异常容器,pause 沙箱、网络、命名空间、卷全部保留;
- 容器重新启动 → 执行 postStart → 探针恢复;
特点:Pod 对象本身不删除、IP 不变、网络不变。
💥 2. 节点宕机
- 节点失联 → apiserver 判定节点 NotReady;
- 默认 5 分钟 后,控制器认定节点不可恢复;
- 在其他健康节点重建全新 Pod(新 IP、新容器);
- 原节点恢复后,本地残留僵尸 Pod 被清理。
📉 3. 驱逐场景
节点出现 MemoryPressure/DiskPressure 等压力:
- kubelet 根据 QoS 优先级 驱逐 Pod(BestEffort > Burstable > Guaranteed);
- 驱逐流程 = 标准删除流程(preStop → SIGTERM → SIGKILL)。
⚙️ 核心配置参数详解
⏱️ terminationGracePeriodSeconds
spec:
terminationGracePeriodSeconds: 30 # 默认30秒
- 作用:优雅关闭最大等待时长;
- 建议:有状态应用(MySQL/Kafka)适当调大(60~120s)。
🔁 restartPolicy
spec:
restartPolicy: Always # 默认 Always
Always:容器任何退出都重启(业务应用默认)OnFailure:仅异常退出(非0码)重启(Job 任务)Never:永不重启(一次性任务)
🔗 生命周期钩子
containers:
- name: app
lifecycle:
postStart: # 启动后执行
exec:
command: ["/bin/sh", "-c", "xxx"]
preStop: # 停止前执行
exec:
command: ["/bin/sh", "-c", "xxx"]
💓 探针
startupProbe / livenessProbe / readinessProbe 直接决定容器是否重启、是否接入流量。
📊 流程状态对应表
| 流程阶段 | Pod 状态(Phase) | 常见原因 |
| 等待调度/拉镜像/Init容器执行 | Pending | 资源不足、镜像拉取失败、Init异常 |
| 容器全部启动并就绪 | Running | 正常运行 |
| 一次性任务全部正常退出 | Succeeded | Job 执行完成 |
| 容器异常退出、多次重启失败 | Failed | 程序崩溃、配置错误 |
| kubelet 失联,状态无法上报 | Unknown | 节点宕机、kubelet 挂掉 |
💡 高频面试考点总结
- 简述 Pod 从创建到删除全流程?
答核心链路:提交请求 → apiserver+etcd → 调度器选节点 → kubelet 拉镜像 → Init容器 → pause沙箱(网络/命名空间) → 主容器 + postStart + 探针 → Running → 删除触发 → 摘除Endpoint → preStop → SIGTERM优雅关闭 → 超时SIGKILL → 销毁资源 → etcd清理。 - pause 容器作用?什么时候创建?
答:创建在 Init 之后、主容器之前;负责共享网络、UTS、IPC 命名空间,作为 Pod 网络基座。 - preStop 与 terminationGracePeriodSeconds 关系?
preStop 执行时间计入优雅终止时长,超时会被强制 kill。 - SIGTERM 和 SIGKILL 区别?
SIGTERM 可被应用捕获,实现优雅退出;SIGKILL 系统强制杀死,无法拦截。 - 容器重启和 Pod 删除的区别?
容器重启:保留 pause、网络、IP、卷;Pod 删除:全部资源销毁,重建会换新IP。 - 为什么删除 Pod 不会立刻消失?
存在优雅终止宽限期,先摘流量、执行钩子、优雅关闭,再清理资源。
📈 极简流程图
创建
用户请求 → apiserver → etcd(Pending) → Scheduler选节点 → kubelet → 拉镜像 → Init容器(串行) → pause沙箱+CNI网络 → 主容器 → postStart → 探针 → Ready(Running)
销毁
删除请求 → apiserver 标记删除 → 摘除Endpoint → preStop钩子 → SIGTERM(优雅关闭) → 超时则SIGKILL → 销毁容器/网络/卷 → etcd清理 → Pod消失
关联文档
- K8s 探针机制 — Pod 探针
- K8s InitContainer — InitContainer
- K8s 资源限制与 QoS — 资源限制
- K8s 生命周期钩子 — 生命周期钩子