适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用
docker composeV2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。
一、遭遇情况:服务都启动了,应用却找不到数据库
应用日志出现 Name or service not known、bad address 或 Temporary failure in name resolution,数据库容器却一直显示运行中。
本篇设定为:运维人员分别运行两个容器,放在默认 bridge 网络上,然后把数据库地址填写为容器名,期待它像 Compose 服务名一样自动解析。实际名称解析失败。
另一种常见错误是应用写着 DB_HOST=localhost。容器里的 localhost 通常指它自己,不是另一个数据库容器;这时往往更像连接拒绝,而不是名称不存在。
二、原因分析:能通信的前提不只有“都在这台机器上”
同一台宿主机可以有多个相互隔离的 Docker 网络。用户自定义 bridge 提供容器名与网络别名解析;默认 bridge 的行为不同,不能把两者混为一谈。
Compose 通常为项目创建默认网络,服务能通过服务名发现彼此。但不同项目各自的默认网络,并不自动成为同一个网络。

三、排查思路:对照双方,而不是只查客户端
假设应用叫 api,数据库叫 db:
docker inspect api --format '{{json .NetworkSettings.Networks}}'
docker inspect db --format '{{json .NetworkSettings.Networks}}'
docker network ls
docker exec api cat /etc/resolv.conf
比较是否有共同的预期网络、该网络下的名称和别名是否正确。不要把 docker inspect 全部输出直接贴到公开平台,它可能包含应用环境变量;这里只读取网络相关字段。
如果镜像有工具,可执行 getent hosts db 或 nslookup db。用户自定义网络常见 127.0.0.11 形式的内置 DNS 配置,但应按实际环境理解,不要手工覆盖容器里的 resolv.conf 来维持容器名解析。
名称能解析后,再测试目标端口。解析失败、TCP 连接拒绝、密码认证失败是三种不同证据:最后一种已经说明请求到达了相应应用服务,不应再归因于 Docker DNS。
四、实践:从默认 bridge 迁移到独立网络
下面在练习服务器使用独立名称。Nginx 代替后端服务,便于通过 HTTP 验证,不需要真实数据库密码:
docker run -d --name dt07-backend nginx:stable-alpine
docker run --rm busybox:1.37 nslookup dt07-backend
第二条预期无法通过默认 bridge 自动获得本地容器名解析。外部 DNS 的响应文本可能不同,不要把某一行错误写死为唯一结果。
创建用户自定义网络,并把实验后端接入:
docker network create dt07-net
docker network connect dt07-net dt07-backend
docker run --rm --network dt07-net busybox:1.37 nslookup dt07-backend
docker run --rm --network dt07-net busybox:1.37 wget -qO- http://dt07-backend:80
现在应能解析名称并获取 Nginx 页面。没有 -p 也可以从同一网络访问容器的 80 端口,因为这不是经过宿主机发布端口的外部访问。
练习使用的后端仍保留原网络连接;生产环境需要在部署定义中明确网络,而不是长期依赖临时 docker network connect。网络连接变化可能影响访问范围,要确认加入的是正确业务网络。
五、Compose 应如何表达网络关系
单项目可以明确声明服务共享的网络:
services:
web:
image: nginx:stable-alpine
networks: [appnet]
client:
image: busybox:1.37
command: ["sleep", "3600"]
networks: [appnet]
networks:
appnet: {}
启动后使用 docker compose exec client wget -qO- http://web:80 验证。应用访问数据库时也应使用实际服务名和容器内服务端口,而不是误填宿主机映射端口。
跨项目通信可以使用经过规划的 external network,但要主动创建并让双方引用。不要为了方便把所有不相关系统都接到一个大网络。
固定写容器 IP 不是可靠替代方案,重建后地址可能变化;修改宿主机 /etc/hosts 也不会自动成为所有容器的服务发现配置。
六、验证、清理与总结
验证顺序:名称解析返回预期网络地址 → 目标端口接受连接 → 应用协议正常 → 业务身份认证通过。能 ping 不能证明数据库可用,不能 ping 也不能直接证明 TCP 服务不可用。
本篇实验完成后,停止删除明确的 dt07-backend,再删除不再有容器连接的 dt07-net。不要运行全局网络清理命令代替有目标的收尾。
这类故障应从名称、网络归属和服务端口入手。把正确的服务名写进正确的共享网络,远比记录一个临时 IP 更容易维护。