LabHub
学习 学习路径 课程

网络排障

/etc/hosts 是什么,什么时候它赢

在 LabHub 中继续学习

一句话总结

/etc/hosts 是一份在 DNS 之前查询的本地名称表,而 dig 完全不会读取这个文件。理解这一句话,就能走出许多故障迷宫。

概念图: 之前 · 完全不会读取这个文件 · 这种事故不会表现出 DNS 错误的样子。 · IP、规范名称、多个别名

为什么需要理解名称解析顺序

有时会收到这样的报障:“DNS 看起来正常,但只有应用程序仍然连接旧服务器。”

检查后发现,dig api.internal 确实返回了新 IP,应用程序却始终连接旧 IP。如果这时开始排查 DNS 服务器,一整天都会白白浪费。

罪魁祸首通常是 /etc/hosts。有人上周调试时临时加入的那一行还留在那里。而且,这种事故不会表现出 DNS 错误的样子。 名称能够正常解析,症状却表现为 connection refused 或 timeout,所以没有人会怀疑名称解析。

它是如何工作的

先看文件格式。每一行由IP、规范名称、多个别名组成。

127.0.0.1       localhost
127.0.1.1       myserver
::1             localhost ip6-localhost ip6-loopback
10.0.1.50       api.internal.mycompany.com api-internal
192.168.1.100   db-master.mycompany.com

接下来是决定查询顺序的文件——/etc/nsswitch.conf

grep '^hosts' /etc/nsswitch.conf
# hosts: files dns myhostname
# hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
# hosts: files resolve [!UNAVAIL=return] dns myhostname

各个令牌的含义如下。

令牌 查询什么
files /etc/hosts
dns 直接查询 /etc/resolv.conf 中的 nameserver
resolve 通过 D-Bus 查询 systemd-resolved
myhostname 本机主机名与本地接口地址
mdns4_minimal 通过 mDNS 解析 .local 名称

方括号内的是行为规则[NOTFOUND=return] 表示前一个模块回答“没有这个名称”后就立即停止,不会继续查询后面的 dns

因此,把公司内部域命名为 .local 的组织很容易踩中这个陷阱。mdns4_minimal [NOTFOUND=return] 会截获 .local 名称,解析失败后就在原地结束,不再转到 DNS。然而,dig 不读取 nsswitch,所以仍会返回正常响应。于是出现了dig 正常,只有应用程序失败的现象。

由此可以得到本课程最重要的一句话。

dig 展示 DNS 服务器给出的答案,getent 展示应用程序会得到的答案。如果两者不同,这个差异本身就指出了原因所在的位置。

dignslookuphost 都是只使用 DNS 协议的工具。它们既不读取 /etc/hosts,也不读取 nsswitch 或 systemd-resolved 的按链路配置,只会从 resolv.conf 获取 nameserver 地址,再向 UDP 53 端口发送查询。能够复现应用程序解析路径的工具只有 getent hostsgetent ahostsresolvectl query

实际工作中会遇到的情况

使用 hosts 临时绕行后忘记删除。 故障处置时决定“先写进 hosts 绕过去”很常见,而且通常是正确选择。问题是三个月后那一行仍然存在。因此,许多团队规定,修改 hosts 时必须在注释中写明日期、原因与负责人

容器镜像中固化了 hosts。 构建时加入的记录会残留在镜像中,导致所有环境都指向同一个 IP。预发布环境连接到生产数据库的事故,就可能这样发生。

下一个实验要做什么

亲自在 /etc/hosts 中添加记录,通过 getent 确认结果,再审计一个损坏的 hosts 文件夹具,找出有问题的行,最后提交满足规则的最终版本。