DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Docker 端口已被占用:改了 Compose 映射为什么仍报错

从网友修改测试端口后仍冲突的案例出发,检查 Compose 最终映射、其他容器和宿主机占用,并按工具版本选择配置修复办法。

运行 docker compose up -d 时提示 port is already allocated,你检查了宿主机端口,却没有找到明显的监听进程。接着改了测试配置中的端口,再启动还是同一个错误。这个场景要先检查 Compose 最终生效的端口映射:后一个文件里的 ports 不一定替换前一个文件。

改了端口,旧映射为什么还在

检查合并结果,而不只看刚修改的文件。 当前 Compose 的合并规则会保留不同的端口条目;端口的唯一性与目标端口、发布端口、IP 和协议有关。

下面是说明问题的配置片段,服务名和端口均为示例:

# compose.yaml
services:
  web:
    image: nginx:stable
    ports:
      - "8080:80"
# compose.test.yaml
services:
  web:
    ports:
      - "8081:80"

你可能期望只发布 8081;普通合并却可能同时保留 8080 和 8081。即使 8081 空闲,8080 被另一个项目占用,启动也会失败。容器内的 80 与宿主机的 8080 是两个不同位置,排查时看报错中的发布地址和端口。

用启动时同一组参数查看配置

如果实际启动使用两个文件和项目名,查看配置也要带相同参数:

docker compose -p app-test -f compose.yaml -f compose.test.yaml config
docker compose -p app-test -f compose.yaml -f compose.test.yaml ps -a

config 会展开变量并展示合并后的模型。它的输出可能包含密码或连接串,分享前删去敏感值。重点找 web 的 ports:报错端口是否仍在其中,是否有另一个服务发布同一个地址、端口和协议。若启动脚本还设置了 COMPOSE_FILE 或额外的 -f,一并核对,避免检查了一份根本没被启动使用的配置。

如果合并结果正确,再查整个 Docker 环境和宿主机,而不是只查当前项目:

docker ps --format 'table {{.Names}}\t{{.Ports}}'
# Linux 宿主机;8080 换成报错中的发布端口
sudo ss -ltnp 'sport = :8080'
# macOS 宿主机可查看 TCP 监听
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN

这几条命令只读取状态。docker ps 用来找其他项目的端口发布;ss 或 lsof 用来找宿主机监听程序。Linux 的端口发布还可能涉及转发规则,因此没有看到一个普通监听进程,不能单凭这一点排除 Docker 端口冲突。涉及 Docker Desktop 时,先记录实际版本,不要把旧版本的缺陷当作当前环境的根因。

根据冲突位置改配置

如果两个环境要同时运行,最直接的办法是让基础文件只描述共同服务,把 ports 分别放入开发和测试文件。这样每次只合并一个环境文件,不会先继承一个不需要的发布端口。这也方便检查哪一层决定公网入口。

Compose 2.24.4 或更新版本支持用 !override 完全替换一个属性。例如:

services:
  web:
    ports: !override
      - "127.0.0.1:8081:80"

先运行 docker compose version 确认版本,再决定是否使用这段语法。较旧工具无法解析时,采用拆分环境文件的办法。绑定 127.0.0.1 只允许宿主机本地访问,适合由宿主机反向代理转发的场景;需要远程直连时不能机械套用这个地址。

如果冲突来自另一项真实服务,应选择新的宿主机端口,或在确认用途后安排停止那项服务。不要直接杀掉未知进程,也不要为修复端口问题执行删除数据卷的命令。修改映射会重建相关容器并影响连接,先保存原配置;回退时恢复原文件和原来的启动参数。

怎样确认这次改的是正确位置

再次查看同参数的 config,确认只剩预期映射;启动后用 ps 查看实际发布端口,再从预期入口访问应用。三处结果应对应起来:配置声明的宿主机端口、容器实际发布的端口、客户端访问的端口。

如果配置已经没有冲突,仍报分配失败,把 Docker/Compose 版本、脱敏后的合并配置和容器端口列表保留下来,再查对应版本的问题。不要把一次服务重启后恢复,直接当作端口冲突已经解释清楚。