上一篇 下一篇 分享链接 返回 返回顶部

Docker 排障手册:从拉镜像失败到 Compose 配置,一篇搞定常见问题

发布人:慈云数据-客服中心 发布时间:22小时前 阅读量:1

Docker 常见问题汇总|附配置文件

Docker 作为目前最常用的容器化工具之一,广泛应用于本地开发、测试环境、CI/CD、微服务部署以及生产环境交付。它可以帮助我们将应用及其依赖打包成标准化镜像,从而实现“一次构建,到处运行”。

不过,在实际使用 Docker 的过程中,很多开发者、运维人员都会遇到各种问题,例如:镜像拉取失败、容器无法启动、端口不通、数据丢失、权限不足、磁盘占用过高、容器网络异常、Docker Compose 配置错误等。

本文将系统整理 Docker 使用过程中的常见问题,并提供对应的排查思路、解决方案以及常用配置文件示例,适合作为 Docker 日常使用和故障排查手册。


一、Docker 基础概念回顾

在排查 Docker 问题之前,有必要先理解几个核心概念。

1. 镜像 Image

镜像可以理解为一个只读模板,里面包含应用程序运行所需的文件系统、依赖库、环境变量、启动命令等。

例如:

docker pull nginx
docker pull mysql:8.0
docker pull redis:7

这些命令会从镜像仓库拉取对应镜像。


2. 容器 Container

容器是镜像运行之后的实例。

例如:

docker run -d --name my-nginx -p 8080:80 nginx

该命令表示基于 nginx 镜像启动一个容器,并将宿主机的 8080 端口映射到容器内部的 80 端口。


3. Dockerfile

Dockerfile 是构建镜像的配置文件,用于定义镜像的构建步骤。

例如:

FROM openjdk:17-jdk-slim

WORKDIR /app

COPY target/demo.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

4. Docker Compose

Docker Compose 用于管理多个容器,适合本地开发环境或中小规模服务编排。

例如同时启动 MySQL、Redis、后端服务:

version: "3.8"

services:
  app:
    image: demo-app:latest
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      - redis

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 123456

  redis:
    image: redis:7

二、Docker 安装后无法启动

问题表现

安装 Docker 后,执行以下命令:

docker ps

出现类似错误:

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

常见原因

  1. Docker 服务没有启动;
  2. 当前用户没有 Docker 权限;
  3. Docker daemon 启动失败;
  4. 配置文件错误;
  5. 系统环境不支持或内核模块缺失。

解决方案

1. 查看 Docker 服务状态

systemctl status docker

如果没有启动,可以执行:

sudo systemctl start docker

设置开机自启:

sudo systemctl enable docker

2. 查看 Docker 启动日志

journalctl -u docker -f

如果配置文件格式错误,通常会在日志中看到明显提示。


3. 检查 Docker 配置文件

Docker daemon 常用配置文件路径为:

/etc/docker/daemon.json

可以使用以下命令检查 JSON 格式是否正确:

cat /etc/docker/daemon.json | python -m json.tool

如果 JSON 格式错误,Docker 可能无法启动。


三、普通用户执行 Docker 命令提示权限不足

问题表现

普通用户执行:

docker ps

提示:

permission denied while trying to connect to the Docker daemon socket

原因分析

Docker 默认通过 Unix Socket 与 Docker daemon 通信:

/var/run/docker.sock

该文件通常归属于 root 用户和 docker 用户组。如果当前用户不在 docker 用户组中,就会出现权限不足。


解决方案

将当前用户加入 docker 用户组:

sudo usermod -aG docker $USER

然后退出当前终端,重新登录,或者执行:

newgrp docker

再次验证:

docker ps

注意:加入 docker 用户组相当于拥有较高系统权限,生产环境应谨慎授权。


四、Docker 镜像拉取失败

问题表现

执行:

docker pull nginx

出现超时、连接失败、TLS 握手失败等问题,例如:

Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: TLS handshake timeout

常见原因

  1. 网络访问 Docker Hub 不稳定;
  2. DNS 解析异常;
  3. 公司代理或防火墙限制;
  4. Docker 镜像源未配置;
  5. Docker daemon 代理配置不正确。

五、配置 Docker 镜像加速器

可以通过修改 /etc/docker/daemon.json 配置镜像加速器。

示例配置

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://mirror.baidubce.com"
  ],
  "dns": [
    "8.8.8.8",
    "114.114.114.114"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

修改完成后执行:

sudo systemctl daemon-reload
sudo systemctl restart docker

查看配置是否生效:

docker info

在输出中可以查看 Registry Mirrors 字段。


六、Docker 代理配置

如果服务器位于公司内网,需要通过 HTTP/HTTPS 代理访问外部镜像仓库,需要为 Docker daemon 配置代理。

创建配置目录

sudo mkdir -p /etc/systemd/system/docker.service.d

新建代理配置文件

文件路径:

/etc/systemd/system/docker.service.d/http-proxy.conf

内容如下:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:7890"
Environment="HTTPS_PROXY=http://proxy.example.com:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1,.example.com"

重新加载配置并重启 Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

查看代理环境变量:

systemctl show --property=Environment docker

七、容器启动后立即退出

问题表现

执行:

docker run -d --name test ubuntu

然后查看容器:

docker ps -a

发现容器状态为:

Exited

原因分析

容器的生命周期取决于主进程。如果主进程执行结束,容器就会退出。

例如:

docker run ubuntu

默认命令可能执行完成后立即退出。


解决方案

1. 使用交互式终端

docker run -it ubuntu bash

2. 保持容器运行

docker run -d ubuntu tail -f /dev/null

3. 查看容器日志

docker logs 容器名或容器ID

4. 查看退出原因

docker inspect 容器名或容器ID

重点查看:

"State": {
  "Status": "exited",
  "ExitCode": 1,
  "Error": ""
}

八、端口映射后无法访问服务

问题表现

启动容器:

docker run -d --name nginx-demo -p 8080:80 nginx

访问:

http://服务器IP:8080

无法打开。


排查步骤

1. 查看容器是否运行

docker ps

确认是否存在:

0.0.0.0:8080->80/tcp

2. 查看容器内部服务是否正常

进入容器:

docker exec -it nginx-demo bash

在容器内检查端口:

curl localhost:80

3. 检查宿主机端口监听

ss -tunlp | grep 8080

4. 检查防火墙

CentOS/RHEL:

sudo firewall-cmd --list-ports
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --reload

Ubuntu:

sudo ufw status
sudo ufw allow 8080/tcp

5. 检查云服务器安全组

如果使用阿里云、腾讯云、华为云、AWS、Azure 等云服务器,还需要在安全组中放行对应端口。


九、容器内无法访问外网

问题表现

进入容器后执行:

curl https://www.baidu.com

或:

ping 8.8.8.8

失败。


常见原因

  1. Docker 网络异常;
  2. DNS 解析失败;
  3. 宿主机转发未开启;
  4. iptables 规则异常;
  5. 公司网络限制;
  6. Docker daemon DNS 配置错误。

解决方案

1. 检查宿主机是否能访问外网

curl https://www.baidu.com

如果宿主机本身无法访问外网,应先解决宿主机网络问题。


2. 指定 Docker DNS

修改:

/etc/docker/daemon.json

示例:

{
  "dns": [
    "8.8.8.8",
    "1.1.1.1",
    "114.114.114.114"
  ]
}

重启 Docker:

sudo systemctl restart docker

3. 开启 IP 转发

查看:

sysctl net.ipv4.ip_forward

如果结果为:

net.ipv4.ip_forward = 0

临时开启:

sudo sysctl -w net.ipv4.ip_forward=1

永久开启,编辑:

/etc/sysctl.conf

添加:

net.ipv4.ip_forward = 1

生效:

sudo sysctl -p

十、容器之间无法通信

Docker 默认提供多个网络模式,最常用的是 bridge 网络。

查看 Docker 网络

docker network ls

创建自定义网络

docker network create app-network

启动容器并加入网络

docker run -d --name mysql --network app-network mysql:8.0
docker run -d --name app --network app-network demo-app:latest

在同一个自定义网络中,容器可以通过容器名互相访问。

例如应用连接 MySQL:

mysql:3306

而不是:

127.0.0.1:3306

十一、Docker Compose 中服务无法连接数据库

常见错误

应用启动时报错:

Connection refused

或者:

UnknownHostException: mysql

原因分析

  1. 数据库容器尚未完全启动;
  2. 服务名写错;
  3. 应用使用了 localhost 连接数据库;
  4. 不在同一个 Docker 网络;
  5. MySQL 权限或账号配置错误。

推荐 Compose 配置

version: "3.8"

services:
  mysql:
    image: mysql:8.0
    container_name: demo-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: demo
      MYSQL_USER: demo
      MYSQL_PASSWORD: demo123
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - demo-net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p123456"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7
    container_name: demo-redis
    restart: always
    ports:
      - "6379:6379"
    networks:
      - demo-net

  app:
    image: demo-app:latest
    container_name: demo-app
    restart: always
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: demo
      SPRING_DATASOURCE_PASSWORD: demo123
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
    ports:
      - "8080:8080"
    networks:
      - demo-net

volumes:
  mysql-data:

networks:
  demo-net:
    driver: bridge

重点说明

在 Compose 中,服务之间访问应使用服务名:

mysql
redis

而不是:

localhost
127.0.0.1

因为在容器内部,localhost 指向的是当前容器本身。


十二、数据卷挂载后文件权限异常

问题表现

容器启动后,应用写文件时报错:

Permission denied

原因分析

宿主机目录挂载到容器后,文件权限由宿主机文件系统决定。如果容器内应用使用非 root 用户运行,而宿主机目录权限不足,就会出现权限问题。


解决方案

1. 修改宿主机目录权限

sudo chown -R 1000:1000 /data/app
sudo chmod -R 755 /data/app

其中 1000:1000 应根据容器内实际用户 UID/GID 调整。

查看容器内用户:

docker exec -it 容器名 id

2. Docker Compose 指定用户

services:
  app:
    image: demo-app:latest
    user: "1000:1000"
    volumes:
      - ./logs:/app/logs

3. 临时使用 root 排查

services:
  app:
    image: demo-app:latest
    user: root

不建议生产环境长期使用 root 用户运行应用容器。


十三、Docker 日志占用磁盘过大

问题表现

磁盘空间不足:

df -h

发现 /var/lib/docker 占用很大。

查看容器日志:

du -h --max-depth=1 /var/lib/docker/containers

Docker 默认使用 json-file 日志驱动,如果不限制大小,日志文件可能无限增长。


解决方案:限制日志大小

编辑:

/etc/docker/daemon.json

添加:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

重启 Docker:

sudo systemctl restart docker

注意:该配置通常只对新创建的容器生效,已有容器可能需要重新创建。


十四、清理 Docker 磁盘空间

查看 Docker 占用

docker system df

清理停止的容器

docker container prune

清理无用镜像

docker image prune

清理所有未使用镜像:

docker image prune -a

清理无用数据卷

docker volume prune

清理无用网络

docker network prune

一键清理

docker system prune

如果希望包含未使用的数据卷:

docker system prune -a --volumes

生产环境执行清理命令前必须确认数据卷是否仍在使用,避免误删数据库数据。


十五、Dockerfile 构建镜像速度慢

常见原因

  1. 基础镜像过大;
  2. 构建上下文包含大量无关文件;
  3. 没有合理利用缓存;
  4. 每次构建都重新下载依赖;
  5. Dockerfile 指令顺序不合理。

推荐 .dockerignore 配置

在项目根目录创建:

.dockerignore

示例:

.git
.idea
.vscode
target
node_modules
logs
tmp
*.log
*.md
.DS_Store

.dockerignore 可以减少构建上下文大小,提高构建速度。


Java 项目 Dockerfile 示例

FROM eclipse-temurin:17-jre

WORKDIR /app

COPY target/demo.jar app.jar

ENV TZ=Asia/Shanghai

EXPOSE 8080

ENTRYPOINT ["java", "-Xms512m", "-Xmx512m", "-jar", "app.jar"]

Node.js 项目 Dockerfile 示例

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./

RUN npm config set registry https://registry.npmmirror.com \
    && npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

十六、容器时间与宿主机时间不一致

问题表现

容器日志时间和北京时间不一致,通常相差 8 小时。

解决方案一:设置环境变量

docker run -d \
  -e TZ=Asia/Shanghai \
  --name app \
  demo-app:latest

Docker Compose:

services:
  app:
    image: demo-app:latest
    environment:
      TZ: Asia/Shanghai

解决方案二:挂载宿主机时间文件

services:
  app:
    image: demo-app:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

十七、容器重启策略配置

Docker 支持多种重启策略。

常见策略

策略 说明
no 默认,不自动重启
always 无论退出原因,都会重启
unless-stopped 除非手动停止,否则自动重启
on-failure 仅异常退出时重启

示例

docker run -d \
  --name nginx \
  --restart always \
  -p 80:80 \
  nginx

Docker Compose:

services:
  nginx:
    image: nginx
    restart: unless-stopped
    ports:
      - "80:80"

生产环境通常推荐:

restart: unless-stopped

十八、Docker 容器内存过高或被 OOM Kill

问题表现

容器突然退出,查看状态:

docker inspect 容器名

看到:

"OOMKilled": true

解决方案

启动容器时限制内存:

docker run -d \
  --name app \
  --memory=1g \
  --memory-swap=1g \
  demo-app:latest

Docker Compose:

services:
  app:
    image: demo-app:latest
    mem_limit: 1g

对于 Java 应用,还应配置 JVM 参数:

java -Xms512m -Xmx512m -jar app.jar

Dockerfile:

ENTRYPOINT ["java", "-Xms512m", "-Xmx512m", "-jar", "app.jar"]

十九、Docker 常用配置文件汇总

1. /etc/docker/daemon.json

推荐基础配置如下:

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://mirror.baidubce.com"
  ],
  "dns": [
    "8.8.8.8",
    "114.114.114.114"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "exec-opts": [
    "native.cgroupdriver=systemd"
  ],
  "storage-driver": "overlay2"
}

重启生效:

sudo systemctl daemon-reload
sudo systemctl restart docker

2. Docker systemd 代理配置

文件:

/etc/systemd/system/docker.service.d/http-proxy.conf

内容:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:7890"
Environment="HTTPS_PROXY=http://proxy.example.com:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1"

3. Docker Compose 完整示例

version: "3.8"

services:
  nginx:
    image: nginx:1.25
    container_name: demo-nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html
      - ./nginx/logs:/var/log/nginx
    networks:
      - demo-net

  mysql:
    image: mysql:8.0
    container_name: demo-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: demo
      TZ: Asia/Shanghai
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d
    networks:
      - demo-net

  redis:
    image: redis:7
    container_name: demo-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass 123456
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    networks:
      - demo-net

networks:
  demo-net:
    driver: bridge

volumes:
  mysql-data:
  redis-data:

4. MySQL 配置文件示例

路径:

./mysql/conf.d/my.cnf

内容:

[mysqld]
default-time-zone = '+8:00'
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
max_connections = 500
default_authentication_plugin = mysql_native_password

[client]
default-character-set = utf8mb4

5. Nginx 配置文件示例

路径:

./nginx/conf.d/default.conf

内容:

server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }

    location /api/ {
        proxy_pass http://app:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

二十、Docker 常用排查命令

查看 Docker 版本

docker version

查看 Docker 系统信息

docker info

查看运行中的容器

docker ps

查看所有容器

docker ps -a

查看容器日志

docker logs -f 容器名

进入容器

docker exec -it 容器名 bash

如果容器没有 bash:

docker exec -it 容器名 sh

查看容器详细信息

docker inspect 容器名

查看容器资源占用

docker stats

查看镜像

docker images

查看数据卷

docker volume ls

查看网络

docker network ls

二十一、生产环境 Docker 使用建议

1. 不建议直接使用 latest 标签

不推荐:

image: mysql:latest

推荐:

image: mysql:8.0

原因是 latest 可能随着时间变化,导致环境不可控。


2. 数据必须挂载到数据卷

数据库、上传文件、日志等数据不要只保存在容器内部,否则容器删除后数据也会丢失。

推荐:

volumes:
  - mysql-data:/var/lib/mysql

3. 限制日志大小

生产环境必须配置日志轮转,避免日志撑满磁盘。


4. 设置容器重启策略

推荐:

restart: unless-stopped

5. 定期备份数据卷

数据库数据卷应定期备份,例如 MySQL:

docker exec demo-mysql mysqldump -uroot -p123456 demo > demo.sql

恢复:

cat demo.sql | docker exec -i demo-mysql mysql -uroot -p123456 demo

6. 避免容器使用过高权限

除非必要,不要使用:

privileged: true

也不要随意挂载宿主机敏感目录,例如:

/
 /etc
 /var/run/docker.sock

二十二、总结

Docker 本身并不复杂,但在实际使用过程中,问题往往出现在网络、权限、数据卷、配置文件、日志、镜像源以及服务依赖关系上。

遇到 Docker 问题时,可以按照以下顺序排查:

  1. 查看容器是否运行:docker ps -a
  2. 查看容器日志:docker logs
  3. 查看容器详情:docker inspect
  4. 检查端口映射和防火墙;
  5. 检查 Docker 网络;
  6. 检查数据卷权限;
  7. 检查 Docker daemon 配置;
  8. 查看系统日志:journalctl -u docker
  9. 检查磁盘空间;
  10. 必要时重新创建容器。

对于生产环境,建议统一维护 Docker 配置文件、Compose 文件、镜像版本、日志策略和数据备份策略。只有将这些基础工作做好,Docker 才能真正发挥出环境一致、部署快速、迁移方便、维护简单的优势。

目录结构
全文