第27章 常见问题与解决方案

27.1 镜像问题

27.1.1 镜像拉取失败

问题1: 网络超时

bash 复制代码
# 错误信息
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: TLS handshake timeout

# 解决方案1: 配置镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}
EOF
sudo systemctl restart docker

# 解决方案2: 使用HTTP代理
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.example.com:8080"
Environment="HTTPS_PROXY=http://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

问题2: 磁盘空间不足

bash 复制代码
# 错误信息
no space left on device

# 检查磁盘使用
docker system df
df -h /var/lib/docker

# 清理无用资源
docker system prune -a --volumes  # 清理所有未使用资源
docker image prune -a              # 清理未使用镜像
docker volume prune                # 清理未使用卷

# 修改Docker数据目录
sudo systemctl stop docker
sudo mv /var/lib/docker /data/docker
sudo ln -s /data/docker /var/lib/docker
sudo systemctl start docker

问题3: 镜像校验失败

bash 复制代码
# 错误信息
failed to verify certificate: x509: certificate signed by unknown authority

# 解决方案: 添加不安全的仓库
sudo tee -a /etc/docker/daemon.json <<EOF
{
  "insecure-registries": ["registry.internal.com:5000"]
}
EOF
sudo systemctl restart docker

27.1.2 镜像构建问题

问题1: 构建缓存导致旧依赖

bash 复制代码
# 不使用缓存重新构建
docker build --no-cache -t myapp:latest .

# 仅从特定层开始重建
docker build --cache-from myapp:base -t myapp:latest .

问题2: ADD/COPY权限问题

dockerfile 复制代码
# 错误写法: 文件权限为root
FROM alpine
COPY app.py /app/
USER appuser  # 切换用户后无法访问

# 正确写法: 明确设置权限
FROM alpine
RUN adduser -D appuser
COPY --chown=appuser:appuser app.py /app/
USER appuser

问题3: 多阶段构建文件缺失

dockerfile 复制代码
# 错误: 忘记复制必要文件
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

FROM alpine
COPY --from=builder /app/myapp /myapp  # 缺少依赖库

# 正确: 使用静态编译或复制依赖
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp  # 静态编译

FROM alpine
COPY --from=builder /app/myapp /myapp

27.2 容器问题

27.2.1 容器启动失败

问题1: 端口已被占用

bash 复制代码
# 错误信息
Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

# 查找占用端口的进程
sudo lsof -i :80
sudo netstat -tulnp | grep :80

# 解决方案1: 停止占用进程
sudo kill <PID>

# 解决方案2: 使用其他端口
docker run -d -p 8080:80 nginx

问题2: 容器立即退出

bash 复制代码
# 查看容器退出状态
docker ps -a
docker inspect <container> | grep -A 5 State

# 查看退出日志
docker logs <container>

# 常见退出码含义
# 0:   正常退出
# 1:   应用错误
# 125: Docker守护进程错误
# 126: 命令无法执行
# 127: 命令未找到
# 137: SIGKILL (OOM或手动kill -9)
# 143: SIGTERM (docker stop)

# 调试: 覆盖ENTRYPOINT
docker run -it --entrypoint /bin/sh myapp

问题3: 健康检查失败

bash 复制代码
# 查看健康检查状态
docker inspect <container> | grep -A 20 Health

# 手动执行健康检查命令
docker exec <container> curl -f http://localhost/ || exit 1

# 调整健康检查参数
services:
  web:
    image: nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s      # 增加超时
      retries: 5        # 增加重试次数
      start_period: 60s # 增加启动等待时间

27.2.2 容器运行问题

问题1: 容器内存溢出

bash 复制代码
# 错误信息
container killed by OOM killer

# 查看OOM状态
docker inspect <container> | grep OOMKilled

# 解决方案1: 增加内存限制
docker run -d -m 1g --memory-swap=1g myapp

# 解决方案2: 优化应用内存使用
# Java应用
docker run -d -m 1g -e JAVA_OPTS="-Xmx768m -Xms512m" myapp

# Node.js应用
docker run -d -m 512m node --max-old-space-size=400 app.js

问题2: 容器无法访问外网

bash 复制代码
# 检查DNS配置
docker exec <container> cat /etc/resolv.conf

# 检查网络连接
docker exec <container> ping 8.8.8.8
docker exec <container> ping google.com

# 解决方案1: 指定DNS服务器
docker run -d --dns 8.8.8.8 --dns 8.8.4.4 nginx

# 解决方案2: 修改Docker默认DNS
sudo tee /etc/docker/daemon.json <<EOF
{
  "dns": ["8.8.8.8", "8.8.4.4"]
}
EOF
sudo systemctl restart docker

27.3 网络问题

27.3.1 容器间通信失败

问题1: 容器无法互相访问

bash 复制代码
# 检查容器网络
docker network inspect bridge

# 确保容器在同一网络
docker network create mynet
docker run -d --name app1 --network mynet nginx
docker run -d --name app2 --network mynet alpine

# 测试连通性
docker exec app2 ping app1
docker exec app2 wget -O- http://app1

# 检查防火墙
sudo iptables -L DOCKER-USER

问题2: 自定义网络DNS解析失败

bash 复制代码
# 使用网络别名
docker run -d --name db --network mynet --network-alias database postgres

# 应用通过别名访问
docker run -d --name app --network mynet \
  -e DB_HOST=database \
  myapp

27.3.2 端口映射问题

问题1: 端口映射不生效

bash 复制代码
# 检查端口映射
docker ps
docker port <container>

# 检查iptables规则
sudo iptables -t nat -L -n | grep <port>

# 检查容器内服务是否监听
docker exec <container> netstat -tulnp

# 确保服务绑定到0.0.0.0而非127.0.0.1
# 错误: 只监听localhost
nginx -g 'daemon off; listen 127.0.0.1:80;'

# 正确: 监听所有接口
nginx -g 'daemon off; listen 0.0.0.0:80;'

问题2: 无法访问宿主机服务

bash 复制代码
# 从容器访问宿主机
# Linux: 使用host.docker.internal (需要添加)
docker run --add-host=host.docker.internal:host-gateway myapp

# 或使用宿主机IP
HOST_IP=$(ip route | grep docker0 | awk '{print $9}')
docker run -e DB_HOST=$HOST_IP myapp

# 或使用host网络模式
docker run --network host myapp

27.4 权限问题

27.4.1 文件权限问题

问题1: 挂载目录无权限

bash 复制代码
# 错误: Permission denied
docker run -v /data:/data -u 1000:1000 alpine touch /data/test

# 解决方案1: 修改宿主机目录权限
sudo chown -R 1000:1000 /data
sudo chmod -R 755 /data

# 解决方案2: 使用root用户(不推荐)
docker run -v /data:/data alpine touch /data/test

# 解决方案3: 在容器内切换用户
docker run -v /data:/data alpine sh -c "
  adduser -D -u 1000 appuser
  chown appuser:appuser /data
  su appuser -c 'touch /data/test'
"

问题2: Volume权限问题

bash 复制代码
# 创建volume时设置权限
docker volume create mydata

# 使用初始化容器设置权限
docker run --rm -v mydata:/data alpine sh -c "
  chown -R 1000:1000 /data
  chmod -R 755 /data
"

# 应用容器使用
docker run -v mydata:/data -u 1000:1000 myapp

27.4.2 Docker权限问题

问题1: 普通用户无法执行docker命令

bash 复制代码
# 错误信息
permission denied while trying to connect to the Docker daemon socket

# 解决方案: 添加用户到docker组
sudo usermod -aG docker $USER
newgrp docker  # 或重新登录

# 验证
docker ps

问题2: GPU设备权限

bash 复制代码
# 错误: 无法访问GPU设备
# 解决方案: 添加用户到video组
sudo usermod -aG video,render $USER

# 检查设备权限
ls -l /dev/kfd /dev/dri

# 容器运行时添加组
docker run --device=/dev/kfd --device=/dev/dri \
  --group-add video --group-add render \
  rocm/pytorch:latest

27.5 存储问题

27.5.1 磁盘空间管理

问题1: Docker占用大量空间

bash 复制代码
# 检查Docker磁盘使用
docker system df -v

# 清理构建缓存
docker builder prune -a

# 清理未使用的镜像
docker image prune -a

# 清理停止的容器
docker container prune

# 清理未使用的卷
docker volume prune

# 一键清理(危险!)
docker system prune -a --volumes

问题2: 日志文件过大

bash 复制代码
# 查找大日志文件
sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -h | tail -n 10

# 清理特定容器日志
sudo truncate -s 0 /var/lib/docker/containers/<container-id>/*-json.log

# 配置日志轮转
sudo tee /etc/docker/daemon.json <<EOF
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF
sudo systemctl restart docker

27.5.2 数据卷问题

问题1: 数据卷丢失

bash 复制代码
# 列出所有卷(包括悬空)
docker volume ls -f dangling=true

# 备份卷数据
docker run --rm -v mydata:/data -v $(pwd):/backup alpine \
  tar czf /backup/mydata-backup.tar.gz /data

# 恢复卷数据
docker volume create mydata-restored
docker run --rm -v mydata-restored:/data -v $(pwd):/backup alpine \
  tar xzf /backup/mydata-backup.tar.gz -C /

27.6 性能问题

27.6.1 容器性能慢

问题1: I/O性能差

bash 复制代码
# 使用volume代替bind mount
# 慢: bind mount
docker run -v $(pwd)/data:/data myapp

# 快: named volume
docker volume create appdata
docker run -v appdata:/data myapp

# Mac/Windows: 使用缓存模式
docker run -v $(pwd)/data:/data:cached myapp

问题2: 网络性能差

bash 复制代码
# 使用host网络(牺牲隔离性)
docker run --network host myapp

# 调整MTU
docker network create --opt com.docker.network.driver.mtu=9000 mynet

27.6.2 资源限制问题

问题1: CPU限流

bash 复制代码
# 检查CPU限流
docker stats <container>

# 查看限流次数
CONTAINER_ID=$(docker inspect -f '{{.Id}}' <container>)
cat /sys/fs/cgroup/cpu/docker/$CONTAINER_ID/cpu.stat | grep throttled

# 增加CPU配额
docker update --cpus=2.0 <container>

27.7 ROCm相关问题

27.7.1 GPU访问问题

问题1: 容器内看不到GPU

bash 复制代码
# 检查设备映射
docker inspect <container> | grep -A 10 Devices

# 正确映射GPU设备
docker run -it --rm \
  --device=/dev/kfd \
  --device=/dev/dri \
  --group-add video \
  rocm/pytorch rocminfo

# 检查宿主机GPU
rocminfo | grep "Name:"
rocm-smi

问题2: ROCm版本不匹配

bash 复制代码
# 检查版本兼容性
# 宿主机ROCm版本
cat /opt/rocm/.info/version

# 容器内ROCm版本
docker run --rm rocm/pytorch:latest cat /opt/rocm/.info/version

# 使用匹配的镜像版本
docker run --device=/dev/kfd --device=/dev/dri \
  rocm/pytorch:rocm6.0-py3.10 python3

27.8 故障排查工具

27.8.1 综合诊断脚本

bash 复制代码
#!/bin/bash
# docker-doctor.sh - Docker健康检查

echo "=== Docker版本信息 ==="
docker version

echo -e "\n=== Docker守护进程状态 ==="
sudo systemctl status docker

echo -e "\n=== 磁盘使用情况 ==="
docker system df
df -h /var/lib/docker

echo -e "\n=== 运行中的容器 ==="
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

echo -e "\n=== 容器资源使用 ==="
docker stats --no-stream

echo -e "\n=== 网络列表 ==="
docker network ls

echo -e "\n=== 数据卷使用 ==="
docker volume ls
docker system df -v | grep -A 5 "Local Volumes"

echo -e "\n=== 最近的容器日志错误 ==="
for container in $(docker ps -q); do
  name=$(docker inspect -f '{{.Name}}' $container | sed 's/\///')
  echo "[$name]"
  docker logs --tail 10 $container 2>&1 | grep -i error || echo "无错误"
done

echo -e "\n=== Docker配置 ==="
cat /etc/docker/daemon.json 2>/dev/null || echo "无配置文件"

echo -e "\n=== 悬空资源 ==="
echo "悬空镜像: $(docker images -f dangling=true -q | wc -l)"
echo "悬空卷: $(docker volume ls -f dangling=true -q | wc -l)"

27.8.2 快速修复脚本

bash 复制代码
#!/bin/bash
# docker-fix.sh - 常见问题快速修复

fix_permissions() {
  echo "修复Docker权限..."
  sudo usermod -aG docker $USER
  echo "请重新登录生效"
}

fix_disk_space() {
  echo "清理Docker磁盘空间..."
  docker system prune -a -f
  docker volume prune -f
  echo "完成清理"
}

fix_network() {
  echo "重置Docker网络..."
  docker network prune -f
  sudo systemctl restart docker
  echo "网络已重置"
}

fix_dns() {
  echo "修复DNS配置..."
  sudo tee /etc/docker/daemon.json <<EOF
{
  "dns": ["8.8.8.8", "8.8.4.4"]
}
EOF
  sudo systemctl restart docker
  echo "DNS已更新"
}

case "$1" in
  permissions) fix_permissions ;;
  disk) fix_disk_space ;;
  network) fix_network ;;
  dns) fix_dns ;;
  *)
    echo "用法: $0 {permissions|disk|network|dns}"
    exit 1
    ;;
esac

27.9 调试技巧

27.9.1 容器调试

bash 复制代码
# 1. 使用调试镜像
docker run -it --rm nicolaka/netshoot

# 2. 查看容器进程
docker top <container>

# 3. 实时查看容器事件
docker events --filter container=<container>

# 4. 导出容器文件系统
docker export <container> > container.tar

# 5. 进入容器命名空间
PID=$(docker inspect -f '{{.State.Pid}}' <container>)
sudo nsenter -t $PID -n ip addr  # 网络命名空间

27.9.2 日志分析

bash 复制代码
# 跟踪特定错误
docker logs -f <container> 2>&1 | grep -i error

# 统计错误频率
docker logs <container> 2>&1 | grep -i error | wc -l

# 导出日志到文件
docker logs <container> > /tmp/container.log 2>&1

# 使用jq解析JSON日志
docker logs <container> 2>&1 | jq -r 'select(.level=="error")'

27.10 总结

27.10.1 问题分类速查

问题类型 常见原因 快速检查
镜像拉取失败 网络、空间、证书 docker pull, df -h
容器启动失败 端口占用、权限、配置 docker logs, lsof -i
网络不通 DNS、防火墙、网络模式 ping, curl, iptables
权限错误 用户组、文件权限、SELinux ls -l, groups, getenforce
磁盘空间不足 镜像、日志、卷 docker system df
性能问题 资源限制、I/O、网络 docker stats, iostat

27.10.2 排查流程

  1. 查看日志 : docker logs <container>
  2. 检查状态 : docker inspect <container>
  3. 测试网络 : docker exec <container> ping/curl
  4. 资源使用 : docker stats <container>
  5. 系统事件 : docker events
  6. 重启服务 : sudo systemctl restart docker

27.10.3 预防措施

  • 定期清理无用资源
  • 配置日志轮转
  • 设置资源限制
  • 使用健康检查
  • 监控磁盘空间
  • 备份重要数据
  • 文档化配置变更

参考资源:

  • Docker官方故障排查指南
  • Stack Overflow Docker标签
  • Docker社区论坛
相关推荐
_OP_CHEN1 小时前
【Linux系统编程】(三十六)深挖信号保存机制:未决、阻塞与信号集的底层实现全解析
linux·运维·操作系统·进程·c/c++·信号·信号保存
catoop1 小时前
Nginx 解决 upstream sent too big header 错误
运维·nginx
!chen2 小时前
Ubuntu 上 Docker 的配置及代理
ubuntu·docker·eureka
ayaya_mana2 小时前
Linux一键部署Docker与镜像加速配置
linux·运维·docker
nix.gnehc2 小时前
深入浅出 K8s 内外部通信:全场景方案解析与生产实践
云原生·容器·kubernetes
市安2 小时前
基于 Alpine 构建轻量 Nginx 错误页面 Docker 镜像
运维·nginx·docker·alpine
bitbot2 小时前
Linux是什麼與如何學習
linux·运维·服务器
杨云龙UP2 小时前
Oracle RMAN 归档日志清理标准流程:CROSSCHECK / EXPIRED / SYSDATE-N
运维·服务器·数据库
DeeplyMind2 小时前
第26章 Docker监控与日志
docker·容器·eureka