Docker 出问题时怎么查:不重装,像物业一样找到是哪间房出了问题

当 Docker 报错时,很多人会做同一件事:关掉 Docker Desktop,重开;不行就删容器;再不行就重装。

这样做有时真的能“暂时好了”,但它没有让你知道问题出在哪里。下次遇到同样的问题,你还是会焦虑。

更麻烦的是:如果你在不知道数据卷作用的情况下乱删,真正重要的数据反而可能被误删。

所以这篇文章先给你一条最重要的原则:

Docker 出问题时,先看状态,再看日志,再看连接。最后才考虑删除重建。

你不需要成为运维工程师。你只需要把 Docker 当成一栋楼:

  • 打不开网页,先看楼外门牌有没有挂好;
  • 两个服务连不上,先看内部电话线有没有接上;
  • 容器一直重启,先看房间里开门后发生了什么;
  • 数据不见了,先看是不是接错了储物柜;
  • 权限报错,先看谁没有拿到该有的钥匙。

按这个顺序排查,绝大多数新手问题都不会再显得神秘。


先把这 5 条“救火命令”收藏起来

你不需要一次学会几十条命令。下面五条足够覆盖最常见情况。

命令 它在生活中像什么 你用它回答什么问题
docker compose ps 看整栋楼的入住名单 n8n 和数据库到底有没有在运行?
docker compose logs -f n8n 调出 n8n 房间的监控记录 n8n 为什么启动失败或重启?
docker compose logs -f postgres 调出数据库房间的监控记录 数据库有没有正常准备好?
docker compose config 让物业把配置册重新读一遍 变量、端口、缩进最后到底是什么样?
docker inspect 容器名 查房屋档案 实际挂了什么端口、网络、数据卷?

你会发现,这些命令不是用来“修复”的,而是用来先看清事实的。

这非常重要。因为 Docker 的很多问题不是程序坏了,而是你以为它按 A 方式启动了,实际上它按 B 方式启动了。


情况一:浏览器打不开 n8n

你输入:

http://localhost:5678

浏览器却说无法访问 。

先不要改端口,也不要删容器。请先在 n8n 的配置文件夹中输入:

docker compose ps

你会看到类似下面几种结果。

结果 A:n8n 显示 running,并且有端口

例如:

127.0.0.1:5678->5678/tcp

这表示:楼外的 5678 门牌已经接到 n8n 房间里的 5678 窗口。此时如果浏览器仍打不开,再看日志:

docker compose logs --tail=100 n8n

重点不要只看最后一句。往上找第一条真正的 ERROR,它通常才是原因。

结果 B:n8n 根本没有 running

这表示房间并没有正常开门。可能是它刚启动就失败了。

立刻执行:

docker compose logs -f n8n

然后观察最早出现的错误。最常见的是数据库连不上、环境变量没填、端口被占用,或者 YAML 配置没有按预期加载。

结果 C:n8n 在运行,但没有显示端口

这说明 n8n 房间在楼里营业,但你没有给它挂对外门牌。

检查 compose.yaml 是否包含:

ports:
  - "127.0.0.1:5678:5678"

如果没有,添加后执行:

docker compose up -d

情况二:提示 port is already allocated

你可能看到过这句话:

Bind for 0.0.0.0:5678 failed: port is already allocated

先把它翻译成人话:

这栋楼外的 5678 门牌,已经被别的店铺占用了。Docker 不能把同一个门牌同时挂给两个房间。

这不代表 n8n 坏了,也不代表 Docker 必须重装。

你有两种选择

第一种:原来占用 5678 的服务已经不用了。

先找出 Docker 中正在运行的容器:

docker ps

确认名称后,再停止并删除那个不再需要的旧容器:

docker stop 旧容器名
docker rm 旧容器名

第二种:你想让两个服务同时存在。

那就改 n8n 的左边端口:

ports:
  - "127.0.0.1:18080:5678"

现在的意思是:

  • 楼外的新门牌叫 18080;
  • n8n 房间内原来的窗口仍然叫 5678。

浏览器改为打开:

http://localhost:18080
改端口时 ,优先改左边。左边是你电脑的门牌,右边是 n8n 房间内部习惯使用的窗口。

情况三:n8n 提示数据库连接失败

这是最常见、也最容易被“localhost”带偏的问题。

你可能会看到类似:

Connection refused

或者:

Could not connect to database

先别慌。把它想成 n8n 想给数据库打电话,但电话没有接通。原因只会在三类地方:数据库房间没开门、电话线没接上、号码拨错了。

第一步:确认数据库真的开门了

docker compose ps postgres

如果 PostgreSQL 不是 running,请看它自己的日志:

docker compose logs --tail=100 postgres

不要先盯着 n8n。n8n 只是打电话的人;如果接电话的数据库房间根本没开门,先修数据库才有意义。

第二步:确认号码没有写成 localhost

请检查 n8n 配置是否是:

DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432

不要写:

DB_POSTGRESDB_HOST: localhost

为什么?

因为 n8n 容器里的 localhost,指的是 n8n 房间自己。它不是你的电脑,也不是 PostgreSQL 房间。

正确的 postgres 是内部电话簿中的房间名;5432 是 PostgreSQL 房间里的接待号码。

第三步:确认密码小信封没有写错

执行:

docker compose config

它会把 .env 里的变量代入并展示最终配置。你要确认:

  • POSTGRES_PASSWORD 不是空的;
  • n8n 和 PostgreSQL 使用的是同一组变量;
  • .env 确实和 compose.yaml 放在同一个文件夹。

如果你在 .env 中写错变量名,Docker 不会猜你的意思。它只会按实际看到的内容运行。


情况四:容器一直重启,像“活不过十秒”

在 Docker Desktop 中看到容器不断从 Restarting 变成 Up,又很快回到 Restarting,通常不是 Docker 在抽风。

它表示:房间打开了,但里面的主程序一启动就遇到问题;由于你设置了:

restart: unless-stopped

物业会不断尝试重新开门。

这时最有价值的不是重启 Docker Desktop,而是:

docker compose logs -f 服务名

例如:

docker compose logs -f n8n

从第一条 ERROR 开始看。常见原因包括:

  • 数据库尚未准备好;
  • .env 中的变量为空;
  • 端口冲突;
  • 配置文件缩进错误;
  • 更新镜像后,某个旧配置不再适用。

你可以把日志理解成房间里的监控录像。房间为什么关门,录像通常比猜测可靠得多。


情况五:重建后,工作流或凭据“看起来没了”

这时请先停下。不要再执行任何 prune、不要随手删 volume、也不要立刻重新注册一套全新的 n8n。

你要先判断:资料是真的没了,还是新房间没有接回原来的储物柜。

第一步:看储物柜还在不在

docker volume ls

找到名称里带有 n8n_data 的 volume。Compose 可能在前面加上项目名,这是正常的。

第二步:看当前 n8n 是否接对了柜子

docker inspect n8n

在输出中查找 Mounts。你希望看到:

  • Type 是 volume;
  • 名称与之前的数据卷对应;
  • 容器内目标路径是 /home/node/.n8n。

第三步:确认主钥匙没有被换掉

检查 .env:

N8N_ENCRYPTION_KEY=...

它必须与原先部署时使用的值一致。

数据卷像储物柜,N8N_ENCRYPTION_KEY 像保险文件的主钥匙。柜子还在,不代表换了钥匙后仍能顺利打开加密内容。

最危险的一条命令

docker compose down -v

普通的 docker compose down 只是关房、拆掉容器;带 -v 则会连这个项目的储物柜一起删除。

除非你明确要“从零开始且不要任何旧数据”,否则不要使用 -v。

Docker 官方也提醒,volume 独立于容器生命周期;它能在容器删除后保留数据,但在你明确删除 volume 时,数据当然也会被清除。Docker 官方说明


情况六:提示 permission denied

这句话的意思是:程序找到了文件柜,但没有钥匙。

它最常发生在你使用类似下面的配置时:

volumes:
  - ./某个本机文件夹:/workspace

这叫 bind mount,意思是把电脑上真实的文件夹直接搬进容器。它很方便,但也会把宿主机的权限问题一起带进来。

新手先这样判断:

  • 如果你只是想保存 n8n 或数据库自己的内部资料,请优先用 named volume。
  • 如果你必须让容器读取电脑上的某个文件夹,再使用 bind mount。
  • 不要一上来就用 chmod -R 777 解决权限。它像为了让员工能拿文件,直接把整个办公室的门全部拆掉,短期省事,长期风险很高。

在 Windows 或 macOS 上,也要确认 Docker Desktop 被允许访问你挂载的文件夹。否则你以为已经把文件箱搬进房间,实际上物业根本不允许搬运。


请记住这张“从外到内”的排查路线

当你下次遇到问题,不用重新翻整篇文章。按下面路线走就可以:

浏览器打不开
  ↓
先看 docker compose ps
  ↓
服务没运行:看 docker compose logs
  ↓
服务运行但打不开:看 ports 是否存在、端口是否被占
  ↓
n8n 连不上数据库:看 postgres 是否运行、地址是否写 postgres、变量是否正确
  ↓
数据不见:先看 volume 和 N8N_ENCRYPTION_KEY,绝不先删除

这套路线的价值在于:你不是在“试命令”,而是在一层层缩小范围。

先站在楼外看门牌,再进入楼里看哪间房,最后才检查房间里的电话线、储物柜和钥匙。这样一来,Docker 就不再像一个黑箱。


结尾:你不需要怕 Docker,但要养成正确的顺序

Docker 真正让人焦虑的,从来不是命令本身,而是“我不知道删掉会发生什么”。

而你现在已经掌握了最实用的安全感来源:

容器可以重建;日志用来找原因;端口决定入口;网络决定谁能通信;数据卷和密钥决定成果能不能回来。

下一次出问题时,先不要重装。先打开终端,运行:

docker compose ps

从这一行开始,你就已经比过去那个只能靠猜的自己,更接近真正能掌控 Docker 了。