Kubernetes

K8s Pod 详解

·24 分钟阅读·9267 字

Pod 核心概念、Pause 沙箱、生命周期阶段、创建到销毁完整流程、重启策略、探针

📋 目录

📦 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),作用:

  1. 创建共享网络栈:所有业务容器加入 pause 的 network namespace,共享同一个 IP、端口空间
  2. 共享生命周期:pause 不退出,Pod 不销毁
  3. 简化网络/存储绑定:kubelet 只需要管理 pause,再把业务容器“挂靠”进来

网络流程:

  • Pod IP → pause 网卡 → 所有容器共享 localhost
  • 容器间通信:直接 localhost:port,无需 NAT

📊 Phase(五大阶段)

  • Pending:已创建未调度 / 调度中 / 拉镜像
  • Running:调度成功,至少一个容器启动
  • Succeeded:所有容器正常退出(Job 完成)
  • Failed:至少一个容器异常退出
  • Unknown:kubelet 失联,状态未知

🔄 详细流程(从创建到销毁)

  1. 创建 Pod 对象(API Server → etcd)
  2. 调度:Scheduler 选节点 → 绑定 NodeName
  3. 拉镜像:kubelet → 容器运行时(containerd)
  4. 启动 InitContainer(串行,必须全成功)
  5. 启动 Pause 容器(创建网络/存储)
  6. 启动主容器
  7. 执行 postStart Hook
  8. 健康检查:liveness/readiness/startup
  9. 运行
  10. 删除/驱逐
  • 执行 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 被杀优先级)

  1. Guaranteed:requests = limits → 最后被 OOM 杀
  2. Burstable:requests < limits → 中间优先级
  3. 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 logskubectl describedmesg 看 OOM

📥 ImagePullBackOff

  • 原因:镜像名错、私有仓库权限、网络不通、镜像不存在
  • 排查:镜像地址、Secret、节点网络

❌ Running 但无法访问

  • 原因:探针失败、端口错误、网络策略拦截、路由异常
  • 排查:kubectl get epcalicoctl get networkpolicyiptables -L

  1. 一个 Pod 一个主容器,辅助容器用 Sidecar(日志、监控)
  2. 必须配资源限制:避免节点资源耗尽
  3. 同时配 liveness + readiness:启动不丢流量、异常自动恢复
  4. 用 InitContainer 做前置依赖,避免主容器逻辑复杂化
  5. 重要业务用 Guaranteed QoS,保障稳定性
  6. 优雅停机:preStop + 合理宽限期,避免数据丢失

如果你愿意,我可以把以上内容整理成一份 可直接打印的 Pod 深度详解文档(含 YAML 示例+面试题),你直接复制就能用。需要我整理吗?



结合 K8s 组件调用链路、内核容器技术、生命周期、钩子、探针、终止逻辑、源码级流转,分两大阶段:创建流程销毁流程,附带关键组件、配置、异常场景、面试考点,适配运维/SRE 学习与面试。

前置说明:
集群组件:kube-apiserveretcdkube-schedulerkubelet、容器运行时(containerd/runc)、CNI 网络插件
默认容器运行时:containerd + runc;Pod 包含 pause 沙箱容器 + 业务容器/Init 容器


📋 生命周期总阶段

创建 → 调度 → 拉取镜像 → 初始化容器(InitContainer) → 启动沙箱(pause) → 启动主容器 → 运行&健康检查 → 接收删除指令 → 优雅终止 → 强制销毁

👥 核心角色分工

  1. apiserver:集群唯一入口,接收请求、鉴权、数据写入 etcd
  2. etcd:集群状态持久化存储,保存所有资源对象
  3. scheduler:调度器,为未绑定节点的 Pod 筛选最优节点
  4. kubelet:节点代理,本节点所有 Pod 生命周期实际执行者
  5. CRI(containerd):容器运行时,创建/启动/停止容器、管理镜像
  6. CNI:网络插件,配置 Pod 网卡、IP、路由

📋 Pod 完整创建流程

步骤1:提交 Pod 资源请求(用户/控制器发起)

  1. 用户通过 kubectl apply、YAML、UI、API 等方式提交 Pod 配置
  2. 请求发送至 kube-apiserver
  3. apiserver 执行:认证 → 授权 → 准入控制器(校验规则、资源策略、安全策略);
  4. 校验通过后,将 Pod 资源数据序列化写入 etcd
  5. etcd 完成持久化,返回成功;此时集群中已存在该 Pod 对象,状态为 Pending

关键点:此时 Pod 还未被调度、节点上无任何容器。

步骤2:调度器筛选节点(Scheduler 工作流程)

  1. kube-scheduler 持续监听 apiserver,发现 未绑定 NodeName 的 Pod
  2. 执行标准调度二阶段:
  • 预选(Predicate):过滤不符合条件的节点
    校验:资源是否充足、节点污点、Pod 亲和/反亲和、节点标签、端口占用等;不满足直接剔除。
  • 优选(Priority):对剩余节点打分,选出最优节点
  1. 调度器将 NodeName 写入 Pod 定义,再次提交 apiserver;
  2. apiserver 更新 etcd 中 Pod 的节点绑定信息;
  3. Pod 状态仍为 Pending,但已确定运行节点。

步骤3:目标节点 kubelet 感知 Pod 变更

  1. 每个节点的 kubelet 通过 Watch 机制 监听 apiserver;
  2. kubelet 发现:本机需要新增一个 Pod;
  3. kubelet 开始执行本地创建逻辑,正式接管该 Pod 全生命周期

步骤4:前置校验 & 镜像拉取

  1. kubelet 校验 Pod 配置:权限、卷、资源配额、安全上下文等;
  2. 调用 CRI 容器运行时(containerd)
  • 检查本地是否存在对应镜像;
  • 本地无镜像 → 按照镜像地址 + Secret 配置,从镜像仓库拉取镜像
  • 镜像拉取失败 → Pod 状态变为 ImagePullBackOff / ErrImagePull

步骤5:创建并启动 Init 初始化容器(串行执行)

InitContainer 是前置一次性任务,必须全部成功,才会启动主容器。

  1. kubelet 按 YAML 定义,串行逐个创建 Init 容器
  2. 为 Init 容器配置:卷挂载、安全上下文、资源限制、命名空间;
  3. 启动 Init 容器,执行内部脚本/程序;
  4. 单个 Init 容器正常退出(退出码0),才会执行下一个;
  5. 若 Init 容器异常退出:
  • 根据 Pod restartPolicy 决定是否重启 Init 容器;
  • 反复失败 → Pod 进入 CrashLoopBackOff
  1. 所有 Init 容器全部执行成功并退出,进入下一阶段。

步骤6:创建 Pause 沙箱容器(Pod 网络/命名空间核心)

这是 Pod 最关键的底层步骤,同 Pod 所有容器共享的命名空间由此创建。

  1. kubelet 调用 containerd 创建 pause 容器(沙箱)
  2. runc 基于 Linux 内核创建一组命名空间:
  • 共享:NET、UTS、IPC、Mount
  • 独立:PID(默认)
  1. 调用 CNI 网络插件
  • 创建虚拟网卡 veth pair、分配 Pod IP;
  • 配置路由、DNS、防火墙、网络策略;
  1. pause 容器启动并常驻,作为整个 Pod 的网络/命名空间基座
    只要 pause 不退出,Pod 网络栈就不会销毁。

步骤7:启动主业务容器

  1. 基于 pause 已创建的命名空间,逐个启动 Pod 内主容器
  2. 挂载 Volume、ConfigMap、Secret、hostPath 等存储;
  3. 应用容器进程启动;
  4. 容器启动瞬间,执行 postStart 生命周期钩子
  • 钩子执行失败:根据重启策略重启容器;
  • 钩子执行不阻塞容器主进程运行。

步骤8:启动健康探针(Probe)

容器启动完成后,kubelet 按照配置时序开启三类探针检测:

  1. startupProbe 启动探针(优先执行):针对慢启动应用,启动阶段独占检测;
    失败 → 重启容器。
  2. livenessProbe 存活探针:持续检测容器是否卡死、无响应;
    连续失败 → 判定容器异常,重启容器
  3. readinessProbe 就绪探针:检测应用是否可对外提供服务;
  • 检测成功:Pod 状态变为 Ready,Endpoint 控制器将此 Pod 加入 Service 后端,开始接收流量
  • 检测失败:Pod 标记为未就绪,Service 不再转发流量。

步骤9:Pod 进入正常 Running 运行状态

  1. 所有容器启动完成、就绪探针通过;
  2. etcd 中 Pod 状态更新为 Running
  3. kubelet 持续循环:监控容器状态 + 执行探针检测
  4. 业务正常对外提供服务,创建流程结束。

🗑️ Pod 完整销毁流程

Pod 销毁分为两类场景:手动删除节点驱逐/资源压力驱逐,底层流程完全一致。

  • 核心参数:terminationGracePeriodSeconds(优雅终止宽限期,默认 30s
  • 终止信号:SIGTERM(15) 优雅关闭 → 超时后 SIGKILL(9) 强制杀死

步骤1:发起删除请求

  1. 执行命令 kubectl delete pod <pod-name> / 控制器缩容 / 节点驱逐;
  2. 请求发送至 apiserver,鉴权校验后,标记 Pod 为删除状态,并添加 deletionTimestamp 时间戳;
  3. apiserver 不会立刻删除 etcd 数据,进入优雅终止倒计时

步骤2:kubelet 感知删除事件,开始终止流程

  1. 节点 kubelet 通过 Watch 发现 Pod 标记删除;
  2. 立刻执行第一步:将 Pod 从 Service Endpoints 中摘除

作用:不再向该 Pod 转发新流量,避免请求丢失。

步骤3:执行 preStop 生命周期钩子(优雅停机核心)

  1. kubelet 触发容器的 preStop 钩子;
  2. 执行提前定义的脚本/命令:关闭连接、刷盘、注销服务、保存临时数据等;
  3. preStop 执行期间会计入优雅宽限期

步骤4:发送 SIGTERM 信号(优雅关闭)

  1. preStop 执行完成(或无 preStop),kubelet 向每个主容器 PID=1 进程发送 SIGTERM 信号;
  2. 应用程序收到信号后,执行内部优雅逻辑:
  • 停止接收新请求
  • 处理完存量连接
  • 释放资源、关闭线程、正常退出
  1. 此阶段仍在 terminationGracePeriodSeconds 倒计时内。

步骤5:宽限期超时判断 & 强制杀死

分两种情况:

情况A:容器在宽限期内正常退出

  1. 所有业务容器主动退出;
  2. kubelet 继续停止 pause 沙箱容器;
  3. 销毁网络命名空间、网卡、路由、挂载卷;

情况B:容器卡住、无法正常退出(超时)

  1. 超过 terminationGracePeriodSeconds 设定时间;
  2. kubelet 直接发送 SIGKILL(9) 强制杀死 所有容器进程(不可被应用捕获,强行终止);
  3. 强制销毁容器、网络、挂载资源。

步骤6:资源回收 & 数据清理

  1. 销毁 Pod 对应的所有容器、网络栈、虚拟网卡;
  2. 临时卷 emptyDir 数据全部删除
  3. 持久化卷(PVC/hostPath)根据回收策略保留数据。

步骤7:etcd 最终清理,Pod 完全消失

  1. 节点 kubelet 确认本地 Pod 资源全部销毁;
  2. 通知 apiserver 彻底删除 etcd 中该 Pod 资源记录;
  3. 集群视角:Pod 彻底消失,销毁流程完成。

🔄 补充关键分支场景 & 异常流转

🔄 1. Pod 重启流程

Pod 内单个容器异常退出,触发 restartPolicy 重启:

  1. 容器进程退出 → kubelet 检测到异常;
  2. 按照策略判断是否重启;
  3. 重建该异常容器pause 沙箱、网络、命名空间、卷全部保留
  4. 容器重新启动 → 执行 postStart → 探针恢复;

特点:Pod 对象本身不删除、IP 不变、网络不变。

💥 2. 节点宕机

  1. 节点失联 → apiserver 判定节点 NotReady;
  2. 默认 5 分钟 后,控制器认定节点不可恢复;
  3. 在其他健康节点重建全新 Pod(新 IP、新容器);
  4. 原节点恢复后,本地残留僵尸 Pod 被清理。

📉 3. 驱逐场景

节点出现 MemoryPressure/DiskPressure 等压力:

  1. kubelet 根据 QoS 优先级 驱逐 Pod(BestEffort > Burstable > Guaranteed);
  2. 驱逐流程 = 标准删除流程(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正常运行
一次性任务全部正常退出SucceededJob 执行完成
容器异常退出、多次重启失败Failed程序崩溃、配置错误
kubelet 失联,状态无法上报Unknown节点宕机、kubelet 挂掉

💡 高频面试考点总结

  1. 简述 Pod 从创建到删除全流程?
    答核心链路:提交请求 → apiserver+etcd → 调度器选节点 → kubelet 拉镜像 → Init容器 → pause沙箱(网络/命名空间) → 主容器 + postStart + 探针 → Running → 删除触发 → 摘除Endpoint → preStop → SIGTERM优雅关闭 → 超时SIGKILL → 销毁资源 → etcd清理。
  2. pause 容器作用?什么时候创建?
    答:创建在 Init 之后、主容器之前;负责共享网络、UTS、IPC 命名空间,作为 Pod 网络基座。
  3. preStop 与 terminationGracePeriodSeconds 关系?
    preStop 执行时间计入优雅终止时长,超时会被强制 kill。
  4. SIGTERM 和 SIGKILL 区别?
    SIGTERM 可被应用捕获,实现优雅退出;SIGKILL 系统强制杀死,无法拦截。
  5. 容器重启和 Pod 删除的区别?
    容器重启:保留 pause、网络、IP、卷;Pod 删除:全部资源销毁,重建会换新IP。
  6. 为什么删除 Pod 不会立刻消失?
    存在优雅终止宽限期,先摘流量、执行钩子、优雅关闭,再清理资源。

📈 极简流程图

创建
用户请求 → apiserver → etcd(Pending) → Scheduler选节点 → kubelet → 拉镜像 → Init容器(串行) → pause沙箱+CNI网络 → 主容器 → postStart → 探针 → Ready(Running)

销毁
删除请求 → apiserver 标记删除 → 摘除Endpoint → preStop钩子 → SIGTERM(优雅关闭) → 超时则SIGKILL → 销毁容器/网络/卷 → etcd清理 → Pod消失


关联文档