面向 P6-P7+ 工程师 框架训练型 · 长文 约 9,500–10,500 字 信息截止 2026-08

K8s 简单运维实战:
从 CrashLoop 告警到可复述的值班 SOP

这不是又一份 kubectl 命令速查,而是给已有资源模型基础、开始承担值班或 SRE 职责的工程师一套可复用框架: 日志怎么采、监控告什么、故障 Pod 按什么顺序查、日常扩缩与节点维护如何不踩坑,以及何时该继续调参、何时该换观测方案。

主线风格:框架训练 60% + 问题现场 40% 版本假设:Kubernetes 1.28+ 证据等级:官方文档优先,标注推断与生产经验
问题现场 · 复合场景

1凌晨两点的 CrashLoop:为什么 delete pod 救不了你

复合场景 · 综合多家团队值班模式的典型对话,非指代具体单一事件 TYPICAL SCENARIO

监控群弹出:order-service 命名空间下 Deployment payment-api 的 Pod 处于 CrashLoopBackOff,十五分钟内重启七次。值班同学第一反应是 kubectl delete pod 强制重建,但新 Pod 仍在三十秒内再次崩溃。 业务方追问「到底能不能恢复」,日志平台却搜不到该 Pod 的任何输出——服务刚上线, 日志采集 Agent 尚未覆盖该命名空间。与此同时 Alertmanager 还挤进十余条「副本不足」告警, 现场变成「重启、搜日志、被告警淹没」的并行混乱。

上述为复合场景,但它把生产里反复出现的三件事拧在了一起:

  • 对象红灯:CrashLoop / OOMKilled / Pending 等状态需要按分支排查,而不是统一「删了重来」。
  • 观测断链:本地 kubectl logs 有输出、集中日志无记录时,排障链路在第一步就断了。
  • 缺少模板:没有 describe → logs --previous → 根因假设的标准路径,值班时间被情绪驱动。

T16 讲清了 Pod / Deployment / Service 等资源模型,T17 聚焦配额、探针与优雅停机等稳定性配置; 本篇 T18 回答另一半问题:资源已经跑起来之后,日常如何运维、如何排障、如何建立可观测性基线。 风格上采用框架训练为主:日志方案选型、监控指标清单、kubectl 排障决策树、巡检清单均可直接贴进 Wiki; 辅以问题现场:用 CrashLoopBackOff、ImagePullBackOff、Pending、节点 DiskPressure 等状态串联实操命令。

与纯理论分享不同,本篇强调「可复述步骤」:听完后应能在十分钟内对任意 CrashLoop Pod 完成 describe → logs --previous → 给出根因假设,而不是只记得几个零散子命令。 文中「机制共识」来自 Kubernetes 官方文档与社区广泛验证的行为;「作者经验总结 / 推断」来自复合场景推演与常见值班模式,落地时请结合本集群实际调整。 第八章给出可嵌入 Runbook 的 SOP 与巡检清单,第九章收束为决策矩阵与相邻知识地图。

常见误区

kubectl delete pod 当成万能修复。Events 里往往已经写明 FailedScheduling、FailedMount、OOMKilled 或 Probe 失败; 跳过 describe 直接删,只会陷入「删了再起、起了再崩」的循环,并抹掉排查现场。

读者对象不是「第一次听说 kubectl」的新手,而是已经能提交工作负载、却在告警响起时缺少稳定排查路径的工程师。 若你仍需要逐字段解释 Deployment 与 Service 的关系,建议先完成 T16;若你已经写过探针与 limit 却解释不清「为何重启七次仍无日志」,本文就是为你准备的。

还可以把凌晨现场翻译成三个可验证问题。第一,Events 里最近的 Warning 是否已经指出 OOMKilled、FailedScheduling 或镜像拉取失败? 若是,问题在对象层,优先 describe,而不是先打开业务代码。第二,本地 kubectl logs 与集中日志平台是否同时有输出? 若本地有、平台无,优先修采集,而不是怀疑应用「没打日志」。第三,告警风暴是否能按 namespace 与变更窗口折叠? 若不能,先治理 Alertmanager,再谈单点根因。三个问题答清,值班会议才会从情绪升级变成证据升级。 分享讨论环节可准备一份脱敏的 CrashLoop 现场(含 describe 与 --previous 日志),对照第五章决策树走一遍,比纯讲幻灯片更容易形成团队共识。

体系总览 · 概念地图

2运维闭环地图:观测、归因、变更、巡检

日常 K8s 运维不是一串孤立命令,而是一条闭环:信号进来 → 定位层 → 执行变更 → 验证恢复 → 沉淀防复发。 信号来自日志、指标与事件;定位层决定你改应用、改采集、改配额还是改节点;变更必须可回滚;巡检把「偶然救火」变成「系统免疫」。 下图把闭环摊开,后文按日志、监控、排障、日常运维四条机制线展开。

图 1 · K8s 日常运维闭环与信号分层
自制示意图
信号层(先分清红灯来自哪一类) 日志 stdout / 文件 / 集中检索 指标 CPU / 内存 / 重启 / 副本 事件 Events / Conditions 链路 Trace(见 T14) 归因与动作层 describe / logs 状态分支决策树 exec / debug 进容器验证假设 scale / rollout 扩缩与回滚 cordon / drain 节点维护 防复发:Runbook + 告警抑制分组 + 巡检清单 + 事故复盘字段 救火结束不等于运维结束;没有沉淀,同一红灯会按周期回来 先分信号层,再选动作层;禁止在未分类的告警风暴里平行开三场战争
关键点:日志回答「发生了什么」,指标回答「有多严重、趋势如何」,事件回答「控制器怎么解释」,链路回答「责任服务在哪」。值班时先选信号,再进决策树。
来源:Kubernetes · Logging Architecture / Cluster Monitoring(logging · resource-metrics-pipeline)。版本假设 1.28+。

本篇与相邻篇的分工

任务回答的问题本篇如何衔接
T16 核心资源对象是什么、如何关联排障时用对象模型读懂 Status / Endpoints
T17 生产稳定性配额 / 探针 / 优雅停机怎么配现象反推配置缺口(Probe 失败、OOMKilled)
T18 运维实战(本篇)值班怎么查、日常怎么巡给出命令模板、SOP、巡检与决策矩阵
T10 / T14JVM 容器适配 / 全链路追踪OOM 与慢接口深入时下钻相邻篇

从组织语言看,很多事故复盘写成「K8s 不稳定」,至少要拆成:采集盲区、告警设计失败、应用启动失败、节点压力驱逐、控制面故障。 前几类对应不同对象与不同修复动作。把复盘标题写精确,是运维判断力的一部分。

声明式系统带来的心智转变是:你描述期望状态,控制器与 kubelet 持续收敛;运维动作若与控制器打架,就会出现「你删掉的 Pod 被立刻补回、 你手工改的字段被 GitOps 同步覆盖」。因此本篇强调的不是「更强的命令行技巧」,而是「在正确层级使用正确工具」: 应用故障用日志与版本回滚;采集故障用 Agent 与规则;容量故障用 Quota 与节点;节点故障用 cordon / drain。 后文四章(日志、监控、排障、日常运维)按「机制解释 → 可复用模板 → 边界」展开,比例上框架训练约占六成、问题现场约占四成,与 execution-plan 中 T18 路由一致。

核心机制 · 日志

3日志收集:DaemonSet、Sidecar 与应用直推

容器 stdout / stderr 是应用日志的默认出口。kubelet 把容器日志写入节点本地(通常位于 /var/log/pods/),并通过 kubectl logs 暴露给运维人员。 但本地日志随 Pod 删除或节点故障而丢失——生产环境必须将日志持久化到集中存储,才能支撑跨 Pod、跨节点的检索与告警关联。

已核验事实

Kubernetes 官方 Logging Architecture 明确:集群本身不提供完整的集中日志解决方案;常见做法是节点级 Agent、 Sidecar,或应用直接推送到后端。Pod 删除后,除非已被采集到集群外,否则节点本地日志不可当作可靠审计源。

图 2 · 日志采集三条路径与汇聚点
自制示意图
业务 Pod 应用容器 stdout/stderr Sidecar Agent(可选) Worker 节点 kubelet → /var/log/pods DaemonSet Agent 应用直推 SDK / OTLP 绕过节点 Agent 集中存储:Elasticsearch / Loki / 云日志 统一标签:namespace / pod / container / app / node 检索平台(Kibana / Grafana)← 告警里的标签一键过滤 排障价值在「能过滤」,不在「能存」
读图:大多数生产集群默认走 DaemonSet;文件日志与多租户强隔离才上 Sidecar;直推适合结构化程度高、愿承担业务侧耦合的新服务。
来源:Kubernetes · Logging Architecture(kubernetes.io/.../logging);Fluent Bit Kubernetes 过滤与 DaemonSet 部署说明。

三种主流采集架构对比

模式部署方式优点缺点适用场景
节点级 DaemonSet 每节点一个 Agent(Fluent Bit / Filebeat / Promtail) 对业务零侵入;统一采集;成本按节点分摊 多租户隔离弱;升级需滚动;特殊格式需统一解析 大多数生产集群默认选择
Sidecar 容器 与业务同 Pod,共享 emptyDir 或日志卷 按应用定制解析;多租户隔离好;可采文件日志 每 Pod 多一容器;Sidecar 故障可能影响状态 遗留写文件日志、多事业部路由不同后端
应用直推 SDK / API 直写远端 结构化高;可携带 TraceId 与语言耦合;网络抖动可能丢日志或拖慢业务 强格式约束的新服务,配合 OpenTelemetry

DaemonSet 落地要点

以 Fluent Bit 为例,DaemonSet 通常挂载 /var/log/containers/var/log/pods 以及运行时对应目录。K8s 1.28+ 集群确认 containerd 后,应使用 CRI 日志格式解析器,避免仍按 Docker JSON 解析导致字段缺失。 多行堆栈(Java Exception、Go panic)必须配置 multiline,否则堆栈拆散后几乎无法阅读——这也是 Sidecar 的隐性优势:按语言定制规则不影响其他服务。

# Fluent Bit DaemonSet 关键挂载片段(示意,K8s 1.28+ / containerd)
volumeMounts:
  - name: varlog
    mountPath: /var/log
  - name: varlibdockercontainers
    mountPath: /var/lib/docker/containers
    readOnly: true
volumes:
  - name: varlog
    hostPath:
      path: /var/log
  - name: varlibdockercontainers
    hostPath:
      path: /var/lib/docker/containers
生产经验

新命名空间上线后忘记在采集规则中加入该 namespace,会导致「Pod 在跑但日志平台搜不到」——排障时误以为应用无输出。 上线 checklist 必须包含「日志可检索验证」:用 kubectl logs 与日志平台双向核对。

日志规范与成本(作者经验)

  • 优先写 stdout/stderr,JSON 结构化,便于 Loki / ES 字段检索。
  • 每条日志携带 trace_id / request_id,与 T14 链路追踪联动。
  • 控制单条体积;配置 kubelet containerLogMaxSize / containerLogMaxFiles 防磁盘打满。
  • 热数据 7~14 天、温数据约 30 天、其后归档或删除——生命周期在 ES ILM / Loki retention 配置,不在 K8s 本体。

某次复合场景排查中,单个 Verbose 级别的 Deployment 占集群日志写入量约四成,清理后存储成本明显下降。 平台团队应每月 review Top 日志量 namespace,推动应用侧收敛生产 debug 输出。

日志检索与排障联动

集中日志的价值不在「能存」,而在「排障时能快速过滤」。无论后端是 Elasticsearch 还是 Loki,建议统一标签维度并与 K8s 元数据自动对齐: namespacepodcontainer 由采集 Agent 从 CRI 元数据注入; app / version 来自 Pod label;node 用于定位磁盘或网络类节点问题。 在 Loki 中典型查询形如按 namespace 与 pod 前缀过滤后再匹配 ERROR;在 Kibana 中则对 pod 名字段做通配。 若团队尚未建立统一 Dashboard,至少应在 Runbook 写明:收到 Pod 告警后,复制 namespace 与 pod 标签到日志平台查询模板, 避免值班现场临时摸索字段名。这是「观测断链」类事故中成本最低、收益最高的补丁。

Sidecar 何时值得用,可以再压成两条判断标准。第一,应用是否把关键审计日志写进容器内文件而非 stdout——若是,DaemonSet 无法自动采集,必须共享卷。 第二,同一集群是否存在「多事业部、日志必须路由到不同后端」的硬约束——在 Sidecar 层打 tenant 标签,往往比在节点 Agent 写复杂路由更清晰、更可审计。 反过来,若所有服务已统一 JSON 到 stdout,且平台能接受统一解析规则,就不要为「看起来更灵活」而全面上 Sidecar,否则调度密度与资源账单会无声上涨。

核心机制 · 监控

4监控接入:核心指标、告警规则与判读顺序

日志回答「发生了什么」,监控回答「有多严重、趋势如何」。运维基线通常由 Prometheus + Alertmanager(或云托管方案)实现, 采集对象分为集群组件、节点、Pod / 工作负载三层。kubectl top 依赖 metrics-server,适合现场快照; Prometheus 负责历史趋势与自动化告警——两者互补,不可互相替代。

图 3 · 监控采集层与告警行动链
自制示意图
采集源 cAdvisor / kubelet 容器资源用量 kube-state-metrics 对象状态与重启 node-exporter 节点磁盘 / 内存 metrics-server kubectl top 快照 Prometheus Alertmanager 告警必须可行动:severity + 抑制分组 + annotation 含 namespace/pod + Runbook 链接 风暴判读顺序:控制面 → 节点 → 最近变更 → 单 Pod 决策树 group_by: [alertname, namespace] 把「十个 CrashLoop」合成一条通知
关键点:指标源齐全不等于可运维;没有可行动告警与 Runbook,监控只是漂亮的大屏。
来源:Kubernetes · Resource metrics pipeline(resource-metrics-pipeline);Prometheus / kube-state-metrics 项目文档。

必采核心指标

层次指标Prometheus 来源示例告警意义
PodCPU 使用率(相对 limit)container_cpu_usage_seconds_total持续逼近 limit 预示节流或需扩容
Pod内存 working setcontainer_memory_working_set_bytes接近 limit 可能 OOMKilled(联动 T17)
Pod重启次数kube_pod_container_status_restarts_total短窗内多次重启触发 CrashLoop 告警
Pod就绪状态kube_pod_status_readyReady=0 持续说明流量可能未接入
Deployment可用 vs 期望副本kube_deployment_status_replicas_availableavailable < desired 触发副本不足
NodeReady / 压力条件kube_node_status_conditionNotReady / DiskPressure 影响调度

告警规则设计原则

  1. 可行动:每条告警对应明确的第一排查命令,避免无上下文的「CPU 高」。
  2. 分级:P1 全站 / 核心交易;P2 单服务降级;P3 有冗余的副本不足;P4 趋势预警。
  3. 抑制与分组:同一 Deployment 下多个 CrashLoop 应合并为一条。
  4. Runbook 链接:annotation 嵌入本篇 SOP 或值班手册章节号。
# Pod 频繁重启告警示例(kube-state-metrics)
groups:
  - name: k8s-pod-health
    rules:
      - alert: PodCrashLooping
        expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
        for: 5m
        labels:
          severity: P2
        annotations:
          summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 短窗内重启过多"
          runbook: "执行 kubectl describe pod + kubectl logs --previous"
作者推断

告警风暴下的判读顺序建议为:控制面(apiserver / etcd)→ 节点 NotReady / DiskPressure → 最近三十分钟变更(发布、ConfigMap、drain)→ 再下钻单 Pod。时间相关性往往是最强信号; 先修控制面或节点,可熄灭一大片「假性」工作负载告警。

Grafana 最小 Dashboard 集

不必一开始追求完美大屏。集群概览、Namespace 资源、Deployment 健康、节点资源四块即可覆盖八成值班需求。 Dashboard 变量预置 namespace 下拉,用 label_values(kube_pod_info, namespace) 动态填充, 避免值班现场临时改 PromQL。最低限度:告警通知包含 namespacepodcontainer, 复制即可执行 kubectl logs;Panel 能链到 Loki 过滤则闭环更短。

metrics-server 与历史趋势的分工

kubectl top podkubectl top node 依赖 metrics-server,它从 kubelet 汇总 CPU / 内存瞬时用量, 是值班同学最快的人工判读手段——无需打开 Grafana 即可确认「哪个 Pod 在吃内存」。安装时需保证 kubelet 指标端点可用、 证书策略与 metrics-server 参数一致,并为 metrics-server 本身配置 request/limit,避免它成为单点资源黑洞。 必须强调:top 显示的是当前用量,不能替代 Prometheus 的历史趋势与告警。两者分工是:top 用于排障现场快照, Prometheus 用于七乘二十四小时自动化监控。把「看了一眼 top 正常」当成「过去一小时没有尖刺」,是常见误判。

控制面监控经常被忽略:etcd 与 apiserver 故障会导致「数据面看起来正常但无法调度」的盲区。 即便工作负载面板全绿,也应在集群概览中保留控制面组件状态。kube-prometheus-stack 一类方案可以快速铺开, 但生产仍需单独评估控制面覆盖是否足够,以及 Alertmanager 的分组与抑制是否已按命名空间落地——否则你会得到「指标很多、仍然不可值班」的系统。

复合场景:告警风暴下的四步收敛

某次发布窗口后,Alertmanager 在两分钟内涌入数十条告警:多个 Pod CrashLoop、若干 Deployment 副本不足、个别节点 CPU 高。 若无分组策略,值班同学容易迷失。推荐判读顺序(作者经验总结):先看控制面是否正常;再看节点是否 NotReady 或 DiskPressure; 然后看最近三十分钟是否有发布、ConfigMap 变更、节点 drain——时间相关性是排障最强信号;最后才下钻单个 Pod 执行第五章决策树。 配置 group_by 将同类告警合并,并在 annotation 注明影响 Pod 数量,能显著降低「被数量吓到却不知是否同一根因」的概率。

核心机制 · 排障

5故障 Pod 排查:describe / logs / exec 决策树

这是本篇的核心框架。无论 Pod 处于何种异常状态,排查顺序遵循不变量: 先看状态、再看事件、再读日志、最后进容器验证。 Events 往往已写明根因;跳过 describe 直接 delete,是最高频的反模式。

图 4 · 故障 Pod 状态分支决策树
自制示意图
get pod -o wide → describe(必经) 按 Status / Reason 分支 Pending 调度 / Quota / PVC CrashLoop logs --previous Not Ready Readiness / 端口 ImagePull 仓库 / Secrets Evicted 节点压力 describe nodes Quota / PVC OOM / Exit Code 配置 / 依赖 / 探针 logs + exec curl 探针路径验证 Events HTTP 码 修 tag / 凭证 describe node 清盘 / 迁移 可选加深:kubectl exec / kubectl debug(ephemeral) 记录根因 → 更新 Runbook → 需要时联动 T17 配置复查或 T10 JVM 参数 多副本:先分「个别异常」还是「全部异常」;仅新 RS 失败优先 rollout undo
不变量:describe 是所有分支的必经节点;CrashLoop 优先 --previous;能进容器再 exec,进不去用 ephemeral debug。

三板斧命令模板

# 第一步:状态与事件(永远从这里开始)
kubectl get pod -n order-service -o wide
kubectl describe pod payment-api-7d8f9c-xk2lm -n order-service

# 第二步:当前与上一个实例日志
kubectl logs payment-api-7d8f9c-xk2lm -n order-service -c payment-api
kubectl logs payment-api-7d8f9c-xk2lm -n order-service -c payment-api --previous

# 第三步:exec / ephemeral debug(K8s 1.28+)
kubectl exec -it payment-api-7d8f9c-xk2lm -n order-service -c payment-api -- sh
kubectl debug -it payment-api-7d8f9c-xk2lm -n order-service \
  --image=busybox:1.36 --target=payment-api -- sh

describe 重点看:Waiting Reason、Last State(OOMKilled / Error / Exit Code)、Events 最近 Warning、 Conditions 中 PodScheduled / Ready。CrashLoop 时当前容器可能尚未输出有效日志就退出, --previous 往往是唯一堆栈来源。多容器必须用 -c 指定;Init 卡在 Init:0/1 时日志要打在 init 容器名上。

已核验事实

Kubernetes 支持通过 ephemeral containers 调试运行中的 Pod(kubectl debug)。 调试容器用于排查,不应替代修复镜像或配置;深度需要共享挂载时,可使用官方文档所述的副本调试流程(如 --copy-to)。

典型状态速查表

状态 / Reason常见根因首选命令处置方向
Pending资源不足、选择器不匹配、PVC 未绑定、Quota 耗尽describe pod + describe nodes扩容、调 request、修 PVC
CrashLoopBackOff启动失败、配置错误、依赖不可达、探针误杀logs --previous + describe修配置/代码;调探针启动窗
ImagePullBackOff镜像名错、凭证过期、网络不通describe(Events 有 HTTP 码)更新 Secrets、确认 tag
Running 0/1 ReadyReadiness 失败、未监听端口describe + logs + exec curl修探针或等待启动
OOMKilledlimit 过低或泄漏Last State + 内存曲线调 limit / 修泄漏;联动 T10
Evicted节点磁盘 / 内存压力describe pod + describe node清盘、调优先级、迁移
生产经验 · 复合场景复盘

回到第一章的 payment-api:若按 SOP 执行,describe 显示 Last State 为 OOMKilled, logs --previous 仅有 JVM 启动日志,监控显示 working set 迅速触及 512Mi limit。 根因是新版本未配置容器感知堆参数(见 T10),而非「K8s 本身故障」。 盲目 delete 无法解决,必须调 limit 或修 JVM 参数后重新发布。

多副本、滚动发布、RBAC 假异常

先区分个别 Pod 异常与全部异常:前者偏向节点或镜像层,后者偏向配置或代码变更。 仅新 ReplicaSet CrashLoop、旧副本正常时,优先 kubectl rollout undo 止损; 新旧均失败则检查 ConfigMap / Secret 变更时间线。Job / CronJob 失败实例可能被 GC, 需用字段选择器查找 Failed,或提高 ttlSecondsAfterFinished 保留现场。 若 describe 正常却无法 exec,先怀疑值班 RBAC,而不是升级紧急变更。

生产 Deployment 通常有多副本,命令上先用标签筛选并输出重启次数,避免「只盯着告警里的那一个 Pod 名」而漏掉同批失败。 滚动发布期间用 kubectl rollout status 观察进度:新旧 ReplicaSet 可能同时存在,状态混读是误判根因的常见来源。 Init Container 卡在 Init:CrashLoopBackOff 时主容器尚未启动,默认 kubectl logs 会为空,必须指定 init 容器名。 CronJob 连续失败时,除了看 Failed Pod,还要看 kubectl get cronjob 的最近调度时间与 Events,区分「没调度」与「调度了但跑挂」。

权限方面,建议为值班角色预置只读 get/list/watch 全部 Pod、log、events 的能力,exec 权限限定在非生产或需审批的通道。 「假异常」还有一类:Service 后端 Endpoints 为空,业务报错,但 Pod 看起来 Running——此时要回到 T16 的 Ready 与 Endpoints 机制, 结合 Readiness 探针与标签选择器排查,而不是在应用容器里反复重启。把「网络不通」写成复盘标题之前,先确认对象发现链是否完整。

# 多副本快速对照:名称 / 阶段 / 重启次数
kubectl get pod -l app=payment-api -n order-service \
  -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\t"}{.status.containerStatuses[0].restartCount}{"\n"}{end}'
kubectl rollout status deployment/payment-api -n order-service
# Init 容器日志
kubectl logs payment-api-xxx -n order-service -c init-db-migration
核心机制 · 日常运维

6扩缩容、节点维护与资源治理

排障解决当下问题,日常运维防止问题复发。平台负责节点与组件,应用负责 Deployment 与业务配置—— 分工清晰时,cordon / drain 与业务发布才不会互相踩脚。

图 5 · 节点维护:cordon → drain → 变更 → uncordon
自制示意图
1. cordon 不可调度 2. drain 尊重 PDB 3. 维护 内核 / 磁盘 / 下线 4. uncordon 恢复调度 drain 卡住常见原因:单副本无冗余、PDB minAvailable、emptyDir / 本地盘 Pod 先临时扩容或手动迁移,再继续 drain;联动 T17 PreStop 与 terminationGracePeriodSeconds
纪律:维护前先确认核心服务副本与 PDB;维护中同步值班交接「进行中变更」;维护后观察驱逐与重新调度是否收敛。

应用扩缩容

kubectl scale deployment payment-api -n order-service --replicas=5
kubectl get hpa -n order-service
kubectl describe hpa payment-api-hpa -n order-service

生产优先 HPA(CPU / 内存或自定义 QPS);手动 scale 用于应急或 HPA 未覆盖的服务。 缩容前确认 PDB 不会阻止必要下调。发布纪律:变更走 GitOps / CI,避免无审计的 kubectl edit;发布后观察十五分钟重启率与错误日志;保留 kubectl rollout undo 能力。

节点维护命令

kubectl cordon worker-node-03
kubectl drain worker-node-03 --ignore-daemonsets --delete-emptydir-data --grace-period=120
# 维护完成后
kubectl uncordon worker-node-03

常用命令与僵尸资源清理

场景命令说明
资源消耗 Topkubectl top pod -A --sort-by=memory需 metrics-server
节点余量kubectl describe nodes 看 Allocated判断能否调度
扫 Warningkubectl get events -n ns --sort-by='.lastTimestamp'快速时间线
强制删 Terminating--grace-period=0 --force最后手段;先查卡住原因
清理 Failedkubectl get pod -A --field-selector=status.phase=Failed降噪与减 etcd 负担

长期集群会积累 Completed Job、Evicted Pod、孤儿 ReplicaSet、无引用 ConfigMap / Secret。 建议每季度做 namespace audit;下线服务走「缩容 → 删 Ingress/Service → 观察 → 再删 ns」, 禁止习惯性 kubectl delete ns。本篇与 T17 的协同:T17 教「怎么配」,T18 教「配错了如何从现象反推」—— describe 发现 Probe 失败时,对照 YAML 中 initialDelaySeconds 是否短于真实启动时间。

常见误区

把 force delete 当日常手段,或在未确认 PDB / 单副本风险时强行 drain。 前者掩盖 kubelet / 最终器问题,后者可能把核心服务打到零副本。

变更纪律与资源审计

生产变更走 GitOps 或 CI/CD,避免直接编辑线上对象导致无审计、难回滚。预发命名空间应用相同镜像与配置做验证; 重大变更窗口配合 PDB,确保至少保留约定数量的可用副本。导出 Deployment YAML 作为变更前快照,是低成本的自我保护。 资源清理方面,可用字段选择器列出 Failed Pod,用 JSON 查询确认某 ConfigMap 仍被哪些 Pod 引用,再决定删除—— 「看起来没人用」不等于「真的没人用」。已下线服务的命名空间应保留观察期,再执行删除,防止误伤共享密钥或网络策略。

日常运维排障中大量问题可追溯至 T17 所述配置缺失:无 readiness 导致流量打到未就绪 Pod、无 preStop 导致发布五零二、 limit 过低导致 OOMKilled。运维 SOP 应内嵌「配置检查」环节:看到探针失败,不仅查应用日志,还要对照 Deployment 中 探针参数是否短于真实启动时间。平台与应用的交接班,除了同步告警,还应同步「半完成的 drain」与「进行中的发布」, 这是减少人为二次事故的最便宜措施。

边界判断 · 适合与不适合

7这套运维框架适合什么,不适合什么

本篇框架假设:集群已具备基本可调度性,团队能使用 kubectl 与集中日志 / 指标中的至少一种, 且愿意把 Runbook 写进 Wiki。它不试图覆盖服务网格深水区、多集群联邦或自研控制面排障。

适合

  • 中小到中大型单集群 / 少量集群的应用与平台联合值班
  • 已有 Prometheus(或等价)与集中日志,需要统一排查模板
  • 故障以 CrashLoop、Pending、ImagePull、节点压力为主
  • 希望把「个人经验」沉淀为 SOP 与巡检清单

不适合(单独靠本篇不够)

  • 尚无任何集中观测,却指望「几条告警规则」解决问题
  • 控制面自身持续故障(需平台专项,而非应用侧决策树)
  • 深度性能剖析、内核级网络、服务网格策略调试
  • 把本篇 SOP 当成可以替代 T17 配置治理的借口
作者推断

若团队每周都被同一类 CrashLoop 叫醒,优先投资「配置门禁 + 日志可达性验收」,而不是再培训一遍 kubectl。 工具熟练度解决的是平均修复时间;配置与观测缺口解决的是事故发生率——两者不可混为一谈。

还可以用「投入回报」快速过滤是否采用本篇全套实践。若集群规模很小、服务个位数、且业务可接受较长恢复时间, 可以先落地第五章决策树与最小告警集,不必一次上齐所有巡检项。若已进入多团队共用集群、发布频繁、对可用性有明确承诺, 则日志可达性验收、告警分组、节点维护剧本与季度资源审计应视为准入项,而不是「有空再做」的优化项。 不适合的边界也要诚实:当你面对的是 etcd 损坏、证书大面积过期、网络插件全局故障时,应切换到平台事故通道, 而不是继续在应用命名空间里执行 describe——工具没错,层级选错了。

生产实践 · SOP

8排障 SOP、巡检清单与值班交接

以下表格可直接嵌入 Alertmanager Runbook 或值班手册。原则:现象 → 工具链 → 根因要点 → 处置 → 预防。

排障 SOP

故障现象排查工具链根因定位要点处置方案预防机制
CrashLoop,重启持续增加 get → describe → logs --previous → 内存/CPU 曲线 Last State Reason / Exit Code;Events 是否 Probe 失败 OOM 调 limit 或修泄漏;配置错误回滚;探针调启动窗 上线压测内存;liveness 宽限期;与 T17 联审
长期 Pending describe pod → nodes → resourcequota → pvc FailedScheduling 消息写明 CPU/内存或亲和性 扩容、降 request、修 selector、绑 PVC Quota 预警;调度失败告警;容量月度 review
服务可用但日志平台无输出 kubectl logs 对比平台 → Agent DaemonSet → 采集规则 本地有/平台无=采集问题;本地也无=未写 stdout 或缺 Sidecar 补规则 / Sidecar / Agent 权限 上线验收含日志可达;Agent 健康监控
available < desired get deploy → describe → get rs → Pod 状态 RS 是否创建;PDB / 选择器是否限制 修模板;临时 scale;检查 PDB 副本可用性告警;发布流水线健康检查
节点 NotReady,Pod Evicted describe node → events → kubelet / 磁盘 DiskPressure / MemoryPressure / kubelet 无响应 清盘、重启 kubelet、cordon+drain 迁移 节点资源告警;日志与镜像 GC;节点巡检

日常运维巡检清单

建议每日自动化 + 每周人工抽查。责任人列按团队 R&R 填写。

检查项通过条件频率责任人
控制面健康kube-system 中 apiserver / etcd / scheduler / controller-manager Running 且无持续重启每日平台 SRE
节点 ReadyReady 数=期望;NotReady 持续过短即升级每日平台 SRE
核心 Deployment标记核心的服务 available ≥ desired每日应用值班
Pod 重启率非发布窗 24h 内无异常高频重启每日应用值班
证书有效期控制面证书剩余充足(如 kubeadm certs check-expiration)每周平台 SRE
日志 AgentDaemonSet 就绪;抽检日志可检索每周平台 SRE
告警通路无长期未认领 firing;测试告警可达每周平台 SRE
ResourceQuota各 ns 使用率未长期顶满每周平台+应用
镜像凭证imagePullSecrets 有效;CI pull 无认证失败每月平台 SRE
etcd / PV 水位磁盘与 etcd 体积在安全区每周平台 SRE
备份演练etcd 备份成功;季度恢复演练有记录每月/季平台 SRE
新服务上线日志可达、Dashboard、告警、Runbook 齐全每次上线应用+SRE

值班交接与事故字段

  • 现象与影响范围(namespace、服务、时长)
  • 时间线(告警、介入、恢复)
  • 根因分类(应用 / 配置 / 平台 / 外部依赖)
  • 关键命令与日志平台链接(不必贴全文)
  • 改进项(告警、Runbook、配置、是否需 T17 复查)

交接班口头同步「未恢复告警」与「进行中变更(drain、发布)」,避免下一班重复操作或遗漏半完成的节点维护。

生产经验

SOP 与巡检清单应随事故复盘持续更新,而不是一次性文档。每关闭一个 P2 及以上故障,至少改一处: 告警表达式、Runbook 步骤,或上线验收项——否则同一复合场景会按季度重复出现。

把第八章落地时,建议分两周完成「最小可用」而不是追求一次写完美:第一周把 CrashLoop / Pending / 日志盲区三条 SOP 写进 Alertmanager annotation; 第二周把控制面、节点 Ready、核心 Deployment、日志 Agent 四项巡检做成自动查询或简单脚本。其余检查项按风险逐步补齐。 这样团队不会因为文档过重而弃用,又能在下一次复合场景中真正用上模板。巡检结果应能回答一个问题:我们是「偶然没出事」,还是「系统上已经挡住了上一类事故的复发路径」。

决策框架 · 收尾

9决策矩阵、相邻知识地图与延伸

K8s 运维判断力不是「记得更多子命令」,而是在观测是否完备、归因是否分层、变更是否可回滚、防复发是否落地 四条线上同时成立。遇到红灯时,用下表决定继续调参、迁移方案,还是先补齐相邻能力。

决策矩阵:继续 / 迁移 / 选型

信号 / 处境继续(调参 / 按 SOP)迁移(换模型)选型补充
CrashLoop,logs --previous 有明确应用错误 修配置 / 回滚版本 / 修依赖连通 若启动逻辑不可收敛,拆 Init / 预热 Job 对照 T17 探针是否误杀
OOMKilled,堆使用不高 上调 limit、查堆外与缓存 固定超大堆则评估专用节点池 / Guaranteed 联动 T10 MaxRAMPercentage
本地有日志、平台无输出 补 namespace 采集规则、修 Agent 文件日志为主则迁 Sidecar;强结构化迁直推 上线验收强制「双向核对」
告警风暴、同类重复轰炸 调整 for / 阈值、加抑制 按 alertname+namespace 分组;P1/P2 分流通道 annotation 强制带 Runbook
Pending / 调度失败频繁 扩节点、调 request、修亲和性 批流混部则拆命名空间与 Quota 容量规划进月度巡检
节点 DiskPressure 反复 Evict 清盘、调日志轮转、镜像 GC 日志量大则迁远端存储策略;节点规格升级 节点水位告警与每周巡检
仅新 RS 失败、旧副本正常 rollout undo 止损后查新镜像 发布模型改为金丝雀 / 分批 流水线增加发布后健康门禁
已核验事实

容器标准输出由 kubelet 管理并可被 kubectl logs 读取;集中式日志与完整监控栈不属于 Kubernetes 控制面的内建能力, 需另行部署节点 Agent、metrics 管道等组件。排障时「对象事件」与「应用日志」是两条独立证据链,缺一不可想当然地合并结论。

相邻知识地图

  • T16 K8s 核心资源理解:先建立 Pod / Deployment / Service 分层,再谈本篇排障分支。
  • T17 K8s 生产稳定性配置:配额、探针、优雅停机——本篇从现象反推这些配置缺口。
  • T10 容器化下 JVM 适配:OOMKilled 且堆未满时的深入参数。
  • T14 SkyWalking 全链路追踪:指标与日志定位到服务后,用 Trace 锁定置信区间。
  • T15 Docker 镜像工程化:ImagePull 与镜像体积、仓库凭证问题的上游治理。
  • T19 Kafka 高可靠:若你同时运维消息中间件,可把本篇 SOP 思维迁移到积压与消费故障。

要点沉淀

  • 日志:生产默认 DaemonSet;文件日志或多租户隔离用 Sidecar;新 namespace 必须验证可检索。
  • 监控:CPU / 内存 / 重启 / 副本可用性是最小告警集;告警必须可行动并链到 Runbook。
  • 排障:describe → logs(含 --previous)→ exec/debug 是不变顺序;按状态分支而非盲目重启。
  • 日常:扩缩容优先 HPA;节点维护 cordon + drain;变更可回滚、可审计。
  • 沉淀:SOP 与巡检清单随复盘更新;决策矩阵帮助在继续调参与换观测模型之间选型。

常见误区再收束四条,便于贴进新人值班培训首页:不要把删除 Pod 当万能修复;不要只监控 CPU 而忽略内存 working set; 不要部署一次日志 Agent 后永不审计命名空间覆盖;不要照搬社区告警阈值却不结合本集群规格与业务 SLA。 四条都破了,才会同时出现「重启循环、OOM 无预警、观测盲区、告警疲劳」——而这正是第一章复合场景的标准配方。

动手练习建议(约三十分钟):在测试集群故意部署 exit 1 镜像观察 CrashLoopBackOff,再部署低 memory limit 的压测镜像观察 OOMKilled, 逐步走通第五章决策树与第八章 SOP 的每一步。kubectl 肌肉记忆来自重复操作,而非只看分享稿。

最后回到第一章的复合场景:当 CrashLoop、日志盲区、告警风暴同时亮起时,不要平行开三场无重点的战争。 先用第五章分状态、用第三章验证采集是否覆盖、用第四章按控制面→节点→变更→单 Pod 收敛告警,再用决策矩阵选择「修应用 / 补观测 / 换方案」。 分层对了,改一个旋钮往往能熄灭两盏灯;分层错了,删再多 Pod 也只是把故障复制到更多时间片上。 这就是本篇相对 T16 / T17 的增量:对象模型告诉你「是什么」,稳定性配置告诉你「合同怎么写」,运维实战告诉你「红灯亮了按什么顺序关掉」。 把顺序写清楚,比半夜凭感觉重启更可辩护——运维判断力的终点不是命令更炫,而是同一类复合场景不再按周期叫醒整个值班群。