1. Pod是什么:K8S里最小的调度单元,到底小到什么程度
先回答一个很多刚接触Kubernetes的人都会问的问题:为什么K8S不直接管容器,非要中间加一层Pod?
我刚开始学K8S的时候也觉得Pod是个多余的抽象,容器跑得好好的,多包一层反而增加理解成本。但真正在生产环境里踩过几次坑之后就明白了,这一层抽象是K8S最核心的设计决策之一。
Pod是Kubernetes里最小的调度和部署单元,它不是一个进程,而是一个"容器运行环境"的集合。你可以把Pod理解成一个"逻辑主机"——这台上可以跑一个容器,也可以跑多个容器,这些容器共享这个主机的网络栈、存储卷和生命周期。
为什么需要这样一个中间层?最典型的场景是"边车模式"(Sidecar)。假设你有一个Web应用容器,你想给它加一个日志收集的Agent,如果让Agent单独跑在另一个Pod里,它就没法直接访问应用的本地日志文件;如果硬塞进同一个容器,又会造成进程管理混乱。放在同一个Pod里,两个容器共享文件系统和网络,Agent可以直接读应用的日志文件,通过localhost互相通信。这种设计在传统虚拟机时代是不需要额外抽象的,因为VM里天然可以跑多个进程,但容器是单进程模型,所以要由Pod这个上层概念来承担"进程组"的职责。
Pod的核心特性可以用三条来概括:共享网络命名空间(每个Pod有一个独立的IP,Pod内所有容器共用这个IP和端口空间)、共享存储卷(Pod内的容器可以挂载同一个Volume)、共享生命周期(Pod是一个整体,K8S只会整体调度、整体重启、整体删除)。
1.1 为什么K8S不直接调度容器
市面上的容器编排工具其实分两派:一派像Docker Compose,直接操作容器,简单但表达能力有限;另一派像K8S,通过Pod这一层抽象来间接管理容器,复杂但灵活。
关键原因在于,容器这个粒度在编排层面"太小了"。在生产环境里,很多应用不是单容器能搞定的,而是多个进程需要紧密协作。比如一个应用需要从本地Unix Socket读数据,或者需要共享内存做IPC通信,强制拆到不同Pod里就得引入Service Mesh、外部存储这些额外设施,代价太高。
另一个原因是容器本身不具备"原子调度"的能力。如果一个应用由A、B两个容器组成,它们必须调度到同一台机器上才能工作,那编排系统就必须把这两个容器当成一个整体来处理。Pod天然支持这种原子性——Pod内的所有容器一定调度到同一个Node上,不存在一个Pod里的两个容器被分配到不同机器的情况。
从资源管理的角度看也一样,Pod是资源配额(ResourceQuota)和资源限制(LimitRange)的最小单位。你在创建Pod时声明的CPU、内存请求,是加总这个Pod里所有容器的声明值。如果去掉Pod这一层,资源管理就只能到容器粒度,调度器的决策空间就会被严重压缩。
1.2 一个Pod里到底能装什么
很多新手对"一个Pod里放几个容器"这个问题特别困惑,我来给一个明确的标准。
最常规的情况是一个Pod一个容器,这也是绝大多数应用的标准姿势。这个"单容器Pod"其实是K8S中最常见的Pod形态,Deployment默认创建的就是这种。
什么时候需要多容器共享一个Pod?我总结了三类典型场景:
- Sidecar模式:主容器负责核心业务,辅助容器负责日志收集、流量代理、配置同步等辅助功能。最经典的例子是Istio的Envoy代理,它会自动注入到每个业务Pod里,和业务容器共享网络。
- Ambassador模式:辅助容器充当主容器的代理,把外部不同的后端服务统一暴露成localhost接口给主容器访问。
- Adapter模式:辅助容器把主容器产生的数据进行格式转换,比如把应用日志转换成统一标准格式再交给下游系统。
但我要提醒一点:多容器Pod不要滥用。两个容器必须满足"要么一起生、要么一起死"的耦合关系,才有必要放进同一个Pod。如果只是互相依赖的服务,用Service去解耦是更合理的方案。我见过有人把数据库和应用放在同一个Pod里的操作,这种设计在Pod重启时数据库也会跟着重启,简直是自己给自己挖坑。
1.3 静态Pod:一种容易被忽略的Pod形态
除了通过API Server创建的普通Pod,K8S还有一种特殊形态叫静态Pod(Static Pod)。静态Pod由kubelet直接管理,不经过API Server和调度器,YAML文件放在节点的特定目录下(默认是/etc/kubernetes/manifests)。
静态Pod最大的特点是"自愈依赖本机"。kubelet会持续监控这个目录,文件变化时创建或删除Pod,Pod崩溃时kubelet直接在当前节点重新拉起。因为不走调度器,它永远只会在本机运行。
你可能好奇这东西有什么用。最著名的用途是部署K8S控制平面组件——apiserver、etcd、controller-manager、scheduler在kubeadm搭建的集群里全都是静态Pod。我自己排查过几次控制平面异常,基本都是直接去/etc/kubernetes/manifests下改配置然后等kubelet自动重建。
明白了Pod是什么,下一步要搞清楚的就是它的生命周期。这个问题不搞透,后面排查故障的时候会非常痛苦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Pod生命周期与状态流转:从Pending到Running再到Failed
Pod的生命周期管理是K8S里最核心的机制之一,也是排查问题时的第一道关卡。我在实际工作中几乎每天都要通过看Pod状态来快速判断问题方向。
2.1 六种状态与阶段流转
首先要把Pod状态(Status)和容器状态区分开。Pod层面有五个阶段(Phase),每个阶段代表Pod的生命周期位置:
- Pending:Pod已被API Server接受,但还没有完成调度或者镜像还没拉取完
- Running:Pod至少有一个容器在运行中,或者正在启动/重启
- Succeeded:所有容器都正常退出,退出码为0,且不会重启
- Failed:至少有一个容器异常退出,退出码非0
- Unknown:API Server无法获取Pod状态,通常意味着节点失联或kubelet挂了
一个正常Pod的流转路径是Pending → Running → Succeeded(对于一次性任务)或者长期保持Running。异常路径则是卡在Pending(调度失败)或者在Running之后反复重启(CrashLoopBackOff)。
这里有个容易误解的点:Running状态不等于Pod健康。Running只代表容器进程在跑,进程内部是否正常工作、是否能够响应请求,K8S根本不关心。要验证应用真的可用,必须靠后面的探针(Probe)机制。
2.2 容器状态:Waiting、Running、Terminated
Pod状态是宏观视角,容器状态才是微观视角。我们用kubectl get pod看到的STATUS那一列,其实综合了Pod阶段和容器状态。深入看容器本身,只有三种状态:
- Waiting:容器还没开始运行,可能是在拉镜像、在等配置、或者在等卷挂载
- Running:容器正在执行
- Terminated:容器曾执行过,但现在已经退出
排查问题时的关键技巧是看Reason字段。Waiting状态最常见的Reason是ImagePullBackOff(拉镜像失败)、ContainerCreating(容器创建中)、CreateContainerConfigError(配置错误)。Terminated状态要重点看Exit Code,0代表正常退出,137代表被kill(通常是内存超限被OOM Killer干掉),1或2通常是应用自身报错。
2.3 为什么Pod一直Pending?排查思路
Pod卡在Pending是新手最常遇到
