遇到 Compose 启动报端口冲突,最稳妥的办法是先查明占用端口的进程,再决定是停止该进程还是修改 Compose 配置。
先说结论:端口被占用通常是因为宿主机上已有服务监听了相同端口,强行启动会导致绑定失败。
- 先确认报错中具体是哪个端口冲突
- 先处理占用进程或修改映射端口
- 再验证服务能否正常访问
命令速用版
如果你已经知道冲突的端口号(例如 8080),可以直接使用以下命令查找占用者:
Linux / macOS:
lsof -i :8080 或 ss -tulpn | grep 8080
Windows (PowerShell):
netstat -ano | findstr :8080
找到进程 PID 后,确认无误可强制结束:
kill -9 <PID> (Linux/macOS)
为什么会这样
TCP/IP 协议规定,在同一网络接口上,一个端口同一时间只能被一个进程绑定。Docker Compose 启动时,如果配置了端口映射(ports),它需要让宿主机的某个端口监听流量并转发给容器。如果宿主机上已经有一个程序(可能是另一个容器、本地安装的服务如 Nginx/MySQL,甚至是僵尸进程)占用了该端口,Docker 守护进程就无法完成绑定,从而抛出 Address already in use 错误。
这不代表 Docker 坏了,而是操作系统在保护网络资源不被重复占用。
分步处理
1. 确认冲突端口
查看 Compose 启动报错日志,通常会明确写出 bind failed: Address already in use,后面会跟着端口号,例如 0.0.0.0:8080。
2. 查找占用进程
使用上文“命令速用版”中的命令查找占用该端口的进程。注意查看进程名称(COMMAND 列),判断它是你需要的服务还是无关程序。
3. 决策处理
- 情况 A:占用进程是无用的或卡死的。直接结束该进程。例如
kill -9 <PID>。 - 情况 B:占用进程是重要服务(如宿主机自带的 Nginx)。不要强行关闭。修改
docker-compose.yml中的 ports 映射,将宿主机端口改为未被占用的端口。例如将8080:80改为8081:80。 - 情况 C:是另一个 Docker 容器占用的。使用
docker ps查找该容器,决定是停止它(docker stop)还是修改当前项目的端口配置。
4. 重新启动
执行 docker compose up -d 重新拉起服务。
怎么验证是否生效
1. 检查容器状态
运行 docker compose ps,确认所有服务状态为 Up 且没有重启循环。
2. 检查端口监听
再次运行 ss -tulpn | grep <端口号>,确认监听该端口的进程名称已变为 docker-proxy 或预期的容器名。
3. 业务访问测试
使用浏览器或 curl 访问该端口,确认服务响应正常。如果修改了端口,记得更新访问地址。
常见坑
1. 误杀系统服务
在 Linux 上,80、443 等端口可能被系统服务占用。结束进程前务必确认进程名,避免导致宿主机管理界面失联。
2. IPv6 绑定问题
有些时候 IPv4 端口空闲,但 IPv6 占用会导致绑定失败。如果确认端口未被占用仍报错,尝试在 Compose 配置中指定绑定 IP,如 127.0.0.1:8080:80。
3. 容器端口与宿主机端口混淆
修改配置时,冒号左边是宿主机端口(冲突源),右边是容器内部端口(通常不用改)。只修改左边即可解决冲突。
4. 僵尸进程残留
有时容器已停止但端口未释放,等待几分钟或重启 Docker 服务(systemctl restart docker)可清理残留绑定。