Docker 故障排查
本章将详细介绍 Docker 常见问题的诊断和解决方法,帮助你快速定位和解决 Docker 使用过程中遇到的各种问题。
故障排查方法论
系统化排查流程
问题发现 → 信息收集 → 问题分析 → 解决方案 → 验证修复 → 预防措施
↓ ↓ ↓ ↓ ↓ ↓
现象描述 日志分析 根因定位 实施修复 功能测试 文档记录
错误信息 状态检查 假设验证 回滚准备 性能验证 流程改进信息收集清单
bash
# 系统信息
docker version
docker info
docker system df
docker system events --since 1h
# 容器状态
docker ps -a
docker stats --no-stream
docker logs container_name
# 网络信息
docker network ls
docker network inspect network_name
# 存储信息
docker volume ls
docker image ls容器启动问题
容器无法启动
问题现象:
bash
docker: Error response from daemon: container failed to start排查步骤:
- 检查容器日志
bash
# 查看容器启动日志
docker logs container_name
# 实时查看日志
docker logs -f container_name
# 查看最近的日志
docker logs --tail 50 container_name- 检查镜像问题
bash
# 验证镜像是否存在
docker images | grep image_name
# 检查镜像完整性
docker inspect image_name
# 重新拉取镜像
docker pull image_name:tag- 检查资源限制
bash
# 检查系统资源
free -h
df -h
docker system df
# 检查容器资源限制
docker inspect container_name | grep -A 10 "Resources"常见解决方案:
bash
# 解决方案 1: 端口冲突
# 检查端口使用情况
netstat -tulpn | grep :8080
lsof -i :8080
# 使用不同端口
docker run -p 8081:80 nginx
# 解决方案 2: 权限问题
# 检查文件权限
ls -la /host/path
# 修改文件所有者
sudo chown -R 1000:1000 /host/path
# 以特定用户运行
docker run -u $(id -u):$(id -g) image_name
# 解决方案 3: 内存不足
# 增加内存限制
docker run -m 1g image_name
# 清理系统资源
docker system prune -f容器异常退出
问题现象:
bash
# 容器状态显示 Exited
docker ps -a
CONTAINER ID IMAGE STATUS
abc123def456 nginx Exited (1) 2 minutes ago排查步骤:
bash
# 查看退出代码
docker ps -a --format "table {{.Names}}\t{{.Status}}"
# 查看详细退出信息
docker inspect container_name | grep -A 5 "State"
# 查看容器事件
docker events --filter container=container_name --since 1h常见退出代码:
| 退出代码 | 含义 | 常见原因 |
|---|---|---|
| 0 | 正常退出 | 程序正常结束 |
| 1 | 一般错误 | 应用程序错误 |
| 125 | Docker 守护进程错误 | 命令执行失败 |
| 126 | 容器命令不可执行 | 权限问题或文件不存在 |
| 127 | 容器命令未找到 | 命令路径错误 |
| 137 | SIGKILL 信号 | 内存不足或被强制杀死 |
| 143 | SIGTERM 信号 | 正常终止信号 |
解决方案:
bash
# 退出代码 137 (内存不足)
# 增加内存限制
docker run -m 2g image_name
# 检查内存使用
docker stats container_name
# 退出代码 126 (权限问题)
# 检查文件权限
docker run --rm -it image_name ls -la /app/
# 修复权限
docker run --rm -v /host/path:/app image_name chown -R app:app /app
# 退出代码 127 (命令未找到)
# 检查命令路径
docker run --rm -it image_name which command_name
# 修复 PATH 环境变量
docker run -e PATH="/usr/local/bin:$PATH" image_name网络连接问题
容器无法访问外网
排查步骤:
bash
# 测试网络连通性
docker exec container_name ping 8.8.8.8
docker exec container_name nslookup google.com
# 检查 DNS 配置
docker exec container_name cat /etc/resolv.conf
# 检查网络配置
docker network ls
docker network inspect bridge解决方案:
bash
# 解决方案 1: DNS 问题
# 指定 DNS 服务器
docker run --dns 8.8.8.8 --dns 8.8.4.4 image_name
# 解决方案 2: 防火墙问题
# 检查 iptables 规则
sudo iptables -L DOCKER-USER
# 允许 Docker 网络
sudo iptables -I DOCKER-USER -j ACCEPT
# 解决方案 3: 代理设置
# 配置 HTTP 代理
docker run -e HTTP_PROXY=http://proxy:8080 \
-e HTTPS_PROXY=http://proxy:8080 \
image_name容器间无法通信
排查步骤:
bash
# 检查容器网络
docker inspect container1 | grep NetworkMode
docker inspect container2 | grep NetworkMode
# 测试连通性
docker exec container1 ping container2
# 检查端口监听
docker exec container2 netstat -tulpn解决方案:
bash
# 确保容器在同一网络
docker network create mynetwork
docker network connect mynetwork container1
docker network connect mynetwork container2
# 使用容器名通信
docker exec container1 ping container2
# 检查防火墙规则
sudo iptables -L DOCKER-USER端口映射问题
排查步骤:
bash
# 检查端口映射
docker port container_name
# 检查端口占用
netstat -tulpn | grep :8080
lsof -i :8080
# 测试端口访问
curl http://localhost:8080
telnet localhost 8080解决方案:
bash
# 使用不同端口
docker run -p 8081:80 nginx
# 绑定到特定 IP
docker run -p 127.0.0.1:8080:80 nginx
# 检查防火墙
sudo ufw status
sudo iptables -L INPUT存储相关问题
数据卷挂载失败
问题现象:
bash
docker: Error response from daemon: invalid mount config排查步骤:
bash
# 检查挂载路径
ls -la /host/path
# 检查权限
stat /host/path
# 检查 SELinux 标签
ls -Z /host/path解决方案:
bash
# 创建目录
sudo mkdir -p /host/path
# 修改权限
sudo chown -R 1000:1000 /host/path
sudo chmod -R 755 /host/path
# SELinux 标签
sudo chcon -Rt svirt_sandbox_file_t /host/path
# 使用绝对路径
docker run -v $(pwd)/data:/app/data image_name磁盘空间不足
排查步骤:
bash
# 检查磁盘使用
df -h
docker system df
docker system df -v
# 查看大文件
du -sh /var/lib/docker/*解决方案:
bash
# 清理未使用资源
docker system prune -f
# 清理所有未使用资源
docker system prune -a -f
# 清理特定资源
docker container prune -f
docker image prune -f
docker volume prune -f
docker network prune -f
# 删除悬空镜像
docker rmi $(docker images -f "dangling=true" -q)
# 删除旧容器
docker rm $(docker ps -aq --filter "status=exited")数据卷权限问题
排查步骤:
bash
# 检查容器内权限
docker exec container_name ls -la /data
# 检查用户 ID
docker exec container_name id
# 检查主机权限
ls -la /host/data解决方案:
bash
# 修改主机文件权限
sudo chown -R 1000:1000 /host/data
# 在容器内修改权限
docker exec container_name chown -R app:app /data
# 使用正确的用户运行容器
docker run -u 1000:1000 -v /host/data:/data image_name性能问题
容器运行缓慢
排查步骤:
bash
# 监控资源使用
docker stats container_name
# 检查系统负载
top
htop
iostat -x 1
# 检查容器限制
docker inspect container_name | grep -A 10 "Resources"解决方案:
bash
# 增加资源限制
docker run -m 2g --cpus="2.0" image_name
# 优化镜像大小
# 使用多阶段构建
# 清理不必要文件
# 使用轻量级基础镜像
# 调整存储驱动
# 在 /etc/docker/daemon.json 中配置
{
"storage-driver": "overlay2"
}内存泄漏
排查步骤:
bash
# 监控内存使用趋势
docker stats --format "table {{.Container}}\t{{.MemUsage}}\t{{.MemPerc}}"
# 检查应用日志
docker logs container_name | grep -i "memory\|oom"
# 系统内存信息
free -h
cat /proc/meminfo解决方案:
bash
# 设置内存限制
docker run -m 1g image_name
# 启用 swap 限制
docker run -m 1g --memory-swap 2g image_name
# 监控和重启
#!/bin/bash
while true; do
MEM_USAGE=$(docker stats --no-stream --format "{{.MemPerc}}" container_name | sed 's/%//')
if (( $(echo "$MEM_USAGE > 90" | bc -l) )); then
echo "Memory usage too high: $MEM_USAGE%"
docker restart container_name
fi
sleep 60
done镜像相关问题
镜像拉取失败
问题现象:
bash
Error response from daemon: pull access denied
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: TLS handshake timeout排查步骤:
bash
# 检查网络连接
ping registry-1.docker.io
curl -I https://registry-1.docker.io/v2/
# 检查认证信息
docker login
cat ~/.docker/config.json
# 检查镜像名称
docker search image_name解决方案:
bash
# 使用镜像加速器
# 配置 /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
# 重启 Docker 服务
sudo systemctl restart docker
# 使用代理
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy:8080"
Environment="HTTPS_PROXY=http://proxy:8080"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker镜像构建失败
排查步骤:
bash
# 详细构建日志
docker build --no-cache --progress=plain -t image_name .
# 检查 Dockerfile 语法
docker build --dry-run -t image_name .
# 检查构建上下文
ls -la .
cat .dockerignore解决方案:
bash
# 常见 Dockerfile 问题修复
# 问题 1: 基础镜像不存在
FROM node:16-alpine # 使用存在的标签
# 问题 2: 文件路径错误
COPY package.json ./ # 确保文件在构建上下文中
# 问题 3: 权限问题
RUN chmod +x /app/script.sh
# 问题 4: 网络问题
RUN apt-get update && apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/* # 清理缓存Docker 守护进程问题
Docker 服务无法启动
排查步骤:
bash
# 检查服务状态
sudo systemctl status docker
# 查看服务日志
sudo journalctl -u docker.service -f
# 检查配置文件
sudo docker daemon --validate
cat /etc/docker/daemon.json解决方案:
bash
# 修复配置文件
sudo nano /etc/docker/daemon.json
# 重置 Docker
sudo systemctl stop docker
sudo rm -rf /var/lib/docker
sudo systemctl start docker
# 重新安装 Docker
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.ioDocker 守护进程响应慢
排查步骤:
bash
# 检查系统资源
top
df -h
iostat -x 1
# 检查 Docker 进程
ps aux | grep docker
pstree -p $(pgrep dockerd)解决方案:
bash
# 优化 Docker 配置
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"live-restore": true
}
# 清理资源
docker system prune -f
# 重启服务
sudo systemctl restart docker调试工具和技巧
容器调试
bash
# 进入运行中的容器
docker exec -it container_name /bin/bash
# 以 root 用户进入
docker exec -it -u root container_name /bin/bash
# 调试已停止的容器
docker commit container_name debug_image
docker run -it debug_image /bin/bash
# 使用调试镜像
docker run -it --rm \
--pid container:target_container \
--net container:target_container \
--cap-add SYS_PTRACE \
nicolaka/netshoot网络调试
bash
# 网络诊断容器
docker run --rm -it \
--net container:target_container \
nicolaka/netshoot
# 在诊断容器中执行
nslookup service_name
ping service_name
netstat -tulpn
ss -tulpn
tcpdump -i eth0性能分析
bash
# 容器性能分析
docker run --rm -it \
--pid host \
--privileged \
brendangregg/perf-tools
# 系统调用跟踪
docker run --rm -it \
--pid container:target_container \
--cap-add SYS_PTRACE \
alpine \
strace -p 1
# 文件系统分析
docker run --rm -it \
-v /var/lib/docker:/var/lib/docker:ro \
alpine \
du -sh /var/lib/docker/*监控和预警
健康检查
dockerfile
# Dockerfile 中添加健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1bash
# 运行时添加健康检查
docker run -d \
--health-cmd="curl -f http://localhost:8080/health || exit 1" \
--health-interval=30s \
--health-timeout=3s \
--health-retries=3 \
myapp监控脚本
bash
#!/bin/bash
# docker-monitor.sh
LOG_FILE="/var/log/docker-monitor.log"
check_containers() {
echo "$(date): 检查容器状态" >> $LOG_FILE
# 检查异常退出的容器
EXITED_CONTAINERS=$(docker ps -aq --filter "status=exited")
if [ ! -z "$EXITED_CONTAINERS" ]; then
echo "$(date): 发现异常退出的容器: $EXITED_CONTAINERS" >> $LOG_FILE
# 发送告警
send_alert "容器异常退出" "$EXITED_CONTAINERS"
fi
# 检查资源使用
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemPerc}}" | \
while read line; do
if echo "$line" | grep -q "%"; then
CPU=$(echo "$line" | awk '{print $2}' | sed 's/%//')
MEM=$(echo "$line" | awk '{print $3}' | sed 's/%//')
CONTAINER=$(echo "$line" | awk '{print $1}')
if (( $(echo "$CPU > 80" | bc -l) )) || (( $(echo "$MEM > 80" | bc -l) )); then
echo "$(date): 容器 $CONTAINER 资源使用过高 CPU:$CPU% MEM:$MEM%" >> $LOG_FILE
send_alert "资源使用告警" "容器 $CONTAINER CPU:$CPU% MEM:$MEM%"
fi
fi
done
}
send_alert() {
local subject="$1"
local message="$2"
# 发送邮件告警
echo "$message" | mail -s "$subject" admin@company.com
# 发送到 Slack
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$subject: $message\"}" \
$SLACK_WEBHOOK_URL
}
# 主循环
while true; do
check_containers
sleep 60
done故障预防
最佳实践清单
容器设计:
- [ ] 使用健康检查
- [ ] 设置合理的资源限制
- [ ] 实现优雅关闭
- [ ] 使用非 root 用户
- [ ] 配置日志轮转
镜像管理:
- [ ] 使用具体版本标签
- [ ] 定期更新基础镜像
- [ ] 扫描安全漏洞
- [ ] 优化镜像大小
- [ ] 使用多阶段构建
运维监控:
- [ ] 实施监控告警
- [ ] 定期备份数据
- [ ] 制定应急预案
- [ ] 文档化操作流程
- [ ] 定期演练故障恢复
自动化脚本
bash
#!/bin/bash
# docker-maintenance.sh
# 定期清理
cleanup_docker() {
echo "开始清理 Docker 资源..."
# 清理停止的容器
docker container prune -f
# 清理未使用的镜像
docker image prune -f
# 清理未使用的数据卷
docker volume prune -f
# 清理未使用的网络
docker network prune -f
echo "清理完成"
}
# 健康检查
health_check() {
echo "执行健康检查..."
# 检查 Docker 服务
if ! systemctl is-active --quiet docker; then
echo "Docker 服务未运行,尝试启动..."
systemctl start docker
fi
# 检查磁盘空间
DISK_USAGE=$(df /var/lib/docker | tail -1 | awk '{print $5}' | sed 's/%//')
if [ $DISK_USAGE -gt 80 ]; then
echo "磁盘使用率过高: $DISK_USAGE%"
cleanup_docker
fi
echo "健康检查完成"
}
# 设置定时任务
# 0 2 * * * /path/to/docker-maintenance.sh cleanup
# */10 * * * * /path/to/docker-maintenance.sh health_check
case "$1" in
cleanup)
cleanup_docker
;;
health_check)
health_check
;;
*)
echo "用法: $0 {cleanup|health_check}"
exit 1
;;
esac本章小结
本章全面介绍了 Docker 故障排查的方法和技巧:
关键要点:
- 系统化方法:遵循标准的故障排查流程
- 信息收集:全面收集系统和应用信息
- 常见问题:掌握典型问题的解决方案
- 调试工具:使用专业工具进行深入分析
- 预防措施:建立监控和预警机制
故障排查技能:
- 日志分析和问题定位
- 网络和存储问题诊断
- 性能问题分析和优化
- 安全问题识别和修复
- 自动化监控和告警
预防策略:
- 实施最佳实践
- 建立监控体系
- 定期维护和清理
- 文档化和知识分享
- 持续改进和优化
掌握这些故障排查技能将帮助你更好地管理和维护 Docker 环境,确保系统的稳定性和可靠性。