Docker 排障手册:从拉镜像失败到 Compose 配置,一篇搞定常见问题
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?
常见原因
- Docker 服务没有启动;
- 当前用户没有 Docker 权限;
- Docker daemon 启动失败;
- 配置文件错误;
- 系统环境不支持或内核模块缺失。
解决方案
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
常见原因
- 网络访问 Docker Hub 不稳定;
- DNS 解析异常;
- 公司代理或防火墙限制;
- Docker 镜像源未配置;
- 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
失败。
常见原因
- Docker 网络异常;
- DNS 解析失败;
- 宿主机转发未开启;
- iptables 规则异常;
- 公司网络限制;
- 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
原因分析
- 数据库容器尚未完全启动;
- 服务名写错;
- 应用使用了
localhost连接数据库; - 不在同一个 Docker 网络;
- 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 构建镜像速度慢
常见原因
- 基础镜像过大;
- 构建上下文包含大量无关文件;
- 没有合理利用缓存;
- 每次构建都重新下载依赖;
- 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 问题时,可以按照以下顺序排查:
- 查看容器是否运行:
docker ps -a; - 查看容器日志:
docker logs; - 查看容器详情:
docker inspect; - 检查端口映射和防火墙;
- 检查 Docker 网络;
- 检查数据卷权限;
- 检查 Docker daemon 配置;
- 查看系统日志:
journalctl -u docker; - 检查磁盘空间;
- 必要时重新创建容器。
对于生产环境,建议统一维护 Docker 配置文件、Compose 文件、镜像版本、日志策略和数据备份策略。只有将这些基础工作做好,Docker 才能真正发挥出环境一致、部署快速、迁移方便、维护简单的优势。