lolspider / notes
Clipping · 3 分钟

Kubernetes 中 Alpine(musl) DNS 解析异常排查复盘

Open: Pasted image 20260513104709.png

Kubernetes 中 Alpine(musl) DNS 解析异常排查复盘

问题现象

某个 Kubernetes Pod 中:

bash
curl csghub.example.com

报错:

plaintext
curl: (6) Could not resolve host: csghub.example.com
DNS server returned general failure

但:

bash
nslookup csghub.example.com 10.43.0.10

能够正常解析:

plaintext
Name: csghub.example.com
Address: 192.168.50.225

同时:

bash
curl csghub.example.com.

(注意最后带 .)

能够正常访问。

而其他 Pod 没有问题。


一、问题背景

1. Pod

/etc/resolv.conf

异常 Pod:

conf
search spaces.svc.cluster.local svc.cluster.local cluster.local example.com
nameserver 10.43.0.10
options ndots:5

其中:

  • 10.43.0.10
    是 Kubernetes CoreDNS Service IP
  • ndots:5
    是 Kubernetes 默认配置
  • example.com
    是额外注入的 search domain

2. Pod 使用 Alpine / musl libc

执行:

bash
ldd --version

输出:

plaintext
musl libc (x86_64)
Version 1.2.5

说明该 Pod 使用:

  • Alpine Linux
  • musl libc resolver

而其他正常 Pod 使用:

  • Ubuntu/Debian
  • glibc resolver

二、根因分析

问题本质:

Kubernetes 默认 DNS 策略 + musl resolver 行为差异 + search domain 污染

共同导致 DNS 查询失败。


三、Kubernetes 默认 DNS 行为

Kubernetes 默认:

conf
options ndots:5

意味着:

域名中 . 数量 < 5 时,
resolver 会优先尝试 search domain。


示例

访问:

plaintext
csghub.example.com

该域名只有:

plaintext
2 个 dots

满足:

plaintext
2 < 5

因此 resolver 不会直接查询公网域名。

而是依次尝试:

plaintext
csghub.example.com.spaces.svc.cluster.local
csghub.example.com.svc.cluster.local
csghub.example.com.cluster.local
csghub.example.com.example.com

四、真正的问题:search domain 污染

关键问题是:

conf
search ... example.com

导致 resolver 产生错误查询:

plaintext
csghub.example.com.example.com

这并不是用户真正想解析的域名。


五、CoreDNS 并没有故障

验证:

bash
nslookup csghub.example.com 10.43.0.10

成功。

说明:

  • CoreDNS 正常
  • 网络正常
  • Service DNS 正常

问题不在 Kubernetes DNS Server。


六、为什么 curl 会失败

curl 使用:

plaintext
libc resolver

即:

  • glibc
  • musl

而:

bash
nslookup
dig

使用的是:

plaintext
自带 DNS client

不会完全走 libc resolver 流程。

因此:

bash
nslookup 正常
curl 失败

是典型现象。


七、musl 与 glibc 的关键差异

这是问题核心。


glibc 行为(Ubuntu/Debian)

glibc 更“宽容”。

当 search domain 查询过程中遇到:

plaintext
SERVFAIL

glibc 通常:

  • 会继续尝试下一个 search
  • 最后可能 fallback 到原始域名

因此:

plaintext
最终仍可能解析成功

musl 行为(Alpine)

musl 更“严格”。

当遇到:

plaintext
SERVFAIL

musl 可能:

plaintext
直接终止解析链

于是:

bash
curl csghub.example.com

失败:

plaintext
DNS server returned general failure

八、为什么

curl domain.

可以成功

执行:

bash
curl csghub.example.com.

注意:

plaintext
最后带 "."

这是:

FQDN(Fully Qualified Domain Name)

完整限定域名。


带

.

的意义

告诉 resolver:

plaintext
不要 search
不要 ndots
直接查询绝对域名

因此:

plaintext
直接查询:
csghub.example.com

成功。


九、最终根因总结

问题并非:

  • CoreDNS 故障
  • 网络故障
  • kube-proxy 故障
  • Service 故障

真正根因:

Alpine(musl) + Kubernetes ndots:5 + search domain 污染

导致 resolver:

  • 进入错误 search 链
  • 遇到 SERVFAIL
  • musl 提前终止解析

十、为什么其他 Pod 正常

因为其他 Pod:

  • 使用 glibc
  • 或没有 example.com search domain
  • 或 resolver 行为不同

因此:

plaintext
即使 search 过程中失败,
glibc 仍可能 fallback 成功

十一、为什么

example.com

是关键问题

标准 Kubernetes search 应该是:

conf
search <ns>.svc.cluster.local svc.cluster.local cluster.local

不应包含公网域名:

plaintext
example.com

额外注入公网 search domain 会导致:

plaintext
domain.example.com

这种错误查询。

属于:

DNS search 污染


十二、最终解决方案


方案 1(推荐)

修改 Pod:

yaml
dnsConfig:
  options:
    - name: ndots
      value: "1"

效果:

公网域名:

plaintext
example.com

会直接查询公网。

不会先 search。


方案 2

删除:

plaintext
example.com

search domain。

恢复标准 K8s search。


方案 3

避免 Alpine。

生产环境建议:

  • Debian slim
  • Ubuntu
  • UBI
  • distroless-glibc

方案 4(临时 workaround)

统一使用:

plaintext
domain.com.

FQDN。

但不推荐长期依赖。


十三、经验总结


1. nslookup 正常 ≠ 应用 DNS 正常

因为:

  • nslookup 使用独立 DNS client
  • curl/go/java/node 使用 libc resolver

行为不同。


2. Kubernetes 默认 ndots:5 对公网域名不友好

会:

  • 增加 DNS 查询
  • 放大 search domain 问题
  • 增加 DNS latency

3. Alpine(musl) 在 Kubernetes 中 DNS 兼容性较差

尤其:

  • ndots
  • search domain
  • SERVFAIL
  • corporate DNS

组合场景。


4. 不要向 search domain 注入公网域名

错误示例:

yaml
searches:
  - example.com

十四、推荐最佳实践

推荐统一:

yaml
dnsConfig:
  options:
    - name: ndots
      value: "1"

并:

  • 避免 Alpine 作为生产基础镜像
  • 保持 search domain 简洁
  • 不混入公网域名
  • 避免依赖 search 自动补全公网域名

十五、此次问题的最终定性

这是一个:

Kubernetes DNS search/ndots 与 musl libc resolver 行为差异导致的兼容性问题

属于:

经典 Alpine + K8s DNS 坑。