Skip to content

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

排查步骤:

  1. 检查容器日志
bash
# 查看容器启动日志
docker logs container_name

# 实时查看日志
docker logs -f container_name

# 查看最近的日志
docker logs --tail 50 container_name
  1. 检查镜像问题
bash
# 验证镜像是否存在
docker images | grep image_name

# 检查镜像完整性
docker inspect image_name

# 重新拉取镜像
docker pull image_name:tag
  1. 检查资源限制
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一般错误应用程序错误
125Docker 守护进程错误命令执行失败
126容器命令不可执行权限问题或文件不存在
127容器命令未找到命令路径错误
137SIGKILL 信号内存不足或被强制杀死
143SIGTERM 信号正常终止信号

解决方案:

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.io

Docker 守护进程响应慢

排查步骤:

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 1
bash
# 运行时添加健康检查
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 环境,确保系统的稳定性和可靠性。

延伸阅读

本站内容仅供学习和研究使用。