← 返回工具首页 Docker 启动失败?我排查了10个案例总结的实战指南

🐳 Docker 启动失败?我排查了10个案例总结的实战指南

你有没有过这种经历:本地跑得好好的容器,一部署就报错;或者昨天还正常的服务,今天突然起不来?本文从10个真实翻车场景出发,梳理5类最常见的 Docker 启动失败原因,每个都带诊断命令 + 修复步骤,拿来就能用。
---

案例1:端口已被宿主机其他进程占用

最经典的"昨天还能跑,今天就不行"——99%是另一个服务抢了你的端口。

🚨 报错信息
Error: Cannot start container: ports are already allocated
🔍 诊断
docker ps -a --format "{{.Names}}\t{{.Ports}}" # 查看所有容器及其端口占用 # 定位哪个进程占了你想要的端口 lsof -i :8080 # 或 ss -tlnp | grep 8080
🛠️ 修复

两种思路:停掉占用端口的进程,或者换端口。

# 方案A:杀掉占用端口的进程(确认可以杀再杀) kill $(lsof -t -i:8080) # 方案B:容器启动时指定不同端口映射 docker run -d -p 8081:80 nginx # 方案C:docker-compose 里改端口 # services: # web: # ports: # - "8081:80"
💡 如果是 Docker 内部端口冲突(比如两个容器都声明 expose: 80),不会报这个错。这个错误一定是宿主机端口被占用。
---

案例2:镜像名称写错 / 私有仓库拉不到

Pull 镜像的时候悄无声息地失败,或者 tag 写错了导致找不到镜像。

🚨 报错信息
Error: pull access denied, repository does not exist or may require authorization
Error: manifest unknown
🔍 诊断
# 检查本地镜像列表(看 tag 是否真的存在) docker images | grep <image_name> # 手动拉取镜像,看完整报错 docker pull <image_name>:<tag> # 如果是私有仓库,先登录 docker login <registry.example.com>
🛠️ 修复
# 常用镜像的官方 tag 通常是 latest,小心这个坑 docker pull nginx:latest # OK docker pull nginx:alpine # 小体积版,更推荐 docker pull nginx:1.27.0 # 指定具体版本,最稳 # 私有仓库完整写法 docker pull registry.example.com/myproject/api:v2.3.1 # pull 失败时检查是否需要认证 docker login registry.example.com
⚠️ latest 标签不保证是"最新稳定版",很多镜像维护者根本不怎么更新 latest,导致你 CI 拉到的可能是一年前的版本。生产环境一定要写死具体 tag。
---

案例3:网络模式配置错误导致容器互通失败

容器启动了,进程也在跑,但容器之间互相访问不到,比如 MySQL 容器明明起来了,API 容器却连不上。

🚨 报错信息
Error: connect ECONNREFUSED 172.18.0.2:3306
🔍 诊断
# 查看容器网络情况 docker network ls docker inspect <container_name> | jq '.[0].NetworkSettings.Networks' # 进入某个容器测试网络连通性 docker exec -it <container_name> ping <target_container> docker exec -it web curl http://db:3306 # 容器名作为 hostname 直接用 # 查看当前 Docker 网络 docker network inspect bridge
🛠️ 修复

docker-compose 的 networks 把相关容器放进同一个网络,这是最推荐的方式:

# docker-compose.yml version: "3.8" services: web: image: myapp:latest networks: - backend db: image: mysql:8 networks: - backend networks: backend: driver: bridge
# 手动创建一个 bridge 网络并把容器加入 docker network create mynet docker network connect mynet <container_a> docker network connect mynet <container_b>
💡 Docker 默认用 bridge 网络,但同一个宿主机上的两个容器默认情况下不在同一个网络里,需要通过 --network 或 docker-compose 显式声明才能互通。
---

案例4:挂载目录权限不够,容器里写不了文件

容器启动参数加了 -v /data:/app/data,但应用启动时报"Permission denied",或者构建时文件所有者是 root。

🚨 报错信息
Permission denied: '/app/data/config.yml'
EACCES: permission denied, open '/app/data/logs/app.log'
🔍 诊断
# 查看容器挂载点和宿主机目录权限 docker inspect <container_name> | jq '.[0].Mounts' # 查看宿主机目录 ls -la /data id # 查看容器内运行用户 docker exec -it <container_name> id docker exec -it <container_name> whoami
🛠️ 修复
# 方案A:在宿主机先建好目录并设好权限 sudo mkdir -p /data sudo chown -R 1000:1000 /data # 1000:1000 是很多默认容器用户的 UID/GID # 方案B:运行时指定用户(如果容器支持) docker run -v /data:/app/data -u 1000 myapp:latest # 方案C:docker-compose 里指定 user # services: # app: # user: "1000:1000" # volumes: # - /data:/app/data # 方案D:使用 ACL(更精细控制) setfacl -R -m u:1000:rwX /data
🔑 容器内 root(UID 0)和宿主机 root 是不同的,但在 volume 挂载场景下,宿主机 root 权限会渗透进去——所以会出现宿主机 root 创建的文件,容器内非 root 用户无法写入的情况。
---

案例5:ENTRYPOINT / CMD 脚本语法错误

Dockerfile 写得很标准,镜像也构建成功了,但容器一启动就退出,日志里只有一个模糊的 exit code。

🚨 报错信息
Error: spawner failed to start: exit status 1
docker: Error response from daemon: oci runtime error: exit status 1
🔍 诊断
# 查看容器退出状态码和日志 docker logs <container_name> --tail 50 docker wait <container_name> docker inspect <container_name> | jq '.[0].State'
🛠️ 修复

先看一个典型的错误 Dockerfile:

# ❌ 错误:CMD 里直接写 shell,路径没加引号 CMD python app.py --port 8080 # ✅ 正确:exec 形式(JSON 数组),加引号 CMD ["python", "app.py", "--port", "8080"] # ❌ 错误:ENTRYPOINT 用 shell 形式会导致 SIGINT 无法传递 ENTRYPOINT python app.py # ✅ 正确:用 exec 形式 ENTRYPOINT ["python", "app.py"]

如果用了 shell 脚本做入口点,注意脚本里要有 exec "$@" 来传递信号:

#!/bin/sh # entrypoint.sh — 正确写法 set -e echo "Starting app with args: $@" exec "$@" # 关键!把信号正确传递给主进程
---

案例6:docker-compose.yml 配置格式踩坑

docker-compose 语法版本不对,或者缩进、空格、引号问题导致配置解析失败。

🚨 报错信息
ERROR: yaml.scanner.ScannerError: while scanning a simple key
ERROR: service 'web' must be a mapping
🔍 诊断
# 先检查 YAML 语法(不用启动容器就能检查) docker-compose config --quiet # 无输出 = 语法OK,有报错会直接显示 # 版本检查 docker-compose --version
🛠️ 修复
# 常见错误1:services 下缩进不对(必须是2空格) # ✅ services: web: image: nginx # ❌(用了 tab 或 4空格) # 常见错误2:ports 写成数字没引号(某些版本报错) # ✅ ports: - "8080:80" # ✅ 也可以 ports: - 8080:80 # 常见错误3:depends_on 只写了名字,但需要显式 version version: "3.8" services: web: depends_on: - db environment: - DB_HOST=db
⚠️ docker-compose v2 开始默认用空格缩进,tab 一定会报错。另外 docker-compose config 能把最终合并后的配置输出来,怀疑有覆盖冲突时用这个命令非常管用。
---

案例7:容器退出后想看日志却不知道从哪看

容器跑了几秒就退出了,docker logs 拿不到任何内容,因为进程在启动脚本里又起了子进程。

🚨 报错信息
container is not running
🔍 诊断
# 查看容器状态(含历史) docker ps -a | grep <container_name> # 强制进入已退出容器(如果想调试) docker start -ia <container_name> # 查看详细状态信息 docker inspect <container_name> | jq '.[0].State' # 看容器内进程(容器必须在运行状态) docker top <container_name>
🛠️ 修复

容器已经退出了?不要慌,先找残余信息:

# 即使容器退出了,日志通常还在(Docker 保留容器文件系统) docker logs <container_name> --tail 200 --details # 查看容器文件系统(进入容器临时重新启动) docker commit <container_name> temp_debug_image docker run -it --rm temp_debug_image /bin/sh # 如果是 entrypoint 脚本有问题,直接用 sh 启动看哪里报错 docker run --rm -it <image_name> /bin/sh
✅ 小技巧:docker-compose up --abort-on-container-exit 可以让 docker-compose 在任何一个容器退出时立即停止并显示输出,排查 entrypoint 脚本问题时非常有用。
---

案例8:docker inspect 挖出隐藏配置问题

docker inspect 是被严重低估的排查工具。容器启动失败时,90%的隐藏问题都能从这里找到答案。

🚨 常见疑问:为什么镜像里有 ENV,容器里读不到?
# 查看容器所有环境变量 docker inspect <container_name> | jq '.[0].Config.Env' # 查看容器启动命令(和实际运行的是否一致) docker inspect <container_name> | jq '.[0].Config.Cmd' docker inspect <container_name> | jq '.[0].Config.Entrypoint' # 查看容器的 mounts(挂载点详情) docker inspect <container_name> | jq '.[0].Mounts' # 查看 Restart policy docker inspect <container_name> | jq '.[0].HostConfig.RestartPolicy'
🛠️ 实战组合拳
# 一次性拿到关键信息(快速定位问题) docker inspect <container_name> | jq '{ State: .[0].State, Env: .[0].Config.Env, Cmd: .[0].Config.Cmd, Mounts: .[0].Mounts, NetworkSettings: .[0].NetworkSettings.Networks, RestartPolicy: .[0].HostConfig.RestartPolicy }'
💡 jq 是神器,上面的组合拳可以一次性拿到所有关键配置,省去来回敲命令的时间。macOS/Linux 安装:brew install jqapt install jq
---

案例9:OOMKilled — 内存限制太小被 kill

容器进程明显在跑,但一会儿就没了。查日志什么都没有,因为进程被宿主机直接 kill 了。

🚨 报错信息
Killed
docker: Error response from daemon: Cannot kill container: ...
exit code 137(128 + 9,OOM SIGKILL 的标准退出码)
🔍 诊断
# 查看容器退出原因(OOM Killed 会在这里显示) docker inspect <container_name> | jq '.[0].State' # 典型输出: # { span class="comment"># "Status": "exited", # "ExitCode": 137, # "OOMKilled": true, <--- 重点看这里 # "Error": "" # } # 宿主机层面验证是否真的 OOM dmesg | grep -i "killed process" | tail 10
🛠️ 修复
# 方案A:调高内存限制(docker run) docker run -d --memory=512m --memory-swap=1g myapp:latest # 方案B:docker-compose 里配置 # services: # app: # mem_limit: 512m # mem_reservation: 256m # 方案C:设成不限制(仅测试用) docker run -d --memory="" myapp:latest
🚨 退出码 137 = OOM(SIGKILL),128 + 9。退出码 143 = SIGTERM(正常停止)。退出码 1 = 应用自己报错退出。搞清楚这三个码,能省一半排查时间。
---

案例10:Docker daemon 本身挂了

最隐蔽的情况:所有命令都报错,但你以为是你自己的配置问题,其实是 Docker 服务本身崩了。

🚨 报错信息
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
🔍 诊断
# 检查 Docker 服务状态 sudo systemctl status docker # 或 sudo service docker status # 检查 docker.sock 是否存在 ls -la /var/run/docker.sock
🛠️ 修复
# 重启 Docker 服务 sudo systemctl restart docker # 如果是磁盘空间不足导致 daemon 崩溃 df -h /var/lib/docker # 清理无用镜像和容器 docker system prune -af --volumes
✅ 建议:生产环境的 Docker 服务用 systemctl enable docker 确保开机自启,并且定期监控 /var/lib/docker 的磁盘使用率。
---

🚀 快速排查流程图(总结)

下次容器起不来,按这个顺序走,基本能覆盖 90% 的坑:

1. 看容器状态 → docker ps -a

2. 看退出码 → docker inspect | jq '.[0].State.ExitCode'

   ├─ 退出码 0 = 正常退出,看 CMD/ENTRYPOINT

   ├─ 退出码 1 = 应用报错 → docker logs

   ├─ 退出码 137 = OOM → 调大 --memory

   └─ 退出码 143 = SIGTERM → 检查 restart policy

3. 连容器都建不起来 → 查 docker daemon systemctl status docker

4. 镜像问题 → docker pull + docker images

5. 端口问题 → lsof -i :端口

6. 网络互通 → docker network inspect

7. 权限问题 → docker inspect Mounts + 宿主机 ls -la

8. YAML 问题 → docker-compose config

---

☘️ 写不动了?试试这些工具——

https://clovertools.cn/tools/dev-tools/docker-run.html

Docker 启动命令生成器 · 一键复制 · 支持 docker & docker-compose

首发于 CloverTools · 助你少加班,多摸鱼 🐟

💡 遇到同类问题?用工具快速解决

试试这些配套工具,无需注册,打开即用

浏览所有工具

常见问题

Q: 如何使用 docker容器启动失败排查指南 相关工具?
A: 这类工具一般有明确的输入框和输出框,按提示输入内容,点击对应按钮即可得到结果。建议先用简单示例测试功能是否正常,再处理实际数据。
Q: docker容器启动失败排查指南 适合在什么场景使用?
A: 根据具体工具类型决定。格式转换工具适合处理第三方数据,编码工具适合加密传输,压缩工具适合文件上传前处理。多积累工具使用经验,遇到问题时能快速判断用哪个工具解决。
Q: 有没有更好的替代工具?
A: 不同工具有不同侧重,重点是理解原理。可以同时安装多个类似工具,实际使用中对比效果,选择最顺手的一个。随着使用经验增加,你也能判断工具的好坏。