Skip to content

第14章 高频故障场景案例集 ​

对应简历:贯穿全部技能与项目——工作职责「负责平台上线后的运维支持,与华为原厂协同处理日常巡检、告警、版本升级与疑难故障」「制定集群证书续期、etcd 快照备份、故障切换演练等运维规范,保障业务 7×24 小时稳定运行」/ 项目二职责「沉淀海外镜像拉取失败、RBAC 字段不可变等 9 项生产避坑清单」

用法:每个案例按"场景 → 排查(命令+讲解)→ 根因 → 解决 → 预防 → 面试讲法(完整 STAR)"六段背。来源标注:【真实项目】= 我在生产亲手处理/验证;【课程项目】= 课程实验 + 理解口径;【经典故障】= 话术库/经典故障库的标准案例,讲的时候用"我处理过类似的"口径。术语:Kubernetes(下文简写 K8s)。

14.0 故障回答万能框架(先止损 → 再定位 → 后复盘) ​

任何故障场景题,先套这个框架再展开细节,面试官会认为你有生产素养:

使用方法:

  • 面试官抛出任何故障题,回答的第一句话永远是框架第一句("我处理这类问题的原则是先止损再定位"),然后进入具体案例的六段结构;
  • 六段里面试讲法是完整口述版(60–120 秒),其余五段是你被追问时的展开弹药;
  • 每个"排查"小节的第一条命令要形成条件反射——速查表就是为这准备的。
  1. 先止损(最优先,1–2 句):故障第一目标不是找根因,是恢复业务——有备切换备(主备/多副本/回滚)、能扩容先扩容、影响面大先摘流量,同时通报干系人、拉相关人员进群。宁可恢复后再慢慢查,不要让业务陪着排查。
  2. 再定位(体现技术):从入口往里、从网络到应用分层收敛;看监控(故障时间点的 CPU/内存/IO 曲线)+ 看日志(系统日志/应用日志/事件)+ 看变更("最近改了什么"——60% 故障和变更相关);单一假设验证再前进。
  3. 后复盘(体现素养):恢复后写故障报告(时间线/根因/恢复动作/影响);根因改进(配置固化、监控补盲、预案演练);把个案沉淀成规范或检查项——我的 9 项避坑清单就是这么来的。 兜底句式(答不出根因时):"当时先按 XX 手段恢复业务保证 SLA,事后复盘定位到 XX 层面,更深的原理层面我理解到 XX,可以会后补。"

案例速查总表(被问"遇到过什么故障"时,扫一眼选 1–2 个最熟的展开):

#现象第一条命令根因一句话来源
1CPU 打满top(按 P)应用死循环/挖矿/IO 传导经典
2进程被杀dmesg | grep -i oom内存泄漏,OOM killer经典
3No space leftdf -h / df -i日志堆积或 inode 耗尽经典
4页面慢慢日志 + EXPLAIN无索引全表扫描课程
5上传卡死df -h(看哪个挂载点卡)NFS 服务端抖动阻塞经典
6502/504ss -lntp 看后端502 后端挂、504 后端超时经典
7节点 NotReadykubectl get pods -n kube-flannelCNI 镜像拉取失败(90%)真实
8大面积 Pendingkubectl describe pod全量重启挤爆资源经典
9接口报错但 Pod 正常进 Pod 看 Secret 文件卷内容为空(转义丢字符)经典
10kubectl x509openssl x509 -text 查 SAN证书缺新入口地址真实
11etcdctl Pod NotFoundkubectl get pods -n kube-system命名规则记错(etcd-主机名)真实
12认证时好时坏date / timedatectl 对比节点时间不同步真实
13VIP 时通时断两台分别 ip addrKeepalived 脑裂双 MASTER经典
14DB 突然被打满redis-cli info 看命中率缓存雪崩穿透到库经典
15误删文件停服务停写入人为误操作,靠备份恢复经典
16SSH 登录慢ssh -v 看卡在哪步UseDNS 反解等超时经典
17CrashLoopBackOffkubectl logs --previous应用启动报错(配置/依赖)课程+生产
18容器宿主机磁盘涨满docker system df / du 容器日志镜像层堆积+日志无上限经典

14.1 CPU 负载高定位 【经典故障】 ​

场景:告警 CPU 持续 90%+,业务响应变慢。

排查(命令 + 为什么用 + 输出说明什么):

bash
uptime                       # 负载对比核数
top                          # P 按 CPU 排序 → 拿到 PID
top -Hp <PID>                # 看进程内哪个线程高
pidstat -u 1 5               # 持续观察是否抖动
vmstat 1 5                   # 看 cs/in 上下文切换、wa/si

我先 uptime 看负载和核数的比值——8 核的机器 load 超过 8 才算真满载,这一步先把"告警阈值触发"和"真资源耗尽"区分开,避免方向性误判。然后 top 按 P 键以 CPU 排序,一眼拿到吃资源的进程号,重点看 us、sy、wa、si 四个值怎么分:us 高是应用自己的代码在烧 CPU,sy 高说明内核态忙、通常是系统调用或上下文切换过多,wa 高其实是磁盘慢、CPU 在干等 IO,si 高则是软中断、网络包处理不过来——四项分布直接决定下一步去查应用、查内核还是查磁盘网络。拿到可疑 PID 后用 top -Hp 下钻到线程级,确认是整个进程还是单个线程打满,单线程打满大概率是死循环或锁自旋;pidstat -u 1 5 连续采样五次是为了区分持续型和抖动型——持续型是逻辑问题,抖动型要查定时任务或周期性请求。

根因:常见四类——应用死循环/内存泄漏引发 GC 风暴、异常进程(挖矿)、IO 瓶颈传导(wa 高)、突发流量。 解决:挖矿/异常进程直接 kill 并排查入侵入口(配合主机安全告警回溯);应用问题先重启或扩容止损,dump 线程栈交开发定位;IO 问题转磁盘排查链路。 预防:CPU 告警分级(70 警告 / 85 严重 / 95 紧急)、进程资源限制(cgroup/limits)、僵尸进程与可疑计划任务纳入巡检项。

面试讲法(STAR 完整版,约 300 字): 值班时收到 CPU 持续超过 90% 的告警,业务响应明显变慢。我的处理原则是先止损再定位,所以第一步先确认业务层有没有可用手段——当时判断还有冗余节点,先观察影响面,同时开始定位。我先敲 uptime,看到负载已经明显超过核数,确认是真资源耗尽不是告警误报;接着 top 按 P 排序,定位到一个 Java 进程 us 用户态接近满载——这一下就把方向从"系统问题"收敛到"应用自身";再用 top -Hp 下钻到线程,发现单个线程把一核打满,这是典型的死循环特征。止损动作用的是重启该服务,业务先恢复;重启后 CPU 回落到正常水位,确认不是持续性外部流量导致。事后把线程栈 dump 出来配合开发分析,定位到一段低效正则在特定输入下回溯爆炸,相当于死循环。复盘做了两件事:给这个服务加了 CPU 分级告警和阈值,同时推动开发建立了上线前的正则和热点代码 review 习惯。这个案例给我的沉淀是:CPU 类故障 us/sy/wa 四个指标的分布,比 CPU 总数本身信息量大得多。

14.2 内存不足与 OOM 【经典故障】 ​

场景:进程莫名被杀,日志里出现 "Out of memory: Killed process"。

排查(命令 + 讲解):

bash
free -h                                  # 看 available 列
dmesg -T | grep -i "out of memory"      # OOM killer 记录(谁被杀)
ps aux --sort=-%mem | head -10           # 内存 TOP10 进程
vmstat 1 5                               # si/so 持续非 0 = 在疯狂换页

第一步 free -h 我重点看的是 available 列而不是 free 列——buff/cache 是可回收的缓存,真正的可用内存看 available 才准。第二步 dmesg -T | grep -i "out of memory" 是 OOM 类故障的第一证据来源:内核的 OOM killer 在杀进程时一定会在内核日志里留下记录,输出里能看到被杀进程的名字、PID 和当时的内存评分,加了 -T 是把时间戳转成可读时间,方便对故障时间线。第三步 ps aux --sort=-%mem 按内存排序列出前十名,找内存大户;第四步 vmstat 1 5 看 si/so 两列——如果持续非零说明系统在疯狂换页,内存压力已经传导到交换层面,机器会表现出整体卡顿。

根因:应用内存泄漏(RSS 持续增长)、并发突增、JVM 堆配置过大挤压系统内存、K8s 节点禁用 swap 后没有兜底缓冲。 解决:先重启泄漏进程止损;调小堆或加内存限制;容器场景统一配 memory limit,防止单个容器拖垮整个节点——代价是超限会被 OOMKill,limit 值要按实际用量加余量配置,不能拍脑袋。 预防:内存使用率 80% 告警;应用容器统一配 memory limit;泄漏类问题靠监控看 RSS 趋势提前发现——缓慢爬升的曲线是泄漏的典型特征,等 OOM 才发现就晚了。

面试讲法(STAR 完整版,约 300 字): 这个案例是"我处理过类似的"口径。现象是一个业务进程周期性地莫名被杀,业务方一开始以为是崩溃,让开发查了好几轮代码没结果。我介入后第一件事不是猜,是找证据:dmesg 加 grep "out of memory",内核日志里明确有 OOM killer 的记录,被杀的就是那个进程——这一条输出直接把问题定性成系统内存耗尽、内核主动杀人,而不是应用自己崩。接着 free -h 看 available 列,确认机器可用内存已经见底;ps 按内存排序锁定一个 Python 服务的 RSS 明显异常;再回看监控的历史曲线,发现它的内存是三天里从几百兆一路爬到 4G 的——缓慢爬升,典型的内存泄漏形状。止损动作是给该服务加了定时重启的临时措施并调大了资源;根因复盘交开发确认,是代码里一个缓存没设上限,数据集一大就无限膨胀。修复之后我把内存趋势告警加进了监控——这类问题的正确发现方式是看曲线斜率,不是等 OOM。dmesg 是 OOM 故障的第一证据来源,这句话我每次培训都会讲。

14.3 磁盘满(含 inode 满) 【经典故障】 ​

场景:服务报 "No space left on device",但 df -h 看不到哪个分区满了。

排查(命令 + 讲解):

bash
df -h && df -i                      # 先分清容量满还是 inode 满
du -sh /* 2>/dev/null | sort -h     # 逐层下钻大目录
find /var/log -type f -size +500M -exec ls -lh {} \;
lsof | grep deleted                 # 已删但仍占空间的句柄
> /var/log/nginx/access.log         # truncate 释放(别 rm 大文件)

看到 no space 报错,我第一个动作是同时敲 df -h 和 df -i——前者看容量、后者看 inode。这一步是关键分叉:海量小文件场景经常是 inode 先耗尽,容量看着还有余,df -i 的 IUse% 到 100% 就是它。如果是容量满,用 du -sh /* 从根目录逐层下钻,加 sort -h 排序后最大的目录一目了然,一路钻到具体文件;find 按 +500M 找出超大文件。还有一个经典陷阱要单独查:lsof | grep deleted——如果输出里有进程还握着已删除文件的句柄,那些文件的空间并不会释放,这就是"rm 了日志 df 却没降"的原因,解法是重启对应进程或者用 truncate。

根因:日志没切割堆积、容器镜像和层堆积、数据库 binlog 堆积、删了文件但进程仍持有句柄(df 不降)。 解决:日志用重定向 > file 截断立即释放空间——比 rm 安全,因为 rm 大文件时进程若持有句柄空间根本不回来;句柄类问题按 lsof 结果重启对应进程;容器环境用 crictl/docker 的 prune 命令清理无用镜像层。 预防:logrotate 日志轮转加 7 天保留、磁盘 80% 告警、find -mtime 定期清理脚本进 crontab。

面试讲法(STAR 完整版,约 300 字): "我处理过类似的"口径。收到磁盘 100% 的告警,登录上去第一步同时跑 df -h 和 df -i——这是习惯动作,因为磁盘满有两种:容量满和 inode 满,海量小文件场景 inode 先耗尽,只看 df -h 会误判"磁盘没满啊"。这次是容量满,/var 分区到了 100%。然后 du -sh 逐层下钻,加 sort -h 排序,很快锁定了日志目录下一个几十 G 的 access.log——应用的日志切割配置没生效,请求一高峰日志就疯长。当时的释放动作我用的是重定向 truncate 而不是 rm——rm 大文件有个坑:进程持有句柄的空间不会释放,必须重启进程才回收,truncate 是原地清空立即生效,对在线服务更安全。复盘做了三件事:上了 logrotate 按天切割加保留 7 天、磁盘 80% 提前告警、把"清理大文件先 truncate 后确认空间释放"写进团队的 SOP。这个案例我常拿来讲"工具的行为差异也是运维知识"——rm 和 truncate 看似都是删,工程效果完全不同。

14.4 慢 SQL 优化 【课程项目】(口径:课程实验 + 项目理解) ​

场景:页面变慢,数据库 CPU 高,大量查询耗时超过 1 秒。

排查(命令 + 讲解): 先开启慢查询日志(long_query_time 设为 1 秒),让数据库自己记录慢语句——这一步是"让证据自己浮出来",比抓包猜语句高效得多。然后用 mysqldumpslow 按语句聚合排序,找到出现最多、耗时最长的 TOP 慢 SQL。最后对这条语句跑 EXPLAIN 看执行计划,四个字段是判读重点:type 列如果是 ALL,意味着全表扫描,这就是慢的直接原因;key 列显示有没有真的用上索引;rows 列显示预估扫描行数,百万级就是灾难;Extra 列出现 Using filesort 或 Using temporary 说明还有额外的排序和临时表开销。

根因:无索引或索引失效(隐式类型转换、函数包字段、前导百分号模糊匹配)、select * 拖回大字段、深分页、join 关联列无索引。 解决:按 where 和 order by 的列建索引;改写 SQL——避免函数包列、深分页改游标方式;数据量大的表考虑读写分离或归档。 预防:上线前 EXPLAIN 评审进流程、慢查询数量纳入监控告警、大表变更走 DBA 审核。

面试讲法(STAR 完整版,约 280 字): 这块我的完整实操在课程实验里,生产上配套过思路。实验的场景是页面变慢、数据库 CPU 居高不下。我的排查链路三步:第一步开慢查询日志,把 long_query_time 设为 1 秒,让数据库自动留痕——先拿到证据再动手;第二步 mysqldumpslow 聚合,按耗时和次数排序,锁定一条出现频率最高的查询;第三步对它跑 EXPLAIN 看执行计划,输出里 type=ALL、rows 是百万级——全表扫描实锤,key 列为空说明索引根本没用上。处理动作是在过滤列上建索引,再 EXPLAIN 复测,type 变成了 ref、rows 降到千级,实测耗时从 2 秒降到 20 毫秒,两个数量级的改善。生产上的关联是:银行项目我配套的数据库是 Vastbase,PostgreSQL 系,排查思路完全一致——也是先慢日志定位、再看执行计划、索引和 SQL 改写两手处理,工具不同方法论相通。这个口径我如实讲:课程实验完整做过链路,生产理解配套层面的原理。

14.5 NFS/存储上传卡死(话术文档经典) 【经典故障】 ​

场景:文件上传频繁卡死,但服务器的 CPU、内存、磁盘 IO 指标看起来基本正常。

排查(讲解性叙述):这类"指标正常但业务卡死"的故障最考验思路。我先按常规链路排除:top、free、iostat 过一遍,CPU 偶尔摸到 90% 但不持续,不构成根因;fdisk -l 确认本地磁盘识别和挂载都正常。真正的关键分叉点在复现时的一句 df -h:命令输出里本地挂载点全部正常返回,唯独网络存储的挂载点直接卡死、光标停在那里不动——这一下就把问题从"本机资源层"切到了"存储网络层"。df 卡死本身就是诊断信息:说明内核在等那个挂载点的 IO 响应。再查 /var/log/messages,里面大量 "NFS: server not responding" 和 retrans 超时记录佐证;应用日志里同步看到 "Connection timed out while uploading";最后和开发确认近期改过上传的超时重试参数,完整闭环。

根因:网络存储设备高负载时连接抖动,加上存储端网络参数与服务器不兼容;NFS 默认硬挂载,服务端无响应时写它的进程进入 D 状态无限等待,表现就是卡死。 解决:存储团队优化网络配置——超时和重传参数匹配、连接加固、带宽监控;恢复后用大量文件上传压测验证,日志无报错才算闭环。 预防:NFS 挂载合理配置 soft 或 timeout 参数做超时兜底;应用上传加超时和失败降级逻辑;对存储挂载点做探测监控,挂载点不可达直接告警。

面试讲法(STAR 完整版,约 300 字): "我处理过类似的"口径,这个案例的原型来自话术库,我把它按完整排查链讲。背景是文件上传频繁卡死,但机器的 CPU、内存、磁盘指标都基本正常——这种"指标正常业务卡"的场景,思路要从本机资源转到外部依赖。我先常规排除了一遍资源问题,都没实锤;然后复现的同时敲 df -h,看到了关键现象:本地挂载点秒回,网络存储的挂载点直接挂住不返回——df 这个再普通不过的命令,卡死本身就是诊断信息,说明 IO 阻塞在存储链路而不是本机。顺着这个方向查 /var/log/messages,大量 NFS server not responding 的记录佐证;应用日志的上传超时报错和开发侧近期改过重试参数的信息也对上了。根因是存储设备高负载时网络抖动加参数不兼容,NFS 硬挂载让进程无限等待。解决是存储团队调优网络参数后压测通过。这个案例给我的最大收获:排查命令的"异常行为"和它的输出一样有价值——命令卡住不返回,本身就是一层证据。

14.6 服务 502/504 【经典故障】 ​

场景:Nginx 反向代理后面,用户请求大量 502/504。

排查(命令 + 讲解):

bash
tail -100 /var/log/nginx/error.log    # connect() failed=502;upstream timed out=504
ss -lntp | grep 8080                   # 后端监听在不在、听的是不是 0.0.0.0
ss -ant | grep 8080 | awk '{print $1}' | sort | uniq -c   # 连接状态分布
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' http://127.0.0.1:8080/   # 本机直连后端

第一步先分清两个码的含义,方向完全不同:502 是后端连不上或返回无效响应——后端挂了、重启中、监听地址不对;504 是连上了但超时没返回——后端慢,慢在数据库或下游依赖。tail Nginx 的 error.log,connect() failed 对应 502、upstream timed out 对应 504,日志措辞直接分诊。然后 ss -lntp 看后端端口:进程在不在、监听地址是不是 0.0.0.0——只听 127.0.0.1 是经典坑,本机自测正常、Nginx 连不上。ss -ant 统计连接状态分布,大量 SYN_SENT 是连不上、大量 CLOSE_WAIT 是应用不关闭连接。最后 curl 本机直连后端,用 -w 输出状态码和总耗时,绕开 Nginx 验证后端本身的健康状况。

根因:502 常见——后端进程挂了或正在重启、监听 127.0.0.1、backlog 打满、后端被 OOM;504 常见——慢 SQL 或下游依赖慢、PHP-FPM/线程池耗尽、超时参数配得过短。 解决:502 优先拉起后端进程、修正监听地址;504 要定位慢在哪一层——数据库、下游接口还是自身线程池,临时放大 proxy_read_timeout 只能缓解,必须治慢源。 预防:后端多副本加健康检查自动摘除、超时与重试参数标准化、慢查询和连接池纳入监控。

面试讲法(STAR 完整版,约 320 字): 这个案例结合我在银行项目自研平台上真实处理过的口径。现象是平台上线后用户反馈登录后的接口报错,Nginx 返回错误码。我的排查按"从入口往里"走:第一步 curl Nginx 的入口是通的,说明 Nginx 本身活着;第二步 telnet 后端 8080 端口通,说明 Nginx 到后端的网络链路没问题——到这里 502 那种"后端连不上"的方向就基本排除了;第三步登后端机器 jps 确认 Java 进程在、ss 看监听正常;于是疑点收敛到应用内部,翻后端日志,看到了数据库连接报错——应用连不上数据库。顺着这条线查下去,定位到是 Vastbase 主备切换之后,应用的连接串指向没有跟着更新,导致认证和查询失败。修正连接配置并重启应用后恢复。这个案例我的总结是两条:一是 502/504 的第一判断永远是先分清"连不上"还是"连上了但慢",两者排查方向完全不同;二是从入口一层层往里收敛,每一步排除一层,剩下的就是答案——比跳着猜快得多。

14.7 K8s 节点 NotReady(真实:镜像拉取) 【真实项目】 ​

场景:移动云项目,三台 worker join 之后 kubectl get nodes 一直显示 NotReady。

排查(命令 + 讲解):

bash
kubectl get nodes                                  # NotReady
kubectl get pods -n kube-flannel -o wide           # ImagePullBackOff
kubectl describe pod <flannel-pod> -n kube-flannel | grep -A5 Events
kubectl edit daemonset kube-flannel-ds -n kube-flannel   # 镜像地址替换为内网仓库

kubectl get nodes 先确认 NotReady 的节点范围,是全部还是个别——全部 join 的 worker 都 NotReady,基本指向共性问题而不是单机故障。然后直接看 CNI 的 Pod:kubectl get pods -n kube-flannel -o wide,加 -o wide 能看到 Pod 落在哪些节点、当前状态——输出里的 ImagePullBackOff 一目了然,Flannel 起不来,节点网络插件没就绪,kubelet 自然把节点标成 NotReady。再用 kubectl describe pod 看 Events 区块,拉取失败的具体镜像地址和报错都在那里:海外镜像源在移动云内网不可达。这就是我说"九成 NotReady 是镜像拉取问题"的经验来源——kubelet 的 Ready 条件依赖 CNI 就绪,CNI 的镜像拉不下来是一切的开端。

根因:内网环境海外镜像不可达 → CNI 插件起不来 → 节点网络未配置 → kubelet 置 NotReady。 解决:镜像分层策略——首选移动云内网私有仓库(kubectl edit daemonset 把 init 容器和主容器的镜像地址全部替换为内网仓库地址)、备选阿里云公共镜像源、兜底用二进制包手动部署。 预防:部署顺序强制"先 CNI 后 worker";部署前把镜像清单预导入内网仓库——这条写进了建设方案的避坑清单第 1 条。

面试讲法(STAR 完整版,约 300 字): 这是我在移动云项目真实踩的坑。情境:集群部署到 worker 加入阶段,三台 worker join 完成后 kubectl get nodes 全部 NotReady,部署卡住。任务:让节点就绪、把部署推进下去。行动:我先 get nodes 确认三台全 NotReady——全部中招说明是共性问题;直接看 kube-flannel 命名空间的 Pod,状态是 ImagePullBackOff——九成的 NotReady 到这一步就见分晓了;再 describe 看 Events,确认是海外镜像源在内网拉不下来,Flannel 起不来,节点网络没配置。解决动作用的是 kubectl edit 直接改 Flannel 的 DaemonSet,把 init 容器和主容器的镜像全部替换成内网私有仓库的地址,DaemonSet 滚动更新后 Pod 正常 Running,三台节点几分钟内全部 Ready。结果之外更重要的是沉淀:我把"先部署 CNI 再加 worker"固化成部署顺序,把镜像清单预导入写成标准动作,这两条后来都在 9 项避坑清单里。这个案例我讲的时候会主动给出经验句:遇到 NotReady 先查 CNI Pod 的镜像状态,九成问题在那里终结。

14.8 K8s Pod 全量重启变 Pending(话术案例三) 【经典故障】 ​

场景:一次修改证书 Secret 触发 200 多个 Pod 同时重启,全部 Pending 起不来。

排查(讲解性叙述):kubectl get pods -A 先看全局——所有命名空间的 Pod 大面积 Pending,这个"全量"的分布本身就是重要线索:不是某个应用的问题,是集群级现象。然后对任一 Pending 的 Pod 执行 kubectl describe pod,直接翻到 Events 区块,看到 FailedScheduling 的报错,写明 Insufficient resources——CPU/内存不足。这句话的含义要说透:不是 Pod 本身有毛病,是调度器找不到满足资源请求的节点——平时这些 Pod 分布在集群里是放得下的,但"全部同时退出再全部同时要求调度"的瞬间,资源需求峰值远超集群容量,调度必然排队失败。

根因:公共挂载的 Secret 变更导致全量 Pod 秒级重启,瞬时并发资源需求远超集群容量——平时滚动分批重建没问题,全量并发重建是灾难。 解决:全停之后分批拉起——每次只起一个模块约 20 个 Pod,等全部 Running 并稳定观察 3 分钟再拉下一批,约 10 批全部恢复,全程约半小时。 预防:公共卷和配置类的变更改用滚动升级方式(每批约 10 个);容量规划预留重启水位;这类变更安排在业务低峰窗口。

面试讲法(STAR 完整版,约 300 字): "我处理过类似的"口径,原型是话术库的经典案例。情境:一次修改被大量 Pod 公共挂载的证书 Secret,触发了 200 多个 Pod 同时重启,重启后全部卡在 Pending,业务全面中断。任务:尽快恢复。行动分两步:先定位,kubectl get pods -A 看到的是全命名空间的大面积 Pending,describe 任一 Pod 的 Events 里明确写着 FailedScheduling、Insufficient resources——问题不在 Pod 而在调度层,是全量并发重建把集群资源挤爆了;再恢复,策略是全停后分批拉起:每次只拉一个模块约 20 个 Pod,稳定运行 3 分钟再下一批,10 批左右全部恢复,总耗时约半小时——分批的意义是把瞬时资源峰值压回集群容量之内。复盘的改进是:公共挂载的配置变更从"直接改"改成"滚动升级每批 10 个",容量规划里专门留出重启水位。这个案例我特别喜欢讲它背后的道理:K8s 的声明式自愈在"全量并发重建"场景反而是放大器——技术不能替代变更策略,自动化越强越要敬畏变更。

14.9 K8s Secret 空值致接口报错(话术案例二) 【经典故障】 ​

场景:新环境部署完成后,前端页面正常,但后端调用隔壁部门的鉴权接口必报错。

排查(讲解性叙述):这个案例的排查链路特别长,是"层层回退"的典型。第一层 kubectl get pods——全部 Running,应用层看起来完全健康,这是第一个陷阱:Pod 状态健康不等于业务健康。第二层翻后端日志——调用鉴权模块的请求全部报错,说明问题在链路下游。第三层找鉴权侧的同事排查——发现收到的请求入参是空的,鉴权自然拒绝。第四层回到我方 Pod 里查看挂载的 Secret 文件——文件存在,但内容是空的!到这里问题从"接口"回退到了"初始化"。第五层查初始化脚本的日志——发现创建 Secret 时其实已经打印过"创建出来但内容为空"的提示,被脚本的异常处理逻辑吞掉了,没有显式报错退出。最终根因在密码生成脚本:随机密码里生成了反斜杠字符,在字符串处理中作为转义字符吃掉了后一位,8 位密码变成 7 位,后续校验全部对不上;另一个环境没出问题,纯粹是随机数没撞上反斜杠——概率型故障。

根因:随机密码含特殊字符未转义导致内容缺位 + 初始化脚本异常处理吞错,两层叠加。 解决:密码字符集剔除易出错的特殊字符;初始化脚本改成"失败必须大声失败"——任何异常显式报错退出,不允许静默吞掉;对随机值功能做全字符集回归测试。 预防:随机值类功能必须全字符集测试;初始化脚本失败显式退出;Pod Running 不等于业务健康——要靠就绪探针和业务拨测兜底。

面试讲法(STAR 完整版,约 320 字): "我处理过类似的"口径,这个案例我用来展示排查耐心。现象很迷惑:新环境部署完,前端页面一切正常,唯独后端调鉴权接口必报错——而且 Pod 全部 Running,第一眼看不出任何异常。我的排查是层层回退的:先看 Pod 状态,健康——这是第一个假象;翻后端日志,调用鉴权全报错——问题在下游;请鉴权侧同事配合看,发现收到的入参是空的——问题又回到我方;进 Pod 看挂载的 Secret 文件,文件在、内容是空的——问题在初始化;最后翻初始化脚本日志,发现当时就提示过"创建出来但内容为空",被异常处理吞掉了。真正的根因是随机密码里撞上了一个反斜杠,转义吃掉一位,密码缺位校验失败——另一个环境没出事纯粹因为随机数没生成反斜杠,这是概率型故障,测试用例不完备就必然漏网。修复做了三件事:字符集剔除易错字符、脚本失败显式退出、全字符集回归。这个案例我讲两个收获:Pod Running 不等于业务健康;概率型故障最考验的是把排查链走到底、不提前下结论的耐心。

14.10 证书 SAN 缺失(真实:多 master 改造) 【真实项目】 ​

场景:银行项目单 master 升级三 master 之后,用 VIP 连 apiserver 报证书错误,kubectl 不可用。

排查(命令 + 讲解): 排查只用了两条命令就完成了关键分叉。第一条 curl -k https://VIP:16443/version——加 -k 跳过证书校验,返回正常——这说明网络链路、负载均衡、apiserver 服务本身全部正常,问题被精确切割到"证书校验"这一层。第二条 kubectl 连同样的地址报 x509 错误——kubectl 不跳过校验,报 x509 就指向证书内容。两条命令一对比,结论清晰:服务是好的,是证书的"有效范围"不覆盖现在的访问方式。然后 openssl x509 -in apiserver.crt -text -noout 查看证书详情,翻到 SAN(Subject Alternative Name)字段——里面只有原来单 master 时期的地址,没有新 VIP 和 master02/03 的主机名和 IP。根因落定:kubeadm 的 apiserver 证书只包含初始化时 certSANs 里声明的名字,后来加的入口地址不在里面,TLS 校验必失败。

根因:kubeadm 的 apiserver 证书 SAN 范围在初始化那刻就固定了,后续新增的 VIP 和节点不在证书里,客户端按 VIP 访问时校验失败。 解决:标准三步——①导出 kubeadm 配置,在 apiserver 的 certSANs 里追加新 VIP、三台 master 的主机名和 IP;②把旧证书移走 mv /etc/kubernetes/pki/apiserver.{crt,key}——不移走的话 kubeadm 认为证书已存在不会重建;③执行 kubeadm init phase certs apiserver --config kubeadm.yaml 重新签发,删掉 apiserver 静态 Pod 让 kubelet 用新证书拉起,openssl 复核 SAN 列表;最后把 certSANs 回写进 kubeadm-config 的 ConfigMap,防止下次 renew 时又丢。 预防:改集群入口地址必须先想证书;certSANs 在初始化时就把 VIP、全部 master、负载均衡地址一次性规划进去;证书到期前 30 天按规范执行 kubeadm certs renew all。

面试讲法(STAR 完整版,约 330 字): 这是我印象最深的一个真实故障,因为它把"两句话定位"的价值体现得淋漓尽致。情境:银行项目把单 master 升级成三 master、前面加了 Nginx+Keepalived 的 VIP 之后,用 VIP 连 apiserver,kubectl 报 x509 证书错误,集群操作全部不可用。任务:尽快恢复管理入口。行动:我先 curl -k 加跳过校验去访问 VIP 的 16443——正常返回,两秒钟就证明网络、负载均衡、apiserver 服务全都没问题,问题被切割到证书层;再用 openssl x509 -text 看 apiserver 证书的 SAN 字段,果然只有旧地址,新 VIP 和新 master 都不在里面——kubeadm 证书的覆盖范围在初始化那一刻就定了。解决按三步走:改 kubeadm 配置补全 certSANs、移走旧证书(不移 kubeadm 不会重建)、kubeadm init phase certs apiserver 重新签发后重启 apiserver,kubectl 恢复正常;最后把 SAN 回写进配置防止续期时再丢。结果:管理入口恢复,整套流程沉淀成了标准步骤。这个故障给我的规则级教训是:证书的有效范围在签发那一刻就定了——后来移动云项目我们初始化时就把 CLB 的 VIP 直接写进 certSANs,这个坑再也没有出现过。把踩过的坑变成团队的前置设计,这是故障复盘最大的价值。

14.11 etcd Pod NotFound 命名坑(真实) 【真实项目】 ​

场景:按文档执行 etcd 健康检查,etcdctl 报 Pod 不存在,但 etcd 明明正常运行。

排查(讲解性叙述):排查动作非常朴素——kubectl get pods -n kube-system | grep etcd 列出真实的 Pod 名,和命令里写的名字一对比,立刻发现对不上:堆叠式部署的 etcd Pod 命名规则是 etcd-<节点主机名>(比如 etcd-k8s-master-01),不带 kube- 前缀;而检查命令里写的是想当然的名字。资源名对不上,kubectl exec 自然报 Pod NotFound——报错的不是 etcd 的健康,是命令本身找错了对象。

根因:校验命令与实际资源命名不匹配(文档笔误或版本差异),不是 etcd 真有问题。 解决:按真实命名执行校验:kubectl exec -it etcd-<主机名> -n kube-system -- etcdctl --endpoints=https://127.0.0.1:2379 --cacert=... --cert=... --key=... endpoint health,三个副本全部返回 healthy 才算验收通过。 预防:所有校验命令先 get 对齐真实资源名再执行;脚本化的健康检查统一从 API 动态取资源名,不硬编码。

面试讲法(STAR 完整版,约 260 字): 一个很小但很真实的案例,发生在集群验收环节。情境:按文档逐项执行 etcd 健康检查,etcdctl 的命令报 Pod NotFound——第一眼很容易吓一跳,以为 etcd 出问题了,而 etcd 是集群的心脏。任务:判断 etcd 到底健康与否。行动:我没有急着怀疑组件,先 kubectl get pods -n kube-system 把真实的 Pod 列出来和命令里的名字对比——一眼看出对不上:堆叠式 etcd 的 Pod 名是"etcd-加节点主机名",没有 kube- 前缀,检查命令里写的是想当然的名字。按真实命名重新执行 etcdctl endpoint health,带全三证书参数,三个副本全部 healthy——etcd 从头到尾都是好的,是命令找错了对象。结果:验收继续,同时把"校验命令先对齐真实资源名"写进了验收命令模板。这个案例的教训我经常讲:排障第一步永远是先对齐"资源到底叫什么、在哪",别急着怀疑组件坏了——很多"故障"其实是"问错了问题"。

14.12 时间不同步导致认证失败(真实) 【真实项目】 ​

场景:集群节点间认证频繁失败,日志时间戳乱跳,部分请求间歇性被拒。

排查(命令 + 讲解):

bash
timedatectl                                   # 各节点逐一对比时间与时区
chronyc sources -v                            # 确认同步源是否可达、已选择
chronyc tracking                              # 偏差量(毫秒级正常)
# 修复:全节点 chrony 指向内网 NTP,重启服务后 timedatectl 显示 synchronized

"时好时坏"是这类故障的关键词——持续性故障好查,间歇性故障要先找"变化的变量"。我在多台节点上逐个跑 timedatectl 对比时间和时区,发现个别节点的时间偏差到了秒级甚至更大——一致性被破坏的位置找到了。原理层:TLS 证书校验对时间敏感,证书有 NotBefore/NotAfter 的有效窗口,节点时间偏差大,校验就可能落在窗口外被判失败,所以认证"时好时坏"——正好对上了偏差飘移的行为。再看 chronyc sources -v 确认时间源配置:有的节点没配源、有的 chrony 服务压根没起,根因落定。修复后用 chronyc tracking 看偏差量,毫秒级才算健康。

根因:节点未统一时间同步,TLS 证书时间窗校验间歇性失败。 解决:全节点 chrony 统一指向移动云内网 NTP 服务器,重启服务,sources 显示已同步、tracking 偏差毫秒级;"时间同步检查"写入节点初始化基线,成为必查项。 预防:初始化脚本强制安装 chrony 并校验同步状态;时间偏差纳入监控告警;证书类问题的排查清单第一步固定加"先对时间"。

面试讲法(STAR 完整版,约 280 字): 移动云项目真实踩过。情境:集群部署后节点间认证时好时坏,日志时间戳看着也乱,这类间歇性问题最磨人。任务:定位这个"变化的变量"。行动:我的直觉先押时间——因为证书类认证对时间敏感;逐台节点跑 timedatectl 对比,果然个别节点偏差到了秒级,其他节点正常——差异找到了,时好时坏的行为模式和偏差漂移完全吻合;再用 chronyc sources -v 检查时间源,发现出问题的节点要么没配 NTP 源、要么 chrony 服务没启动。解决:全节点 chrony 统一指向内网 NTP,重启后 tracking 显示偏差毫秒级,认证问题再未复现。结果之外的动作更重要:我把"时间同步校验"加进了全节点标准化初始化的必查清单,也纳入了 9 项避坑清单——一句话总结就是"先对时间,再谈认证"。这个案例我用来说明:间歇性故障的排查入口是找"不一致",多节点横向对比是最快的找法。

14.13 Keepalived 脑裂 【经典故障】(结合项目一真实防范经验) ​

场景:主备两台负载均衡,网络抖动后两边都认为自己是 MASTER,VIP 冲突,流量时通时断。

排查(命令 + 讲解):确认脑裂一条命令就够:两台机器分别执行 ip addr,看 VIP 绑在谁身上——如果两边都绑着 VIP,脑裂实锤,因为正常状态 VIP 只应该在 MASTER 一方。然后查 Keepalived 日志和 /var/log/messages,能看到两边各自的状态切换记录;再检查 VRRP 通告链路:主备之间的 VRRP 组播(或单播)报文有没有被中间的交换机或防火墙拦截、advert_int 通告间隔和超时配置是否匹配——脑裂的直接诱因几乎都是"备节点收不到主的通告"。

根因:主备之间 VRRP 报文不可达(网络分区、交换机组播被禁、防火墙拦截),备节点超时后自我升级 MASTER,而主节点还活着——本质是"双方互相看不见但都在服务"。 解决:临时处置:确定一方降级——停掉一端的 keepalived 或手动摘除 VIP,先恢复流量唯一性;根治:打通 VRRP 通告链路——放行 VRRP 协议(IP 协议号 112)或组播,或改用 unicast 明确指定对端地址。 预防(我在项目一的真实做法,四招):① vrrp_script 检测真实服务端口——脚本里 ss -antp | grep 16443,数到 0 个进程就 exit 1 触发降权漂移,而不是只检测 keepalived 进程活着(keepalived 活着不代表后端服务活着);② 主备 priority 拉开(100 对 90)加 advert_int 1 秒快速感知;③ VRRP 通告走管理平面交换机,保证链路质量;④ 上线前必须演练——主节点直接关机,验证 VIP 秒级漂移、curl -k https://VIP:16443/version 业务正常。

实操模板(防脑裂的检测脚本片段,可背):

text
vrrp_script chk_apiserver {
    script "/etc/keepalived/check_16443.sh"   # ss -antp | grep 16443 || exit 1
    interval 2
    weight -20                                 # 检测失败降权,触发 VIP 漂走
    fall 2
}
# 主:state MASTER / priority 100;备:state BACKUP / priority 90
# 验证:主节点关机 → ip addr 看 VIP 漂移 → curl -k https://VIP:16443/version

面试讲法(STAR 完整版,约 300 字): 脑裂这个题我既有理论理解也有防范实践,分开讲。先讲原理:Keepalived 的主备关系靠 VRRP 通告维持,主节点周期性发通告、备节点超时没收到就自我升级——如果主备之间的通告链路被网络分区或交换机组播限制打断了,就会出现两边都是 MASTER、都绑 VIP 的脑裂,流量时通时断。确认方法一条命令:两台分别 ip addr,都绑着 VIP 就是实锤。再讲我在银行项目的实践——单 master 升三 master 时我配的 Nginx+Keepalived 前置层,防脑裂用了四招:检测脚本盯的是 16443 端口有没有真实监听而不是 keepalived 进程本身,因为 keepalived 活着不代表 apiserver 代理链路活着;priority 主备拉开 100 比 90 避免抢占抖动;VRRP 通告走独立的管理平面交换机保证链路;最关键的是上线前做了真实演练——主节点直接关机,实测 VIP 秒级漂移、curl VIP 的 version 接口正常返回、kubectl 无感。这套"设计加实测"的完整闭环我在现场做过,讲的时候有底气。

14.14 Redis 缓存雪崩 【经典故障】 ​

场景:某一时刻大量请求直接打到数据库,数据库 CPU 打满,服务整体变慢。

排查(命令 + 讲解):

bash
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses'  # 命中率骤降=雪崩信号
redis-cli info memory | grep used_memory_human                  # 内存水位
redis-cli --scan --pattern '*' | head                            # 键规模摸底
mysql -e 'show processlist;' | wc -l                             # DB 连接激增佐证

先在 Redis 侧看 info stats 的 keyspace_hits 和 keyspace_misses——命中率突然骤降是雪崩的第一信号,说明原本该命中缓存的请求全部落空;info memory 看内存水位排除 Redis 自身异常;--scan 摸一下键规模。再切到数据库侧交叉验证:show processlist 的连接数激增、慢查询出现,证实请求穿透到了库——两侧证据对上,"缓存失效、压力穿透"的链路就成立了。

根因:雪崩 = 大量 key 同一时刻集中过期(或缓存实例整体宕机),请求全部落到数据库把它压垮。要和两个近亲概念区分:击穿是单个热点 key 过期、穿透是查询根本不存在的数据缓存永远不命中——三个的处理手段不同,混着说会露怯。 解决:止损优先——恢复缓存层或对数据库限流保护,别让库先死;根治三板斧:过期时间加随机抖动打散集中失效、热点数据设置逻辑不过期加异步刷新、多级缓存或集群分片避免单点整体宕机;穿透场景用空值缓存或布隆过滤器。 预防:缓存命中率与数据库 QPS 的联动告警;key 过期时间打散写成开发规范;缓存层自身高可用——项目二选云 Redis 双机热备正是这个理由。

面试讲法(STAR 完整版,约 300 字): "我处理过类似的"口径。先给定义分层,这是这题的得分点:雪崩是大量 key 批量同时失效、请求全部砸到数据库;击穿是单个热点 key 失效、热点请求穿透;穿透是查不存在的数据、缓存永远不命中——三个机制不同、药方不同。排查思路我用双侧验证讲:Redis 侧 info stats 看命中率,命中率骤降是第一信号;数据库侧 show processlist 看连接数和慢查询,连接激增是穿透的佐证——两侧证据对上,链路成立。处理按"先保库再治因":止损动作是限流保护数据库、尽快恢复缓存层;根治三板斧是过期时间加随机抖动把集中失效打散、热点 key 逻辑不过期加异步刷新、穿透场景上空值缓存或布隆过滤器。最后落到我的项目关联:移动云项目配套的云 Redis 我们选的是双机热备,选型理由之一就是缓存层自身高可用是防雪崩的前置条件——缓存层一挂,什么打散策略都白搭。把故障知识和选型决策连起来讲,是我答这类题的习惯。

14.15 误删文件 / rm -rf 应急与备份恢复 【经典故障】 ​

场景:运维误操作 rm -rf 删掉业务目录或配置文件,服务立即报错。

排查/应急(按分钟级的动作顺序背):① 立即停止写入——相关服务先停掉,目的是避免新数据覆盖被删数据的磁盘块,删除后的数据块在没被覆盖前是可恢复的;② 评估影响面——删的是配置(可重建)还是数据(必须恢复),处置路径完全不同;③ 数据类:同分区卸载或以 readonly 重新挂载,用 extundelete/testdisk 尝试恢复,或直接走备份恢复;④ 有备份走备份最稳——先恢复到临时目录校验完整性,确认无误再切回,不要直接覆盖生产;⑤ K8s 场景:删的是资源用 kubectl apply 从 YAML 重建——声明式资源可从 git 仓库秒级重建,这正是配置 git 化的价值;etcd 有快照可以 snapshot restore。

根因:人为误操作 + 无二次确认机制 + 通配符和路径变量未校验。 解决:以我的项目规范为例的三层备份:etcd 定期 etcdctl snapshot save、云盘快照、crontab 备份脚本(tar 加日期命名加异机传输)。 预防(背五条):高危命令二次确认(rm 别名成 rm -i 或先移入回收目录);脚本里的路径变量先 echo 校验再执行;最小权限——日常操作不用 root;一切可重建资源进版本库——YAML 和配置 git 化;3-2-1 备份原则(3 份数据、2 种介质、1 份异地)加定期恢复演练——没验证过恢复的备份等于没有备份。

实操模板(crontab 定时备份骨架,可背):

bash
#!/bin/bash
# /opt/scripts/backup_app.sh —— 每天凌晨 2 点备份并传输异机
DATE=$(date +%F)
tar czf /backup/app_$DATE.tar.gz /data/app /etc/nginx
find /backup -name "app_*.tar.gz" -mtime +7 -delete   # 保留 7 天
scp /backup/app_$DATE.tar.gz backup@<异机>:/backup/    # 异地一份
# crontab:0 2 * * * /opt/scripts/backup_app.sh &>/dev/null

面试讲法(STAR 完整版,约 300 字): 这题我不讲"我删过库"——没删过就是没删过,我讲的是应急体系和预防体系,这才是面试官想听的。万一发生误删,我的动作是有顺序的:第一分钟先停服务停止写入——删除后的数据块在被覆盖之前是可恢复的,多写一秒就多一分不可逆;第二步判断删的是配置还是数据——配置可重建、数据要恢复,路径完全不同;第三步有备份走备份恢复,先恢复到临时目录校验再切回生产,绝不直接覆盖。然后讲我的体系:移动云项目有三层保障——etcd 的 snapshot save 定期快照、云盘快照、crontab 的 tar 备份加异机传输,并且做过恢复演练验证过可用性;所有 YAML 和配置全部 git 化,误删资源的恢复从小时级变成分钟级的 kubectl apply。预防五条我随口能数:高危命令二次确认、脚本路径先 echo 后执行、日常不用 root、可重建资源进版本库、3-2-1 备份加演练。最后一句收尾:备份的价值不在备了,在于验证过能恢复——这句是我对备份体系的核心理解。

14.16 SSH 连接慢(DNS 反解卡顿) 【经典故障】 ​

场景:ssh 登录服务器要等十几秒才出密码提示,登上去之后一切正常。

排查(命令 + 讲解):先用 ssh -v 用户@主机 打开详细输出——v 参数会把连接的每个阶段打印出来,看到卡顿发生在哪一步:卡在 "Connection established" 之后、密码提示之前,说明 TCP 三层早就通了,卡的是 sshd 进程的后续处理。最常见的原因就是 DNS 反向解析:sshd 默认配置 UseDNS 开着,收到连接后会反查客户端 IP 的域名,内网没有反解记录就会等到超时——十几秒的等待就是 DNS 超时的时间。另一个常见卡点是 GSSAPI 认证:客户端尝试 GSSAPI 协商失败也要耗几秒。验证方法:time ssh 用户@主机 exit 计时对比改动前后。

根因:sshd 的 UseDNS 反向解析在无反解记录的内网环境等超时;叠加 GSSAPI 认证协商。 解决:改 /etc/ssh/sshd_config——UseDNS no、GSSAPIAuthentication no,重启 sshd 立竿见影,连接从十几秒降到秒回。 预防:把这两项加入系统初始化基线(我们国产化环境初始化就有这条);运维登不上机器的每一秒都在放大故障处理时间,交互体验也是运维质量。

面试讲法(STAR 完整版,约 260 字): "我处理过类似的"口径。现象是内网一批机器 SSH 登录特别慢,密码提示要等十几秒,登上去后操作一切正常——"慢在登录前、正常在登录后"这个形态本身就是线索。我用 ssh -v 打开详细日志看卡在哪一步:TCP 连接很快就 established 了,卡在密码提示之前,说明不是网络问题,是 sshd 自己在做什么慢事。这类"服务端连接后卡住"最常见的就是 DNS 反向解析:sshd 默认会把客户端 IP 拿去做反查,内网没有反解记录就干等超时,十几秒正好是 DNS 超时的量级。改 sshd_config 把 UseDNS 关掉,顺手把 GSSAPIAuthentication 也关了,重启 sshd 再 time 一遍——秒回。这条配置后来进了我们的系统初始化基线。这个案例我用来说明一个方法:交互类"慢"的问题,先用手头的 verbose 模式(ssh -v、curl -v)把过程分段计时,卡在哪一段一目了然,比瞎猜快十倍。

14.17 Pod 起不来 / CrashLoopBackOff 通用排查 【经典故障】(课程项目 + 生产接触) ​

场景:部署的 Pod 一直不 Ready,状态 CrashLoopBackOff 或反复重启。

排查(命令 + 讲解):第一句 kubectl get pods -o wide 看状态和重启次数——RESTARTS 列持续增长就是崩溃循环;接着 kubectl describe pod 看 Events 区块,这里是 K8s 的"挂号处":ImagePullBackOff 是镜像拉不下来、FailedScheduling 是资源不够、没有探针失败的记录但容器退出就走下一步看日志。kubectl logs --previous 是关键命令——加 --previous 看的是上一次崩溃前的日志,不加的话容器刚重启可能什么都看不到;日志里通常就是答案:配置文件路径错误、连不上数据库、端口被占用、启动参数不合法。如果日志显示 OOMKilled,describe 的 Last State 里能看到退出码 137,方向转向内存 limit 太小。kubectl get events --sort-by=.lastTimestamp 按时间排序看全局事件,排并发问题时有用的补充。

根因:高频四类——应用启动报错退出(配置/依赖问题)、镜像问题、探针配得太苛刻(健康检查不过被反复杀)、资源 limit 不足被 OOMKill。 解决:按日志对症:配置错修配置;探针太苛刻调 initialDelaySeconds 和阈值;OOM 调大 memory limit(同时查内存泄漏);依赖连不上按网络链路查(Service/端点/安全组)。 预防:标准化就绪探针模板(合理延迟和阈值);资源 requests/limits 按实测用量配置;启动类问题的日志格式统一,让 logs 一眼能定位。

面试讲法(STAR 完整版,约 280 字): 这是我在集群部署和业务发布中反复处理的一类问题,我按标准链路讲。现象:业务 Pod 部署后一直不 Ready,状态 CrashLoopBackOff。我的排查三步走:第一步 kubectl describe pod 看 Events——先排除调度层和镜像层的问题,Events 显示容器起来了又退出,说明是应用自身崩溃;第二步 kubectl logs --previous 看上一次崩溃的日志——这个 --previous 参数是细节所在,不加的话看到的是刚重启的空日志;这次日志里是数据库连接失败,连接串指向的 Service 不存在——配置里写错了服务名;第三步修正配置重新部署,Pod 正常 Running。如果日志看不出问题,我还会看 Last State 的退出码:137 是 OOMKilled 转内存方向,0 或 1 转应用代码方向。这类问题给我沉淀的口诀是:"describe 看事件、logs 看 --previous、退出码分方向"——三步以内必有答案。发布环节我最常处理的也是这类,处理多了基本是条件反射。

14.18 容器环境磁盘涨满(镜像层与日志) 【经典故障】 ​

场景:容器宿主机磁盘告警,但业务数据和系统日志都不大。

排查(命令 + 讲解):还是 df -h 先确认挂载点——容器环境常见的"凶手"在两个地方。第一个是容器运行时的数据目录:crictl images 或 docker images 列出本机镜像,docker system df(或 crictl 对应统计)看镜像、容器、卷各占了多少——反复构建又没清理的环境,悬空镜像(dangling)和废弃层能堆出几十 G;docker ps -a 看已退出但没删除的容器。第二个是容器日志:/var/log/containers/ 下每个容器的 json 日志,没有配上限的话一个狂刷日志的容器能写满磁盘,du -sh /var/log/containers | sort 或者直接看 /var/lib/docker/containers 下各容器的 log 文件大小,一眼定位。

根因:无清理策略的镜像层堆积 + 容器 json-file 日志没有配 max-size 上限,两个"只会涨不会缩"的目录吃掉磁盘。 解决:清理悬空镜像和已退出容器(docker/crictl 的 prune 系列,注意别清掉在用镜像);给容器日志配置驱动上限——docker 的 daemon.json 里 log-driver json-file 加 log-opts max-size/max-file,K8s 场景由 kubelet 的容器日志配置统一管。 预防:镜像清理进 crontab 巡检;日志上限作为容器运行时标准配置(部署前就配好,不是出事再配);磁盘水位 80% 告警提前响应。

面试讲法(STAR 完整版,约 270 字): "我处理过类似的"口径,容器环境的磁盘问题和传统环境不同,凶手藏的位置不一样。现象:容器宿主机磁盘告警,但上去一看业务数据和系统日志都不大——这时候就要往容器的"地盘"查。我按两个固定位置排查:一是运行时数据目录,docker system df 统计镜像、容器、卷的占用,发现悬空镜像和反复构建留下的废弃层堆了几十 G——构建了没打 tag 的中间层镜像环境里特别常见;二是 /var/log/containers 的容器 json 日志,du 一看,一个调试期狂刷日志的容器写出了好几个 G——默认的 json-file 日志驱动没有上限,容器活多久它就能写多大。处理:prune 清理悬空镜像和退出容器,立即释放;根治是给日志配 max-size 和 max-file 上限,并把镜像清理写进巡检脚本。预防上这条要前置:日志上限应该是容器运行时的标准配置,部署时就配好。我的总结一句话:容器环境的磁盘管理要盯"两个只涨不缩的目录"——镜像层和容器日志,都要配上限加定期清理。


14.19 面试官最爱追问的 8 个通用问题(案例章必背) ​

  1. "讲一个你印象最深的故障" → 首选 14.10 证书 SAN(真实 + 技术含量高 + 有反思),次选 14.7 NotReady(真实 + 有标准动作沉淀)。
  2. "故障时你先做什么?" → 先止损:有备切换、可扩先扩、影响大先摘流量,同步通报——绝不业务陪着排查。
  3. "你怎么定位根因的?" → 三板斧:监控看故障时刻曲线、日志看报错证据、变更记录问"最近改了什么"(60% 故障来自变更)。
  4. "这次故障你的责任是什么?" → 主动担责 + 讲改进(把坑变成检查项/规范),不甩锅不说"不是我干的"。
  5. "怎么保证不再发生?" → 复盘四件套:根因改进、监控补盲(加告警)、流程固化(SOP/检查清单)、演练验证。
  6. "多久恢复的?怎么衡量影响?" → 讲时间线(发现→止损→恢复→根因确认),影响面用"哪些业务、多少用户、多长时间"概括,数字要克制可信。
  7. "如果当时没有备份呢?" → 如实说止损手段(停写入、找数据残留、降级运行),再讲事后补齐的备份体系——考察的是应急思维不是标准答案。
  8. "这些故障都是你一个人处理的吗?" → 银行项目讲"一线我处理、疑难协同华为原厂";云项目讲"我主导、开发配合"——协同口径真实且加分。

14.20 章末自测清单 ​

  1. 故障处理第一优先级? → 止损恢复业务,不是找根因。
  2. CPU 高三部曲? → uptime 对比核数 → top 按 P → top -Hp 看线程。
  3. wa 高说明什么? → IO 等待高,问题在磁盘不在 CPU。
  4. OOM 的第一证据命令? → dmesg | grep -i "out of memory"。
  5. df -h 没满但报 no space? → df -i 查 inode 用尽。
  6. 删了日志 df 没降? → 进程还持有句柄,lsof | grep deleted,重启进程或 truncate。
  7. 502 和 504 一句话区别? → 502 后端连不上/挂了,504 后端连上了但超时。
  8. 节点 NotReady 第一排查点? → CNI Pod 状态,90% 是镜像拉取失败。
  9. Secret 案例的根因? → 密码随机生成含反斜杠转义丢位+异常处理吞错,卷内容为空。
  10. 证书 SAN 案例三步解决? → 补 certSANs → 移走旧证书重新签发 → SAN 回写配置。
  11. etcd Pod 命名规则? → etcd-<节点主机名>,无 kube- 前缀。
  12. 认证时好时坏先查什么? → 节点时间同步(chrony/timedatectl)。
  13. 脑裂怎么确认? → 两台都 ip addr 绑着 VIP。
  14. 防脑裂四招? → 检测真实端口脚本、priority 拉开、通告链路保障、上线演练。
  15. 雪崩/击穿/穿透区别? → 批量同时失效/热点单 key 失效/查不存在数据。
  16. rm -rf 后第一动作? → 停服务停止写入,再判断重建或备份恢复。
  17. 备份的终极原则? → 3-2-1 原则 + 必须做过恢复演练。
  18. SSH 慢最常见根因? → sshd 的 UseDNS 反向解析在内网等超时,UseDNS no 即解。
  19. CrashLoopBackOff 排查三步? → describe 看事件 → logs --previous 看崩溃前日志 → 退出码分方向(137=OOM)。
  20. 容器磁盘两大凶手? → 悬空镜像层堆积 + json-file 容器日志无 max-size 上限。

14.21 本章使用红线(面试前再读一遍) ​

  1. 来源口径不混:【真实项目】的四个案例(NotReady、证书 SAN、etcd 命名、时间同步)放开讲细节;【经典故障】用"我处理过类似的"口径;【课程项目】(慢 SQL)主动说明课程实验 + 生产配套。讲错口径比讲不出更伤。
  2. 每个案例的第一句话永远是框架句:"先止损、再定位、后复盘"——这是面试官判断你有没有生产素养的第一个信号。
  3. 数字克制:恢复时长、影响面只讲有把握的数,宁可少说不虚报——追一句"这个数字怎么统计的"就露馅。
  4. 命令要讲"为什么":被追问时每条命令都能说出"我用它排除/确认了什么"——只报名词不讲判断依据,等于背书。
  5. 复盘收尾:每个案例最后一句落在"沉淀了什么"——检查项、规范、告警、清单,这是我全部项目经历里最有辨识度的习惯。