Docker 服务名访问:为什么 localhost 找不到另一个容器

应用与数据库各自启动正常,但应用连接 localhost 失败。容器网络隔离让同一个地址在不同环境里代表不同目标,应先画出发起请求的一方。

edyang · 2020-03-24

应用与数据库各自启动正常,但应用连接 localhost 失败。容器网络隔离让同一个地址在不同环境里代表不同目标,应先画出发起请求的一方。

同一用户自定义 bridge 网络上的容器可以使用网络内服务名。localhost 指当前网络命名空间自身,发布端口面向宿主机入口,而容器间通信使用目标容器端口。容器重建还可能更换 IP。

Docker 服务名访问:为什么 localhost 找不到另一个容器:处理路径与验证条件

一、问题的范围与前提

镜像、容器、网络和数据卷是不同对象。镜像定义运行产物,容器执行进程,网络决定可达关系,卷管理跨容器生命周期的数据。把它们分别列出来,有助于判断重建究竟改变了什么;单个容器显示 Up,只能说明相关入口进程仍然存在。

二、技术分析与方案取舍

比如 Web 在容器内访问 redis:6379,宿主机管理员通过发布端口访问同一服务,两个请求使用不同地址并不矛盾。关键在于先确认发起方所在网络。服务名解析后客户端可能持有已建立连接,依赖重建会使旧连接失效,即使新 IP 已可解析,也还需要重新连接。

检查连接恢复时应保留故障和恢复过程,不能只在重建前测试一次 DNS。

先固定基础镜像、应用版本和必要配置,再检查最终容器的实际参数。Compose 文件只是期望描述,已经创建的容器可能仍带旧环境。涉及端口、设备和挂载等创建参数时,需要按差异重建;普通 restart 不会重新读入全部创建配置。重建前确认数据所在位置和现有卷身份。

三、实现与排查的顺序

  1. 确认请求由哪个进程发起。
  2. 查看两个服务共同网络。
  3. 使用服务名替代临时 IP。
  4. 分别验证 DNS 与应用协议。

按这个顺序保留中间结果,可以区分输入条件、处理过程和最终输出。前一阶段的条件不成立时,先解释对应错误,再继续后面的试验;单次返回成功不足以覆盖整条链路。

最小示例

1
2
3
docker network ls
docker inspect example-web
docker inspect example-db

先确认两个服务是否接入共同网络,再比较目标端口与服务名。模板表达式属于 Docker 命令格式,并非文章占位符。实际地址不应被复制到公开排障材料。网络身份改变以后,已有客户端连接也可能需要重建。

四、验证和结果解释

可以将配置解析结果、容器实际状态和一次业务请求放在一起观察。配置有效说明语法和部分引用成立,镜像构建有效说明产物生成,真实请求才进一步说明依赖链可用。将这些结果分开记录,能避免一个阶段的成功遮住另一个阶段的失败。

需要验证的结果 保留的对照 不能由此推出的结论
解析结果属于目标服务网络 固定输入与配置、对应输出 一次成功代表所有条件成功
端口与应用实际监听一致 中断前后状态与错误阶段 没有报错代表结果正确
重建依赖后连接能够恢复 恢复后的同条件复测 临时恢复代表根因已经消失

容器异常不一定需要重建整套服务。先定位受影响对象,再确认是否有状态需要保留。数据卷独立于容器并不等于有独立备份,健康检查也不等于自动重启。恢复策略需要与退出、网络失联、数据损坏等具体条件对应。

五、适用边界与结论

host 网络、默认 bridge 与用户自定义网络具有不同条件。服务名可解析不证明凭据正确;已经打开的旧连接可能还需要客户端重新建立。

这条路径把“确认请求由哪个进程发起”与“分别验证 DNS 与应用协议”连在一起,中间保留可复查的条件。实施时优先确认“解析结果属于目标服务网络”,再检查“重建依赖后连接能够恢复”;两者都满足,才能在当前样本与配置范围内评价方案。设备、数据或软件版本改变以后,相关假设需要重新验证。

参考资料