Docker 容器内 DNS 解析失败速查:Name or service not known 与服务名互访
更新时间:2026-10-24。FAQ 速查页,面向容器里
ping db、curl http://api:8080直接报「名字不认识」的同学。容器内 DNS 解析失败的本质是一句话:名字解析依赖「你在哪个网络」加「谁来回答」两层,任何一层断了都是 Name or service not known。默认 bridge 网络根本没有服务名解析能力,只有自定义网络里 Docker 内嵌 DNS 才把容器名/服务名翻译成地址;而外网域名解析又要看宿主机resolv.conf能不能穿透到容器。病因收敛在六根轴上:跑在默认 bridge 上想用服务名、两个容器不在同一自定义网络、名字拼错或缺 network alias、compose 工程名前缀变了、内嵌 DNS 被镜像里的/etc/resolv.conf覆盖、极简镜像裁掉了 NSS 组件。顺一遍基本必中。如果是连接被拒而不是名字解析不了,转 Docker 连接被拒速查。
本文要回答的问题
- 容器里
ping 服务名报 Name or service not known,第一步查什么? - 默认 bridge 网络和自定义网络的 DNS 能力差在哪?
- compose 启动的容器,服务名为什么有时候解析不通?
- 外网域名解析不了,但内网服务名正常,是哪一层断了?
- 用什么命令在容器里做 DNS 诊断最快?
一、报错原文与典型现象
报错集中在三类:应用日志里的解析失败、命令行工具的直接报错、以及连接层被翻译后的误导性报错(镜像名以 registry.example.com 占位,路径以 /proj/demo 占位):
# 命令行:解析直接失败
/ # ping db
ping: bad address 'db'
$ curl http://api:8080/health
curl: (6) Could not resolve host: api# 应用日志(glibc 系)
getaddrinfo failed: Name or service not known
# 或 musl 系(alpine)
getaddrinfo failed: Try again# 外网域名失败(注意与内网服务名区分)
nslookup example.com
;; connection timed out; no servers could be reached
Temporary failure in name resolution读现象先分两类:bad address / Could not resolve host / Name or service not known 是名字根本没翻译出来,问题在 DNS 层;如果报错是 Connection refused 或 Connection timed out,说明名字已经翻译成了地址,问题在对方服务没监听或网络不通,那不是本篇范围。第二条分界线是失败对象:内网服务名失败查「网络成员资格与内嵌 DNS」,外网域名失败查「上游 DNS 透传」。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| ping 服务名 bad address | 容器跑在默认 bridge,无服务名解析 | docker inspect 看 NetworkMode 是 bridge | 建自定义网络,容器加入后用名字互访 |
| 同主机两容器互解析不了 | 不在同一个自定义网络 | docker network inspect 比对成员列表 | 把两容器接入同一网络或加 connect |
| 服务名对、别名不识别 | 缺 network alias 或名字拼错 | 容器里 nslookup 别名 对比 | run 时加 --network-alias 或修正拼写 |
| compose 里服务名突然失效 | 工程名/副本名变化,引用名不对 | docker ps --format 看实际容器名 | 引用用服务名不带工程前缀,重启栈 |
| 外网域名解析超时 | 宿主机 resolv.conf 不可达或代理环境 | 宿主机直接 nslookup example.com 对比 | 修宿主机 DNS 或 daemon 配 dns 项 |
| alpine 镜像偶发解析失败 | musl 并发查询与裁剪 NSS 的差异 | 换 glibc 基础镜像对照复现 | 用 FQDN 加点号或换基础镜像 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓分水岭:先把「解析谁失败」说清楚——内网服务名失败走左支,九成是「不在同一网络」;外网域名失败走右支,九成是「宿主机 DNS 透传断了」。两条支路的修复互不相干,不要拿改 resolv.conf 的药去治服务名解析。
四、逐条排查展开
默认 bridge 没有服务名解析,这是最大的认知坑。 docker run 不加 --network 时容器落在默认 bridge 上,这个网络只有 --link 这种已废弃的静态注入方式,内嵌 DNS 不为它服务。也就是说两个都跑在默认 bridge 上的容器,ping 对方容器名 必报 bad address——不是配置错了,是这条路从一开始就不存在。修法:docker network create appnet,两边都 --network appnet,之后容器名即可解析。
同一网络才可解析,跨网络是硬边界。 Docker 内嵌 DNS 按网络隔离:容器 A 在 net1、容器 B 在 net2,即使同一宿主机,A 也解析不到 B 的名字。验证用 docker network inspect net1 看 Containers 列表,成员里没有就是没加入。处置不用重建容器:docker network connect net2 容器A 让它同时加入第二个网络即可。compose 场景同理——不同 compose 工程默认各建各的网络,跨工程互访要显式声明 external 网络。
名字不对是最廉价的失败。 容器名、服务名、network alias 是三个不同的名字空间:自定义网络里默认解析「容器名」与「compose 服务名」,额外别名要 --network-alias 显式给。compose 重建后容器名会带工程名与序号后缀,应用配置里写死完整容器名的,重启栈就解析失败——配置里应只写服务名。快速验证:容器里 nslookup 目标名,不通就把 docker ps 的实际名字逐个试一遍定位差异。
外网域名失败查透传链。 容器内网名字由内嵌 DNS 直接回答,外网域名则要内嵌 DNS 转发到宿主机 resolv.conf 里的上游服务器。宿主机换了网络环境(如办公网换到家庭网)、上游服务器在内网 VPN 里而 VPN 断了、或镜像里硬编码了不可达的 DNS,都会表现为「服务名正常、外网域名超时」。诊断顺序:先在宿主机上 nslookup example.com,宿主机通而容器不通,在 daemon 配置里显式给 dns 列表重启生效;宿主机自己就不通,那是宿主机网络问题,与 Docker 无关。
极简镜像的 NSS 裁剪是隐藏变量。 alpine(musl libc)对 DNS 的实现与 glibc 有行为差异:并发 A/AAAA 查询在某些上游实现下会拿不到应答,search 域补全逻辑也不同。症状是「同样的网络,debian 系镜像能解析、alpine 偶发失败」。处置:把名字写成末尾带点号的 FQDN 绕开 search 域补全,或对 DNS 敏感的服务换 glibc 基础镜像。另外一些 scratch/distroless 镜像连 nslookup 都没有,诊断时换 busybox 镜像加同网络临时容器来查。
诊断三板斧。 容器里按顺序敲:cat /etc/resolv.conf(看 nameserver 是不是内嵌 DNS 入口)、nslookup 目标名(看是否返回地址)、getent hosts 目标名(验证 NSS 全链路,会走 hosts 文件与 DNS 的组合)。三条分别对应「谁来答」「答没答」「应用视角能不能拿到」,一步定位断点在哪一环。
五、规范做法与预防
- 互访一律走自定义网络:默认 bridge 只用于单机临时容器,任何「容器找容器」的需求都建专属网络。
- 应用配置只写服务名:不写容器全名、不写地址字面量,重启与扩缩容时名字稳定。
- 健康检查带解析探针:compose 的 healthcheck 里加一条
nslookup 依赖服务名,把 DNS 故障提前到启动期暴露。 - 上游 DNS 显式化:对网络环境多变的机器,在 daemon 配置里写死可靠的上游 DNS 列表,不依赖宿主机运行时状态。
- 别名显式声明:需要多个名字访问同一服务时,别名写在 compose 的
networks.aliases里,版本化进仓库。 - 诊断容器常备:镜像仓库里留一个带 bind-tools 的 busybox 诊断镜像,排障时同网络起一个即用。
这一篇在知识体系里的位置
本篇是 Docker 排错速查簇的网络入口篇,定位「名字解析」:名字解析通了但连接被拒看 Docker 连接被拒速查;解析与连接都正常但请求挂死看 Docker 超时挂起速查;容器起来就退出、日志里混着解析报错看 Docker 段错误崩溃速查。「先分内外、再分网络成员资格与上游透传」这条主线对一切 DNS 类报错通用。
一句话总结
容器内 DNS 解析失败先按失败对象分两类:内网服务名报 Name or service not known,九成是容器没加入同一个自定义网络——默认 bridge 根本没有服务名解析,建网络、接容器、用服务名互访;外网域名超时,问题在宿主机 resolv.conf 到内嵌 DNS 的透传链断了,修宿主机 DNS 或在 daemon 里显式配 dns。诊断三板斧:看容器 resolv.conf、nslookup 目标名、getent 验证全链路。alpine 的 musl 差异用 FQDN 加点号绕过。互访走自定义网络、配置只写服务名、健康检查带解析探针,这类报错基本绝迹。