15.11.2 典型故障场景与排查思路

典型故障场景与排查思路需覆盖容器启动失败、服务不可用、性能劣化、网络异常与持久化故障等高频问题。排查总思路遵循“现象—影响面—最近变更—关键指标—最小复现”的链路,优先确认故障范围与业务影响,再回溯镜像版本、配置变更、发布记录与集群事件,最后通过最小化环境复现问题验证修复方案。

文章图片

常用命令速查(含解释):

# 容器状态与退出码
docker ps -a

# 容器详细配置与挂载
docker inspect <container_name_or_id>

# 查看容器日志(应用层)
docker logs --tail 200 -f <container_name_or_id>

# 容器事件(启动/停止/拉取等)
docker events --since 30m

# 资源消耗(CPU/内存/IO/网络)
docker stats

# 宿主机系统日志与内核事件
journalctl -u docker --since "30 min ago"
dmesg | tail -n 50

# 端口监听与网络状态
ss -lntp
ip a

1. 容器无法启动(ExitCode 非 0)#

典型原因:镜像缺失、入口命令错误、依赖未满足、端口冲突、权限不足。
排查示例

# 1) 查看容器退出码
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"

# 2) 拉取镜像失败的确认
docker pull registry.example.com/app:v1.2.3

# 3) 查看日志定位入口错误
docker logs <app_container>

# 4) 检查启动命令与环境变量
docker inspect <app_container> | jq '.[0].Config.Cmd,.[0].Config.Env'

# 5) 进入临时容器验证依赖
docker run --rm -it --entrypoint /bin/sh registry.example.com/app:v1.2.3
# 在容器内执行依赖检查
/opt/app/bin/app --version

最小复现建议:使用相同镜像与最小环境变量启动,逐步加入依赖配置。

2. 服务启动但不可访问#

典型原因:端口映射错误、容器内监听地址不对、宿主机防火墙拦截、网络模式错误。
排查示例

# 1) 映射端口核对
docker ps --format "table {{.Names}}\t{{.Ports}}"

# 2) 容器内检查监听地址
docker exec -it <app_container> sh -c "ss -lntp"

# 3) 宿主机防火墙检查(Ubuntu/Debian)
ufw status

# 4) 宿主机防火墙检查(CentOS/RHEL)
firewall-cmd --list-all

# 5) 容器内访问自检
docker exec -it <app_container> sh -c "curl -sS http://127.0.0.1:8080/health"

示例修复:应用监听 127.0.0.1 导致外部不可达,需改为 0.0.0.0。
应用配置示例(/opt/app/config.yaml):

server:
  host: 0.0.0.0
  port: 8080

重启容器生效:

docker restart <app_container>

3. 容器频繁重启#

典型原因:健康检查失败、依赖超时、资源限制过低或进程崩溃。
排查示例

# 查看重启策略与健康检查
docker inspect <app_container> | jq '.[0].HostConfig.RestartPolicy,.[0].Config.Healthcheck'

# 查看最近的重启事件
docker events --filter container=<app_container> --since 1h

# 查看资源限制与实际消耗
docker inspect <app_container> | jq '.[0].HostConfig.Memory,.[0].HostConfig.NanoCpus'
docker stats <app_container>

修复示例:提升内存限制并延长健康检查间隔:

docker run -d --name app \
  --memory=1g --cpus=1.0 \
  --health-cmd="curl -f http://127.0.0.1:8080/health || exit 1" \
  --health-interval=30s --health-retries=5 \
  registry.example.com/app:v1.2.3

4. 性能劣化(CPU/内存/IO/网络)#

排查思路:先定高消耗容器,再定位应用内部问题。
示例流程

# 1) 定位高消耗容器
docker stats --no-stream

# 2) 宿主机整体负载与IO
top -o %CPU
iostat -x 1 5
vmstat 1 5

# 3) 容器内应用慢查询/GC排查示例(以 Java 为例)
docker exec -it <java_container> sh -c "jstat -gcutil 1 5"
docker exec -it <java_container> sh -c "jstack 1 | head -n 50"

结论示例:IO 等待高 -> 将数据卷迁移至 SSD 或优化写入策略。

5. 镜像相关故障(拉取失败/层损坏)#

排查示例

# 1) 仓库可达性
curl -I https://registry.example.com/v2/

# 2) 登录凭证
docker login registry.example.com

# 3) 镜像标签检查
docker images | grep app

# 4) 使用镜像校验重拉
docker rmi registry.example.com/app:v1.2.3
docker pull registry.example.com/app:v1.2.3

修复建议:固定基础镜像版本,避免 latest 漂移。

6. 数据持久化异常(挂载失败/权限/数据丢失)#

排查示例

# 1) 检查挂载路径
docker inspect <app_container> | jq '.[0].Mounts'

# 2) 宿主机目录权限
ls -ld /data/app
id

# 3) SELinux 状态(CentOS/RHEL)
getenforce

修复示例:权限不足导致写入失败:

# 假设容器内以 UID 1001 运行
sudo chown -R 1001:1001 /data/app

数据恢复演练(示例):

# 备份
tar -czf /backup/app_data_$(date +%F).tgz -C /data/app .

# 恢复
tar -xzf /backup/app_data_2024-01-01.tgz -C /data/app

7. 网络异常(DNS/容器间通信/跨主机)#

排查示例

# 1) DNS 解析
docker exec -it <app_container> sh -c "nslookup redis.service.local"

# 2) 容器间通信
docker exec -it <app_container> sh -c "curl -sS http://redis:6379"

# 3) 检查网络模式与桥接
docker network ls
docker network inspect bridge

常见修复:DNS 失效 -> 指定自定义 DNS 或修复宿主机 resolv.conf。

docker run -d --name app \
  --dns 8.8.8.8 --dns 1.1.1.1 \
  registry.example.com/app:v1.2.3

练习:构建一条完整排查链路#

  1. 启动一个错误入口命令的容器,观察退出码与日志。
  2. 修复启动命令并验证服务可访问。
  3. 人为限制内存并观察重启与 OOM。

操作示例:

# 1) 错误入口命令
docker run --name badapp -d busybox /not/exist

# 2) 查看退出码与日志
docker ps -a
docker logs badapp

# 3) 正确启动并验证
docker run --name goodapp -d -p 8080:80 nginx:1.25
curl -I http://127.0.0.1:8080

# 4) 限制内存导致 OOM
docker run --name oomapp -d --memory=32m nginx:1.25
docker stats oomapp

故障排查结束后需形成复盘记录:故障触发条件、定位路径、修复动作与预防措施。将常见问题沉淀为标准化手册与告警规则,以缩短 MTTR 并降低重复故障发生率。