适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用
docker composeV2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。
一、遭遇情况:docker ps 正常,curl 却失败
Web 容器一直显示 Up,端口栏也有映射,但访问服务器端口时连接被重置、拒绝或超时。只盯着 docker ps 看,通常找不出原因。
本篇案例是 Python Web 服务在容器里只监听 127.0.0.1:8000。进程运行正常,容器自己访问成功,但发布端口转发到容器网络接口时,目标地址并没有服务监听。
二、原因分析:不同空间里的 127.0.0.1 不是同一处
容器内的 127.0.0.1 指容器自己的回环接口,不是宿主机。应用绑定它,通常只能从该容器内部访问。为了通过容器网络接口接收请求,应用通常需要监听 0.0.0.0 或合适的容器地址。
另一个容易混淆的地方是 -p 127.0.0.1:18086:8000:这里的回环绑定发生在宿主机一侧,适合只让本机反向代理访问。它与容器内应用的绑定地址是两层独立设置。

三、排查思路:从里到外缩小故障范围
1. 容器是否真的在运行,应用是否报错
假设业务容器名为 web:
docker inspect web --format 'Status={{.State.Status}} Error={{.State.Error}}'
docker logs --tail 100 --timestamps web
docker port web
docker inspect web --format '{{json .NetworkSettings.Ports}}'
Up 只说明主进程尚在运行。应用可能没有启动监听、还在初始化,或者错误地监听了其他端口。Dockerfile 的 EXPOSE 是端口说明,不等于已经执行宿主机端口发布。
2. 容器内能访问,宿主机能访问吗
有合适客户端工具时,从容器内请求应用;镜像很精简而没有 curl、ss 时,不必因此断言网络坏了,更不要为了排查直接修改生产镜像安装一堆工具。
宿主机使用 curl --connect-timeout 3 --max-time 5 http://127.0.0.1:发布端口。如果本机成功而远程失败,才继续查外部访问路径;如果本机就失败,先处理应用和映射。
四、实践:复现“容器内可访问,发布端口失败”
以下使用独立实验名和本机练习端口,前提是镜像可拉取:
docker run -d --name dt06-loop -p 127.0.0.1:18086:8000 python:3.12-alpine python -m http.server 8000 --bind 127.0.0.1
docker logs --tail 20 dt06-loop
docker exec dt06-loop python -c 'import urllib.request; print(urllib.request.urlopen("http://127.0.0.1:8000", timeout=3).status)'
curl -I --connect-timeout 3 --max-time 5 http://127.0.0.1:18086
容器内部的 Python 请求应返回 200,宿主机请求预期失败。具体失败文本取决于网络实现,判断重点是同一服务从不同入口的可达性不同。
只对这个明确的实验容器停止、删除并修正绑定:
docker stop dt06-loop
docker rm dt06-loop
docker run -d --name dt06-loop -p 127.0.0.1:18086:8000 python:3.12-alpine python -m http.server 8000 --bind 0.0.0.0
curl -I --connect-timeout 3 --max-time 5 http://127.0.0.1:18086
此时宿主机应得到 HTTP 响应。练习仍只发布到宿主机回环地址,因此另一台机器直接访问服务器的 18086 失败仍然符合配置预期。
五、本机正常、外部不通时查哪里
先明确部署方案。如果入口由宿主机 Nginx 反向代理,后端只发布到 127.0.0.1 是合理设计,外部应访问代理的业务端口。不要为了测试方便把所有后端端口公开。
如果业务确实需要直接远程访问,则要确认发布地址包含正确的服务器接口、云安全组允许预期来源、宿主机转发与防火墙规则匹配。云服务器公网 IP 可能通过平台 NAT 映射,不一定能在本机直接绑定该公网地址。
检查时可读取 sudo nft list ruleset 或适合本系统后端的 sudo iptables -S,但不要同时盲改两套规则。Docker 的端口发布会参与防火墙与转发处理,不能只凭 ufw status 里一条普通 INPUT 规则判断整个链路。
curl 已收到 403、404、502 等 HTTP 状态时,至少说明某个 HTTP 服务作出了响应,应转向对应应用或代理层,不要继续当成单纯 TCP 不通。
六、验证与总结
至少验证三个视角:容器内请求、宿主机发布入口请求、预期客户端真实入口请求。记录哪一步开始失败,证据会自然指向应用监听、发布映射或外部链路。
这类故障的核心是把“进程活着”“端口可达”“HTTP 正确”“业务可用”分开验证。修复容器内监听地址后,还要确认宿主机入口的暴露范围符合原部署设计。