容器故障排查最大的问题通常不是命令不够多,而是排查顺序混乱。很多人遇到容器异常会第一时间进入容器翻日志,但如果容器根本没能正常启动,当前日志可能一片空白;如果只盯着应用报错,又可能忽略节点资源耗尽。黄金三步法把定位过程拆成查看运行状态、对齐日志指标、进入容器验证三个环节,分别回答容器处于什么状态、异常从什么时间开始、内部环境到底哪里不对。它适用于Kubernetes、Docker以及containerd等常见容器运行时。

第一步:从运行状态和事件中锁定异常类型
容器故障往往先表现为状态异常。在Kubernetes环境里,Pod可能处于Pending、CrashLoopBackOff、ImagePullBackOff、Error等状态;在Docker环境里,容器可能处于created、restarting、exited、paused等状态。状态本身不是最终结论,而是排查方向的入口。例如CrashLoopBackOff表示容器启动后进程很快退出,这与镜像拉不下来是两类完全不同的问题;如果直接去查镜像仓库连通性,就会浪费大量时间。因此第一步应该先查看当前状态和最近事件,而不是急着进入容器或翻应用日志。
常用命令如下:
kubectl get pods -n default -o wide
kubectl describe pod <pod-name>
docker ps -a --format "table {{.ID}}\t{{.Status}}\t{{.Names}}"
在kubectl describe的输出中,Events部分往往最先暴露原因。例如FailedScheduling提示资源不足或节点选择器不匹配,Failed to pull image提示镜像名称错误或仓库认证失败,Back-off restarting failed container提示容器启动后立刻退出。对照ExitCode也能进一步缩小范围:退出码1通常表示应用自身逻辑错误,137往往与OOMKilled或SIGKILL有关,143则通常是收到SIGTERM后退出。把这些字段和事件连起来看,就能把故障快速分成调度失败、镜像问题、启动失败、运行中崩溃等几类。
还需要注意容器运行时层面的信息。如果Kubernetes底层使用containerd或CRI-O,可以执行crictl ps -a和crictl inspect查看容器退出原因。容器层面记录的原因可能比Pod事件更贴近进程真实行为。第一步的目标不是马上定位根因,而是正确分类,避免在错误方向上持续投入。
第二步:拉取日志和指标,把异常时间线对齐
确认容器属于哪一类故障后,再进入日志环节。Kubernetes中使用kubectl logs查看日志时,如果Pod内有多个容器,必须用-c指定容器名;如果容器已经崩溃重启,当前容器的日志可能为空或者只有启动阶段几行输出,这时要用--previous参数拉取上一次实例的日志。Docker用户可以使用docker logs,containerd环境则使用crictl logs。日志命令看起来简单,但少一个参数就可能漏掉关键信息。
kubectl logs <pod-name> -c <container-name> --tail=200 kubectl logs <pod-name> -c <container-name> --previous --tail=200 docker logs --tail 200 --timestamps <container-name> crictl logs --tail 200 <container-id>
拉日志更重要的动作是把时间线对齐。容器启动时间、应用初始化耗时、健康检查失败时间、重启时间,这些时间点需要和日志中的ERROR、WARN对应起来。例如Pod事件显示12:03:22探针失败,应用日志在12:03:20打出连接数据库超时,就可以基本确定探针失败是数据库问题的结果,而不是独立故障。反过来,如果先看到大量业务超时,再通过指标发现CPU在几分钟前已经打满,就应该把时间线再往前推。使用--timestamps和--since参数可以让日志具备更好的时间维度。
指标信息同样不能忽略。kubectl top pod可以查看Pod当前CPU和内存消耗,docker stats可以查看单机容器资源变化。如果内存曲线在一段时间内持续上升直到接近limit,随后容器被OOMKilled,应用日志可能只留下一句Killed。此外,磁盘空间耗尽、inode耗尽、文件句柄不足等问题很难从CPU和内存指标中发现,往往需要结合节点级命令或者进入容器进一步确认。把日志与指标放在同一条时间线上观察,是避免被表象误导的关键。
第三步:进入容器做交互式验证,确认根因
状态和日志能把排查范围缩到较小区域,但很多配置类问题必须进入容器验证。DNS解析失败、挂载目录只读、依赖服务端口不通、用户权限不足、环境变量缺失,这些现象在日志中可能只表现为connection refused或permission denied,单看日志很难判断真正原因。进入容器后先检查基础信息,比继续猜测更有效。
kubectl exec -it <pod-name> -c <container-name> -- /bin/sh docker exec -it <container-name> /bin/bash id env pwd df -h cat /etc/resolv.conf
网络类故障非常适合在容器内部验证。先确认DNS是否能正常解析,再检查TCP连接是否可达。如果容器内没有ping、curl、nc等工具,需要根据镜像类型临时安装,或者使用替代命令。解析正常但连接失败,通常说明目标服务未监听、网络策略拦截或端口映射错误;解析失败则要检查/etc/resolv.conf、CoreDNS或宿主DNS配置。检查服务连通性时不要只看能不能通,还要拿到明确的失败阶段。
镜像问题与运行环境问题也要区分开。进入容器后如果发现基础命令缺失、时区不对、CA证书未安装、字符集异常,说明是镜像构建不完整,应该修改Dockerfile而不是调整部署配置。如果容器内环境变量、文件权限、挂载目录都正常,但外部请求仍然失败,就需要回到节点网络命名空间检查iptables、路由和Service规则,可以使用nsenter进入Pod网络命名空间继续排查。黄金三步法不是机械地执行几个命令,而是通过状态、日志、容器内验证形成闭环,把故障定位到最可能的根因,再进入修复环节。