什么是docker端口:用打电话来举例

系列第二篇:端口不是一个神秘数字。它更像门牌、接待窗口和楼内电话线的组合。

很多刚接触 Docker 的人会遇到一个矛盾画面:Docker Desktop 显示 n8n 正在运行,日志也没有报错,但浏览器打开 http://localhost:5678 却没有反应 。另一个常见问题是,教程写着 5678:5678,两个一样的数字到底为什么要写两次?

答案是:Docker 把“楼外入口”和“房间内入口”分开了。

先记一句话:端口映射是“把楼外门牌,接到房间内的门”

假设你的电脑是一栋大楼,Docker 容器是楼里的房间。n8n 这个房间内部已经有一个接待窗口,编号是 5678。但楼外的人并不知道该怎么走到这里。你需要在大楼外再挂一个门牌,并告诉前台:所有来到这个门牌的人,都转接到 n8n 房间的 5678 号窗口。

这就是:

ports:
  - "5678:5678"
写法位置 生活化解释 技术上真正指向什么
左边第一个 5678 大楼外面的门牌 宿主机端口,浏览器访问 localhost:5678 时敲的门。
右边第二个 5678 n8n 房间里面的接待窗口 容器端口,n8n 程序实际监听的端口。
HOST_PORT:CONTAINER_PORT。左边属于你的电脑,右边属于容器内部。两边相同只是巧合,不是规定。

Docker 官方文档的例子 -p 8080:80 就是把宿主机 8080 的访问转发到容器内 80 端口。1

为什么 5678:5678 可以改成 18080:5678?

如果你电脑上的 5678 已经被别的软件占用,或者你只是想让本地门牌更容易区分,可以这样写:

ports:
  - "18080:5678"

现在浏览器应该访问:

http://localhost:18080

而容器里的 n8n 仍然在 5678 工作 。就像大楼外门牌改成了 18080,但房间里面的窗口编号不需要改变。

这也是排查端口问题时最重要的思路:先问是哪一边出了问题。

  • 浏览器访问的地址,关注左边的宿主机端口。
  • 应用程序文档说“n8n 默认使用 5678”,通常指右边的容器端口。
  • 容器之间互相访问时,通常也使用右边的容器端口,而不是你映射到电脑上的左边端口。

ports、EXPOSE 和“我能打开网页”不是同一件事

你有时会在镜像说明里看到 EXPOSE 5678。它像施工图上的标注:“这个房间预计会用 5678 号窗口。”但这并没有替你在楼外挂牌。

只有 -p / --publish 或 Compose 里的 ports,才会真正建立从宿主机到容器的转发规则。Docker 官方明确说明,镜像里的 EXPOSE 不会自动发布端口。1

容器网络不相通,是什么意思?

继续使用大楼比喻。假设一层楼里有 n8n 房间和 PostgreSQL 数据库房间。它们虽然都在同一栋楼里,但默认不代表你随便喊一声就能互相听见。每个容器都有自己的网络空间和地址,外部访问、容器间访问、不同网络中的访问是三件不同的事。

“网络不相通”可以理解为:两个房间不在同一个内部电话分组,前台不知道该如何把一个房间的呼叫转给另一个。此时就要把它们接进同一个 Docker 自定义网络。

docker network create app-net

这条命令相当于给大楼增加一个“项目组电话网”。然后把两个房间接进去:

docker network connect app-net n8n
docker network connect app-net postgres

在同一个自定义网络里,容器可以通过容器名通信。Docker 官方文档说明,连接到同一自定义网络的容器可通过容器名或 IP 通信;相比之下,默认 bridge 网络中的容器不能按名称互相引用。2

“打通网络”不是把所有端口暴露给外网

这是最容易被误解的地方。

假设 n8n 需要访问 PostgreSQL。最好的做法通常是:

  1. n8n 与 PostgreSQL 放到同一个私有网络;
  2. n8n 使用 postgres:5432 访问数据库;
  3. 不给 PostgreSQL 配置 ports,这样浏览器和局域网其他设备不能直接敲数据库的门。

此时“打通”只表示房间之间接上内部电话线,不表示把数据库窗口暴露到整栋楼外。

services:
  n8n:
    image: n8nio/n8n
    networks:
      - automation-net

  postgres:
    image: postgres:16
    networks:
      - automation-net

networks:
  automation-net:

上面的配置没有为 PostgreSQL 写 ports。n8n 仍可通过服务名 postgres 找到它,因为二者在同一个 Compose 网络中;外部浏览器却不能直接访问 PostgreSQL 的 5432 端口。

为什么 Compose 里经常没有显式写 networks?

Docker Compose 会为同一个项目创建默认网络,并把服务放进去。因此,一个普通的 compose.yaml 中,即使没有显式 networks,n8n 通常也能通过服务名访问 postgres。显式写出网络的价值是:当项目开始复杂、需要区分“对外服务”和“内部服务”时,配置意图会更清楚。

你可以把它理解为:小型合租房默认大家在同一微信群;当楼层多起来后,最好建“前台群”“内部群”“数据库群”,而不是让所有人都在一个群里。

用 n8n 练习一次端口和内部网络

新建一个空目录,创建 compose.yaml:

services:
  n8n:
    image: n8nio/n8n:latest
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_ENCRYPTION_KEY=请替换为一串足够长的随机字符
    networks:
      - automation-net

networks:
  automation-net:

这里每一行的意思是:

配置 你在做什么 为什么需要它
services 登记本项目有哪些房间 Compose 以服务为单位管理容器。
image 指定使用哪套样板房 Docker 会按镜像创建 n8n 容器。
127.0.0.1:5678:5678 只在本机大厅挂出 5678 门牌 访问限于本机,局域网其他设备无法直接打开。
N8N_ENCRYPTION_KEY 设置 n8n 的重要加密钥匙 用于保护 n8n 中保存的凭据;不要随意更换。
networks 把 n8n 接入项目内部电话网 方便后续与数据库等服务协作。

启动:

docker compose up -d

然后在浏览器打开:

http://localhost:5678

“打不开”时 ,用这一张表排查

现象 更像哪种问题 先检查什么
浏览器显示无法连接 大楼外门牌没有挂好 docker ps 是否显示 127.0.0.1:5678->5678/tcp;Compose 是否已启动。
报 port is already allocated 该门牌已被别的店铺占用 改左侧宿主机端口,例如 18080:5678。
容器运行,但另一容器连不上数据库 房间没有接进同一个内部电话网,或地址写错 使用同一 Compose 项目 / 自定义网络;地址用服务名如 postgres。
你在局域网另一台电脑打不开 端口只绑定在 127.0.0.1 这是预期安全行为;不要为了测试直接暴露敏感服务。
服务暴露后被外网扫描 楼外门牌对所有网络接口开放 优先使用 127.0.0.1,需要对外访问时再通过反向代理、认证和 HTTPS 设计。
Docker 默认发布端口时会监听所有宿主机网络接口。对于数据库、管理后台等敏感服务,应谨慎发布端口;绑定到 127.0.0.1 可以限制为本机访问。1

下一篇预告

容器可以随时删除重建,这很好;但 n8n 的工作流、凭据和历史执行记录不能随着房间一起被拆掉。下一篇我们讲“数据卷”:为什么它像独立储物柜,容器删了,资料仍然在。

参考资料

[1]Docker Docs — Publishing and exposing ports

[2] Docker Docs — Networking overview