什么是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。最好的做法通常是:
- n8n 与 PostgreSQL 放到同一个私有网络;
- n8n 使用
postgres:5432访问数据库; - 不给 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 的工作流、凭据和历史执行记录不能随着房间一起被拆掉。下一篇我们讲“数据卷”:为什么它像独立储物柜,容器删了,资料仍然在。