资讯动态

Kubernetes Deployment排障指南:一张可视化地图搞定五大高频故障

发布时间:2026/10/22 3:20:15 来源:尧图企业网站定制
凌晨两点手机告警把我从床上拽了起来。交易服务的新版本刚发布Pod副本卡在ContainerCreating页面开始报5xx。打开电脑后的第一件事不是疯狂敲describe而是把终端分成三块左边看kubectl get deployment中间看按时间排序的Events右边准备抓日志。这不是什么天赋而是2021年一整年在Kubernetes里摔打之后整理出来的排障方法——把Kubernetes Deployment故障排除这件乱麻一样的事做成了一张能一眼看清的可视化地图。这份指南不是某个版本的一次性笔记。我会把Deployment排障期间最常见的五类故障、每类故障完整的排查链路以及怎么把分散的命令输出组织成可视化地图都写清楚。适合刚接手Kubernetes的运维和开发者也适合已经有排障经验、想沉淀一套团队方法的人。虽然最初的坑都踩在2021年但到了今天这些排障逻辑依然没有过时。1. 先把“排障可视化”这件事想清楚1.1 排障低效从来不是因为命令不够多Deployment出问题时大多数人的第一反应是打开终端疯狂敲命令。kubectl describe pod、kubectl logs、kubectl rollout status挨个试方向全靠直觉。我也经历过这个阶段当时每次发布出问题都是一身汗。后来复盘才发现命令本身不难难的是信息怎么串起来。我见过有人卡在一个CrashLoopBackOff上整整两小时反复翻最后几行应用日志始终不得其解。真正的原因是Liveness探针的路径写错了容器本身是健康的但探针不停把容器杀掉应用日志里根本看不到探针的报错报错只出现在Event里。另一次是Pending问题有人抱着Pod日志啃了半天而调度失败的根因只存在于FailedScheduling事件中——Pod压根没起来又哪里来的容器日志。所以问题的本质不是命令不够多而是大多数人的信息获取是点状的。看到一条异常就扑上去查一个对象被表象带跑脑子里始终没有一张完整的地图。1.2 一张可复用的Deployment排障地图三条信息轴我把整个排查过程抽象成一个可视化框架核心是三条信息轴。第一条轴是期望状态来自你声明的Deployment配置replicas是多少、镜像tag是什么、有没有配探针、滚动策略长什么样。第二条轴是实际状态来自集群的实时信息READY列的数字、Pod的phase、容器的restartCount、节点的可用资源。第三条轴是事件流来自kubelet、调度器、Deployment控制器持续写入的事件记录它们描述系统每一层到底发生了什么。排障过程就是把这三条轴对齐到同一个画面上按时间线去读。容器日志只是实际状态轴里的一环探针问题要看期望状态轴里的配置调度失败要读事件流轴镜像拉取失败同时涉及期望状态镜像地址和事件流具体报错。这套三维坐标系用顺了再接到Deployment相关告警心里就不会慌。我后面所有章节都围绕这三轴展开第2章讲怎么读期望状态和实际状态第3章讲五大高频故障在不同轴上的表现第4章专门讲怎么把事件流做成时间线第5章给一个完整的案例复盘。2. 先读Deployment的状态字段再决定要不要慌2.1 一条kubectl命令背后的四个数字接到告警后我的第一步永远是kubectl get deployment。这条命令输出只有几列但信息密度很高kubectl get deployment -n trading NAME READY UP-TO-DATE AVAILABLE AGE trading 0/3 3/3 0/3 42m四个数字各有含义。READY表示当前有几个副本处于可用状态通过Readiness探针UP-TO-DATE表示有没有把副本更新到最新声明的版本AVAILABLE表示有多少副本真正在对外提供服务。三者组合能直接判断故障发生在滚动更新的哪个阶段。举个例子如果是发布刚触发十几秒看到READY 2/3、UP-TO-DATE 1/3这是滚动更新正常推进新Pod正在启动不用慌。但如果发布已经过去五分钟READY还是2/3、UP-TO-DATE 3/3说明新版本Pod已经创建出来却起不来大概率是探针没过或者应用启动崩溃。AGE列则能帮你判断Deployment是刚创建还是一直在跑、最近才开始出问题。2.2 用状态机理解发布过程Deployment → ReplicaSet → PodKubernetes里Deployment不是直接管Pod的它下面还有一层ReplicaSet负责维护副本数量。更新镜像时Deployment会创建一个新ReplicaSet把新Pod拉起来再把旧ReplicaSet缩容这就是滚动更新的本质。理解这层关系对排障特别重要。kubectl get rs的输出我强烈建议经常看因为ReplicaSet的名字就是Pod名的前缀。比如Pod叫trading-7df4b9c8d9-8kf2m7df4b9c8d9就是它所属ReplicaSet的模板哈希。发布时新旧两个ReplicaSet同时存在新的DESIRED逐渐变大旧的DESIRED逐渐变小。如果新的ReplicaSet一直卡在DESIRED0说明发布压根没开始如果DESIRED满了但READY上不去问题就出在Pod层。发布推进可以理解成一个状态机Deployment控制器先在新的ReplicaSet上创建PodPod经过Pending、ContainerCreating、Running再通过Readiness探针进入ReadyDeployment才会把流量切过去同时缩容旧ReplicaSet。任何一步卡住状态机就停在原地事件流里一定会有对应的报错。2.3 状态组合判读表五秒定位故障层级为了快速缩小范围我自己整理过一张状态组合表实测非常省力READYUP-TO-DATEAVAILABLE最可能的情况下一步动作0/30/30/3Deployment刚创建或控制器还没开始工作describe Deployment查Conditions2/31/32/3滚动更新进行中属正常过渡等几秒再get一次1/33/31/3新Pod创建了但大部分不健康查新Pod的Events和日志3/33/32/3有旧Pod正在终止或就绪状态异常查旧ReplicaSet的终止状态0/33/30/3新版本整体故障准备回滚先查新ReplicaSet失败原因3/33/33/3一切正常不需要排障这张表的价值不在于覆盖所有情况而在于把“我该看哪里”的决策时间从十分钟压缩到十秒。后面遇到具体故障形态再从对应层级往下钻。3. 五大高频故障的排查链路与可视化判读3.1 镜像拉取失败ImagePullBackOff的前世今生现象新发布后Pod卡在ContainerCreating最后变成ImagePullBackOff。describe Pod的Events里能看到Events: Type Reason Age Message ---- ------ ---- ------- Normal Scheduled 45m Successfully assigned ... Normal Pulling 45m Pulling image registry.example.com/trading/app:v2.0.1 Warning Failed 45m Failed to pull image ... authentication required Warning BackOff 45m Back-off pulling image ...我的经验是镜像拉取失败的事件消息已经非常直白直接把人指向答案。常见的几种事件消息特征根因方向manifest unknown / not found镜像不存在或tag写错authentication required认证信息缺失或过期EOF / connection refused / timeout仓库网络不通或仓库不可达排查步骤上也别乱先看事件消息确认方向再检查Pod所属的ServiceAccount有没有关联imagePullSecrets。这是2021年最容易被忽略的坑——很多人把Secret建好了但没挂到ServiceAccount上Pod拉私有仓镜像时拿不到认证。最后可以手动到节点上验证镜像容器运行时是containerd时用crictl pull registry.example.com/trading/app:v2.0.1能在节点层面复现问题排除Kubernetes配置因素的干扰。注意ErrImagePull是第一次拉取失败ImagePullBackOff是kubelet开始按退避算法重试。看到ImagePullBackOff意味着问题不是偶发抖动而是持续性的别指望等一等就好。3.2 CrashLoopBackOff容器崩溃循环的三种死法CrashLoopBackOff是Deployment场景里最让人焦虑的报错之一现象直观根因却五花八门。我的经验是先看退出码再看日志顺序别反。退出码是容器运行时的第一线索退出码通常含义137被SIGKILL杀掉最常见是OOMKilled资源limit太小143收到SIGTERM后没等优化雅退出就被强杀一般是关闭逻辑有问题1 或 2应用自身启动失败配置文件错误、端口占用、依赖缺失126 / 127容器里的命令不存在或权限不够确定退出码方向后再配合两条命令。kubectl logs -c --previous能看上一个容器实例退出前的日志kubectl describe pod里的Events能直接看到Killing原因比如OOMKilled会直接出现在Events里。CrashLoop还有一种非常迷惑人的情况应用启动要十几秒但Liveness探针的initialDelaySeconds只设了5秒探针第一次检查就失败容器被杀。这种场景下应用日志里其实没有任何异常但Events会反复出现Killing顺着探针配置的线索就能摸到原因。3.3 Pending调度失败的根因藏在FailedScheduling事件里Pod卡在Pending时别急着看日志——Pod还没被调度到节点上根本没有容器日志。正确的入口是describe Pod的Events重点找FailedScheduling。常见的调度失败原因有几种Insufficient cpu/memory说明节点资源不足用kubectl top nodes和kubectl describe node查看AllocatablenodeSelector或nodeAffinity不匹配说明节点标签和Pod要求对不上节点有Taint且Pod没有对应Toleration也是最容易误判的一种。事件消息里通常写得比较直接比如0/3 nodes are available: 3 Insufficient memory前面的数字是节点总数后面是失败原因明细。还要注意一个容易和Pending混合的情况pod has unbound immediate PersistentVolumeClaims。PVC没有绑定成功时Pod也可能卡在ContainerCreating而不是Pending但两者背后的逻辑都是“底层依赖没就绪”。Pending这个状态是非常适合可视化的把节点列表和Pod的调度要求放一起看节点资源、标签、污点这三列信息基本能覆盖90%的调度问题。3.4 探针失败Pod看着Running流量却死活进不来探针故障最坑的地方在于欺骗性kubectl get pod看到的状态是Running第一反应是“容器没崩应该没事”。但往下看READY列可能写着0/1——容器的Readiness探针从来没通过Pod永远不会被加入Service的Endpoint。常见的探针问题有几种httpGet的路径写错探针打到404或500端口号漏写或写错initialDelaySeconds太短容器还在初始化就急着探测timeoutSeconds太短接口处理慢一点就被判失败探针访问的接口需要鉴权探针请求直接返回401。排查方法很直接describe Pod看Events里的Unhealthy条目会明确指出是liveness还是readiness失败附带失败状态码。如果Readiness探针失败但应用日志看着正常多半是探针参数或路径问题而不是应用逻辑问题。Startup探针是为慢启动应用准备的如果你的应用启动就要一两分钟别把希望寄托在把Liveness的initialDelaySeconds调大上直接用startupProbe更靠谱。3.5 发布进度卡死ReplicaSet新旧交替的暗坑最后一种高频故障是Deployment的Conditions里Progressing变成FalseReason是ProgressDeadlineExceeded事件里写着某个ReplicaSet has not progressed。意思是控制器在规定时间内默认600秒没看到新版本推进成功直接放弃等待。最常见的元凶是滚动策略配置得太严苛。maxSurge和maxUnavailable是控制滚动速度的两个旋钮如果两个都设成0就意味着“一个都不许多一个都不能少”滚动更新直接死锁新Pod起不来因为没有可用的空余额度旧Pod也不能缩因为不允许临时减少。有些配置模板把maxSurge设成0又没给maxUnavailable留余量发布必卡。另一个原因是新版本探针一直不通过progressDeadlineSeconds到了直接标记失败。这种情况kubectl rollout status会一直卡在等待describe Deployment能看到ProgressingFalse。处理方式通常是先kubectl rollout undo回滚再把滚动策略改成更合理的值比如maxUnavailable0、maxSurge1先多起一个新的实例再逐步替换旧的保证发布过程中始终有旧版本在处理流量。4. 可视化排障的实操抓手事件时间线与资源拓扑4.1 把Events按时间排成一条线很多人排障时describe Pod看完Events里最后几条就关掉了。其实Events的参考价值很大但前提是排序。kubectl get events --sort-by.lastTimestamp能把事件按发生时间排好。以镜像拉取失败的场景为例排序前事件是一堆乱码排序后你能看到完整的因果链先Scheduled成功然后SuccessfulCreate接着Failed to pull image再是BackOff、BackOff……事件的先后顺序直接告诉你在哪个环节开始出岔子。想只看某个Pod的事件加--field-selector involvedObject.namePod名。事件里还有一个COUNT列count一直在涨说明事件在反复发生比如CrashLoopBackOff场景里Killing、Pulled、Pulled、Killing反复出现说明容器在持续被杀重建。提示Events是有时效的默认只保留一小时左右。收到告警后第一时间把events全量导出保存哪怕当时没时间分析后面复盘也用得上。4.2 手工画一棵资源树信息立刻清晰Kubernetes对象之间的层级关系用一棵树就能画得明明白白Deployment trading └── ReplicaSet trading-7df4b9c8d9 ├── Pod trading-7df4b9c8d9-8kf2m └── Pod trading-7df4b9c8d9-h4j2n这棵树不是画着好看它提示了排查路径Deployment层面看要几个副本ReplicaSet层面看是哪个版本在扛Pod层面看具体容器的状态。遇到发布卡住时kubectl get rs -n 看新旧两个ReplicaSet各自的DESIRED和READY能直接判断是新的起不来还是旧的退不下。想省手动标注的功夫可以装kubectl-tree插件一条命令把Pod的子资源也展开比如PVC、Secret。有图形界面的工具当然更好但哪怕在纸上把这棵树画出来排障思路也会清晰很多。4.3 我实测过的几款可视化工具选型既然标题带“可视化”工具部分必须展开。2021年我试过几款各有侧重点工具可视化形式适合场景注意点K9s终端实时UI个人日常排障首选数字键切资源看日志、事件方便Kubernetes Dashboard网页图形界面不常敲命令的人应急集群大了页面容易卡kubectl-tree终端资源树快速看对象间层级关系需要krew插件安装kubectl-debug临时调试容器网络和DNS疑难杂症进Pod网络命名空间诊断选型建议单人排障用终端流K9s是效率最高的团队要统一复盘时Dashboard的截图比终端输出更适合贴文档。工具本身不是目的能把故障前后因后果讲清楚才是目的。5. 一个真实的发布故障复盘从ContainerCreating到流量恢复5.1 现象快照0/3副本卡在ContainerCreating场景是内部业务集群里某个交易服务发新版本v2.0.1发布流水线显示成功但页面开始出现大量5xx。我先按惯例拍了一张状态快照kubectl get deployment -n trading NAME READY UP-TO-DATE AVAILABLE AGE trading 0/3 3/3 0/3 42mUP-TO-DATE已经是3/3说明Deployment控制器已经把副本都更新到新版本但READY 0/3意味着没有一个Pod真正可用。再kubectl get pods -n trading看到两个Pod处于ImagePullBackOff还有一个仍在ContainerCreating。这个组合立刻指向两个可能要么镜像拉不下来要么存储卷挂载不上。于是顺着事件时间线继续往下查。5.2 顺着事件时间线摸到根因认证信息失效describe其中一个PodEvents里出现的关键信息是Warning Failed 45m Failed to pull image registry.example.com/trading/app:v2.0.1 ... rpc error: code Unknown desc authentication requiredauthentication required非常明显的认证报错。第一反应检查Secret。kubectl get secrets -n trading发现有一个叫regcred的Secret是存在的。但继续看kubectl get sa default -n trading -o yaml发现这个ServiceAccount里根本没有imagePullSecrets。也就是说Pod在拉私有仓库镜像时没有带任何认证信息自然一直报authentication required。这里有一个很典型的坑很多发布流水线建Secret很积极但把Secret关联到ServiceAccount这一步经常漏。部署模板默认只创建Secret本身忘了它必须被Pod通过ServiceAccount间接引用。5.3 修复步骤与验证结果把Secret关联到默认ServiceAccount一行patch就能解决kubectl patch serviceaccount default -n trading -p {imagePullSecrets:[{name:regcred}]}然后删除旧Pod让Deployment重建kubectl delete pod -n trading -l apptrading一两分钟后新Pod的Events开始出现Pulled成功Pod进入RunningREADY逐步变成1/1、2/3、3/3。页面5xx消失。最终输出kubectl get deployment -n trading NAME READY UP-TO-DATE AVAILABLE AGE trading 3/3 3/3 3/3 68m5.4 故障复盘问题在发布流水线不在Kubernetes复盘会上大家发现根因不只是Secret没关联。镜像仓库升级过认证方式旧Secret里的凭据早已过期但发布流水线在发布前没有任何校验步骤。后来我们在流水线里加了一道检查发布前自动校验关联镜像仓库的认证信息并设置Secret过期提醒。还把这套状态快照和事件时间线的记录模板放进了团队文档。从那以后同样的问题再没偷袭成功过。6. 把排障经验沉淀成团队的可视化资产6.1 日常巡检的可视化清单这次故障后我给自己定了每天下午几分钟的巡检就三行命令kubectl get deploy -A kubectl get pods -A | grep -Ev Running|Completed kubectl get events -A --sort-by.lastTimestamp | head -50不用搞得多复杂重要的是“状态矩阵”意识把所有命名空间的Deployment状态当成一张表异常行自然会成为视觉焦点。很多大事故在爆发前其实就藏在那张表里的一两个1/3里。6.2 排障记录模板每次故障都是一次资产积累我常用的排障记录模板长这样时间命名空间现象快照事件摘要根因修复动作预防措施2021-xx-xxtradingREADY 0/3authentication requiredSecret未关联SApatch SA关联regcred流水线加认证校验每次排完障花十分钟填完这张表半年后它就是团队里最值钱的文档。新人来了直接翻历史故障上手速度比任何培训都快。一张结构化的表格其实就是一种可视化——把一段经历压缩成一行关键信息再看的人毫无压力。6.3 团队协作里最值得留意的一件事最后说一件很不技术但影响深远的事Kubernetes排障最怕口头传话。有人看Pod有问题截图发到群里说“新Pod一直在ImagePullBackOff”后面的人再传“应该是网络问题”再往后的人听了开始查网络——信息经过层层加工后不断失真。Kubernetes排障最有效的协作方式是把第一手命令输出原样贴出来用状态快照代替口头描述。我给团队定的规矩是故障群里只允许贴原始命令输出和事件时间线不允许只发一句“Pod好像有问题”。可视化不是花哨的图表是一切信息都以可复现的形态呈现。到现在我接到Deployment相关告警的第一反应依然是先把kubectl get、events、logs三类输出按时间线摆好。看起来多花了半分钟但省下的是反复试错的两小时。如果你也是每天跟Deployment打交道的人建议也养一个自己的排障习惯先拍照再动手。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑