Appearance
容器排错实战:「起不来、连不上、进不去」怎么破
更新: 8/23/2026 字数: 0 字 时长: 0 分钟
开篇:那些年,联调环境里的容器坑
作为有后端接口开发经验的前端,你大概率遇到过这些场景:
- 后端甩给你一个镜像,让你本地
docker run跑起来自己联调,结果跑起来就秒退; - 联调环境好好的,某天前端页面所有接口都
502,你 F12 看半天,其实是容器挂了或连不上; - 你怀疑后端返回的数据不对,想进容器里看看配置文件和日志,却不知道怎么进去。
这三类问题,就是容器化世界里最高频的「起不来、连不上、进不去」。好消息是:排查它们靠的不是内核知识,而是一套和你调接口高度相似的思路——看现象、定位环节、逐层收敛。 本文跳过晦涩的底层原理,只讲能直接抄作业的排错操作。

在动手前,先记住一个"万能第一步"——先看状态:
bash
docker ps -a # 列出所有容器(-a 包含已停止的),看 STATUS 列STATUS 列就是你的第一份诊断书:
Up 10 minutes→ 活着,问题多半在「连不上」;Exited (1) 5 seconds ago→ 起不来,退出码非 0,去看日志;Restarting→ 反复重启,通常是启动即崩溃在死循环重试。
模块一:起不来 —— 容器启动就退出
常见触发场景
- 后端镜像
docker run后,docker ps里根本看不到它(其实已经 Exited); - 端口被占用、环境变量没配、依赖的数据库还没起来;
- 镜像构建时就有问题(比如启动命令写错)。
分步排错思路
第一步:看退出码和状态。 docker ps -a 看 STATUS。Exited (0) 是正常结束(比如脚本跑完就退,这可能是预期行为);Exited (1)、Exited (137) 等非 0 码就是异常。其中 137 是个高频信号,通常意味着内存超限被 OOM 杀掉(128 + 9,9 是 SIGKILL 信号)。
第二步:看日志——这是 90% 问题的答案所在。 这一步等价于你调接口时看后端的报错堆栈:
bash
docker logs <容器名或ID> # 查看容器的标准输出/错误日志
docker logs --tail 50 <容器名> # 只看最后 50 行,快速定位崩溃点
docker logs -f <容器名> # 实时追踪(像 tail -f),适合看反复重启的日志里一般会明明白白告诉你原因,比如 Error: listen EADDRINUSE :::8080(端口被占)、connection refused(依赖服务没起)、MODULE_NOT_FOUND(依赖没装)。

第三步:如果日志没打出来就崩了(容器起来瞬间就挂,连日志都没来得及写),说明可能是启动命令本身就错了。这时可以覆盖启动命令,进去手动跑:
bash
# 不执行原本的启动命令,而是开一个 shell 进去手动排查
docker run -it --entrypoint /bin/sh <镜像名>
# 进去后手动执行启动命令,直接看报错典型案例:端口占用
你 docker run -p 8080:8080 backend-image,秒退。docker logs 显示 EADDRINUSE 8080。原因:你之前跑的另一个容器/本地进程已经占了宿主机 8080。
解决:换个宿主机端口映射即可,冒号左边改掉,容器内部不用动:
bash
docker run -p 8081:8080 backend-image # 宿主机 8081 → 容器 8080
# 之后前端访问 localhost:8081这和你本地起 dev server 报"端口被占,换个端口"是一模一样的处理逻辑。
模块二:连不上 —— 容器活着,但访问不通
这是最容易让前端困惑的一类,因为"容器明明是 Up 状态,为什么接口就是 connection refused?"。关键是理解:请求从你的浏览器到容器里的服务,要穿过好几层,任何一层断了都连不上。
先分清两种"连不上"
| 类型 | 场景 | 排查方向 |
|---|---|---|
| 外部访问不通 | 浏览器 / Postman 访问 localhost:3000 失败 | 端口映射、服务是否真在监听 |
| 容器间访问不通 | A 容器调 B 容器的接口失败 | 是否同一网络、服务名解析 |

分步排错思路(外部访问不通)
第一步:确认端口映射配了没。
bash
docker ps # 看 PORTS 列,应显示 0.0.0.0:3000->3000/tcp如果 PORTS 列是空的,或者没有 -> 箭头,说明你忘了加 -p 映射。容器内的服务再正常,外面也进不来——就像后端服务只监听了内网,没对外开放。
⚠️ 前端最常踩的坑:容器之间互访不需要端口映射(走内部网络),但你的浏览器在容器网络之外,必须靠端口映射才能进去。别把这两件事搞混。
第二步:确认服务真的在容器内监听了,而且监听的是 0.0.0.0 而非 127.0.0.1。 这是一个极其隐蔽、又极其高频的坑:
bash
docker exec -it <容器名> sh # 进容器(下一模块细讲)
netstat -tlnp # 或 ss -tlnp,看服务监听在哪个地址如果看到服务监听的是 127.0.0.1:3000,那就是问题所在:容器内的 127.0.0.1 只有容器自己能访问,端口映射转发进来的流量根本够不着。解决办法是让你的后端服务监听 0.0.0.0(比如 Node 里 app.listen(3000, '0.0.0.0'))。这个坑几乎每个刚接触容器的人都会中一次。
分步排错思路(容器间访问不通)
第一步:确认两个容器在同一个网络。
bash
docker network ls # 列出所有网络
docker network inspect <网络名> # 看这个网络里挂了哪些容器如果 A、B 不在同一个网络,自然互相找不到。用 Docker Compose 编排的服务默认在同一网络里,一般没这问题;手动 docker run 的容器则可能各在各的默认网络。
第二步:用服务名而不是 localhost 互访。 在 A 容器里调 B,地址要写 B 的服务名,不是 localhost:
bash
# ❌ 错误:localhost 指的是 A 容器自己
fetch('http://localhost:3000/api')
# ✅ 正确:用 B 的服务名,Docker 内置 DNS 会解析成它的 IP
fetch('http://backend:3000/api')第三步:进 A 容器里实测连通性,这一步最能一锤定音:
bash
docker exec -it <A容器> sh
ping backend # 能不能解析到 IP(测 DNS 和网络)
curl http://backend:3000/api # 能不能真正调通接口(测服务)ping 通但 curl 不通 → 网络没问题,是对方服务没起或端口不对;ping 都不通 → 网络/服务名的问题。这套"分层定位"的思路,和你排查接口时"先看 DNS、再看网络、最后看服务返回"完全一致。
典型案例:联调环境接口全 502
现象:前端页面所有接口 502。排查:docker ps 发现 api 容器是 Up,但 nginx 容器 curl http://api:3000 报 connection refused。进 api 容器 netstat 一看,服务监听在 127.0.0.1:3000。根因:后端服务没监听 0.0.0.0。改配置重启,恢复。
模块三:进不去 —— 想进容器看看却无从下手
前面已经多次用到"进容器",这里系统讲。所谓"进不去",往往是不知道用什么命令进、或者容器压根没有 shell。
核心命令:docker exec
docker exec 就是"在正在运行的容器里执行命令",最常用的是开一个交互式 shell 钻进去:
bash
docker exec -it <容器名> /bin/bash # 进入容器的 bash
docker exec -it <容器名> /bin/sh # 若没有 bash 就用 sh(精简镜像常见)参数解释:-i 保持输入流打开(可交互),-t 分配一个终端(让界面像正常命令行)。两个一起用 -it,你就能像 SSH 到一台服务器一样在容器里敲命令了。

进去之后,你可以像在普通 Linux 里一样干这些事:
bash
cat /app/config.json # 看配置对不对
env # 看环境变量是否正确注入(很多联调问题是环境变量错)
ls -l /app # 看代码/文件是不是真的在里面
ps aux # 看进程是不是真在跑三个常见"进不去"的坑
坑一:容器已经退出了,exec 进不去。 exec 只能进运行中的容器。如果容器已 Exited,你要排查它,得用上面「起不来」模块的 docker logs,或用 --entrypoint 覆盖启动命令重新跑一个进去。
坑二:提示 bash: not found。 很多精简镜像(如 alpine)没有 bash,改用 /bin/sh 即可。
坑三:不想进容器,只想临时看一眼文件。 不必进去,可以直接把文件拷出来:
bash
docker cp <容器名>:/app/config.json ./ # 从容器拷文件到本机
docker cp ./fix.json <容器名>:/app/config.json # 也能把文件拷进去做临时修复典型案例:接口返回的配置不对
现象:后端接口返回的某个配置值明显是错的,但代码看着没问题。排查:docker exec -it api sh 进去,env 一看,发现 API_BASE_URL 环境变量传的是测试环境的值。根因:docker run 时 -e 传错了变量,或 compose 文件里配错。这类"环境变量注入错误"是联调环境最隐蔽的问题之一,进容器一看便知。
知识拓展:排错路上的关联知识
1. 容器网络基础(一句话理清)
- 每个容器有自己独立的 IP 和
localhost,容器的localhost只指它自己; - 同一网络内的容器,用服务名互访,Docker 内置 DNS 自动解析,不用记 IP;
- 端口映射(
-p)只为让容器网络"之外"的访问者(你的浏览器)进来,容器互访不需要它。
记住这三条,「连不上」的问题你已经能解决大半。
2. 容器生命周期管理
容器有清晰的状态流转,理解它能帮你判断"该用哪个命令":
bash
docker start <容器名> # 启动已停止的容器
docker stop <容器名> # 优雅停止(发 SIGTERM,给程序时间收尾)
docker restart <容器名> # 重启,连不上时先试试这个
docker rm <容器名> # 删除已停止的容器
docker rm -f <容器名> # 强制删除运行中的容器一个实用习惯:排查环境类问题,先 restart 试试,很多"偶发连不上"重启即恢复;若重启无效,再深入看日志。
3. 实用排错工具推荐
| 工具/命令 | 用途 | 适合场景 |
|---|---|---|
docker stats | 实时看容器 CPU/内存占用 | 怀疑 OOM(137 退出码)、性能问题 |
docker inspect <容器> | 看容器完整配置(网络、挂载、环境变量) | 深挖端口映射、卷挂载、网络细节 |
docker logs -f | 实时追踪日志 | 复现问题时盯着看 |
| Docker Desktop GUI | 图形界面看容器/日志/终端 | 不想记命令的前端,点点鼠标即可 |
| Lazydocker | 终端里的可视化 Docker 面板 | 想在命令行里高效浏览多个容器 |
对前端来说,Docker Desktop 的图形界面是最低门槛的选择:容器列表、日志、进入终端、资源占用一目了然,不用背命令。
结尾:容器排错通用方法论
抛开具体命令,排错的底层思路始终是这套**"三步收敛法"**,它和你排查线上接口问题的直觉完全一致:
- 看状态,定大类:
docker ps -a看STATUS,先判断是「起不来(Exited)」还是「连不上(Up 但不通)」; - 看日志,找线索:
docker logs是第一现场,90% 的启动问题日志里直接给答案; - 进容器,做验证:
docker exec -it钻进去,用env/netstat/curl逐层确认环境变量、监听地址、连通性。
核心心法一句话:别猜,去看。 状态、日志、容器内部实况,这三样看全了,绝大多数问题自然浮出水面。
高频命令速查清单
bash
# —— 看状态 ——
docker ps -a # 所有容器及状态
docker stats # 实时资源占用
# —— 起不来 ——
docker logs --tail 50 <容器> # 看最后 50 行日志
docker logs -f <容器> # 实时追踪日志
docker run -it --entrypoint sh <镜像> # 崩溃前就退?覆盖启动命令进去手动查
# —— 连不上 ——
docker ps # 看 PORTS 列确认端口映射
docker network ls # 看网络列表
docker network inspect <网络> # 看网络里有哪些容器
docker exec -it <容器> sh -c "netstat -tlnp" # 看服务监听地址(是否 0.0.0.0)
# —— 进不去 ——
docker exec -it <容器> /bin/bash # 进容器(无 bash 换 sh)
docker cp <容器>:/path/file ./ # 从容器拷文件出来
docker inspect <容器> # 看完整配置(环境变量/挂载/网络)
# —— 生命周期 ——
docker restart <容器> # 重启(偶发问题先试它)
docker rm -f <容器> # 强制删除