前言

说实话,Docker 容器启动失败这事儿,几乎每个用 Docker 的人都踩过坑。有时候明明本地跑得好好的,一到服务器就给你来个 exit code 1,真的让人头大。

我之前在部署一个微服务项目的时候,连续碰到了端口被占用、挂载目录权限不够、日志看不懂这三大经典问题。花了整整一个下午才搞定,当时就想:要是有人把这些坑都总结出来该多好。

今天就把我的排查经验分享出来,希望能帮你少走弯路。

Docker容器排查实战

一、端口冲突:最常见的"拦路虎"

1.1 症状表现

启动容器时报这样的错:

docker: Error response from daemon: driver failed programming external connectivity on endpoint my_container
Bind for 0.0.0.0:8080 failed: port is already allocated

或者用 docker-compose up 的时候:

ERROR: for web  Cannot start service web: driver failed programming external connectivity

1.2 排查步骤

第一步:看看是谁占了端口

# Linux/Mac
sudo lsof -i :8080
# 或者
sudo netstat -tlnp | grep 8080

# Windows (PowerShell)
Get-NetTCPConnection -LocalPort 8080

第二步:根据情况处理

  • 如果是之前的 Docker 容器没停干净:
    docker ps -a  # 查看所有容器
    docker rm -f <container_id>  # 强制删除
    
  • 如果是宿主机上其他服务占用了端口:改映射端口,比如把 8080:80 改成 8081:80
  • 如果是系统保留端口(Windows 常见):用 netsh interface ipv4 show excludedportrange protocol=tcp 查看保留端口范围

端口冲突排查

1.3 预防措施

在 docker-compose.yml 里用变量管理端口:

services:
  web:
    ports:
      - "${WEB_PORT:-8080}:80"

这样不同环境可以用不同的端口,避免冲突。

二、日志分析:读懂 Docker 在"说"什么

2.1 看日志的正确姿势

很多新手只会用 docker logs <container>,其实还能加很多参数:

# 看最近 100 行
docker logs --tail 100 my_container

# 实时跟踪(类似 tail -f)
docker logs -f my_container

# 看指定时间之后的日志
docker logs --since 2024-01-01T10:00:00 my_container

# 带时间戳
docker logs -t my_container

2.2 常见错误日志解读

错误信息可能原因解决方案
OOMKilled内存不足增加内存限制或优化程序
Permission denied权限问题检查文件权限或用 --privileged
No such file or directory挂载路径错误检查 volumes 配置
Connection refused依赖服务未启动检查 depends_on 和健康检查

2.3 容器启动失败但没有日志?

这种情况一般是容器根本没跑到你的应用代码。试试:

# 查看容器详细信息
docker inspect my_container

# 看看 State 和 Error 字段
docker inspect --format='{{.State.ExitCode}}' my_container
docker inspect --format='{{.State.Error}}' my_container

日志分析技巧

三、权限问题:Linux 上的"经典坑"

3.1 挂载目录权限不足

这是 Linux 环境下最常见的问题之一。比如你把宿主机的目录挂载到容器里,结果容器里的进程没权限读写:

Error: EACCES: permission denied, open '/app/data/config.json'

原因: 宿主机目录的所有者 UID 和容器内进程的 UID 不一致。

解决方案:

# 方案1:修改宿主机目录权限(开发环境推荐)
sudo chown -R 1000:1000 /path/to/mount

# 方案2:在 Dockerfile 里创建对应用户
RUN groupadd -g 1000 appuser && useradd -u 1000 -g appuser appuser
USER appuser

# 方案3:用 --user 参数指定 UID
docker run --user $(id -u):$(id -g) -v /path:/app my_image

3.2 SELinux 导致的权限问题

如果你的系统开了 SELinux(CentOS/RHEL 默认开启),挂载目录时需要加 :z 或 :Z 标签:

# :z 表示共享标签(多容器共享)
docker run -v /data:/data:z my_image

# :Z 表示私有标签(仅当前容器使用)
docker run -v /data:/data:Z my_image

四、实战案例:从报错到解决的完整流程

来看一个真实场景:一个 Node.js 应用在 Docker 里启动失败。

报错信息:

Error: Cannot find module '/app/server.js'

排查过程:

  1. 先看 Dockerfile 的 COPY 指令:

    COPY . /app
    WORKDIR /app
    CMD ["node", "server.js"]
    
  2. 检查 .dockerignore 文件,发现里面写了 *.js,把所有 JS 文件都排除了

  3. 修改 .dockerignore,重新构建镜像

  4. 问题解决

教训: .dockerignore 的配错率比你想象的高得多,构建前最好检查一下。

五、排查清单(收藏备用)

遇到容器启动失败,按这个顺序排查:

  1. 看退出码 docker ps -a → 看 STATUS 列
  2. 看日志 docker logs --tail 50 <container>
  3. 看详细信息 docker inspect <container>
  4. 检查端口 lsof -i :<port> 或 netstat
  5. 检查挂载 确认路径存在且有权限
  6. 检查网络 docker network ls → 确认网络配置
  7. 检查资源 docker system df → 确认磁盘空间

排查清单总结

总结

Docker 容器启动失败看起来很吓人,但大多数情况都是那几个经典问题:端口冲突、权限不足、日志报错、配置写错。掌握了排查思路,基本上 10 分钟内就能定位问题。

说实话,用 Docker 这几年,我踩过的坑比写过的 Dockerfile 还多。但每次踩坑都是一次成长,关键是要学会看日志、读文档、善用搜索引擎。

你在使用 Docker 的过程中遇到过什么奇葩问题?欢迎在评论区分享,说不定能帮到其他人。

更多推荐