首页
/ Kubernetes DNS 双栈解析测试基石:glibc-dns-testing 镜像的设计、实现与 E2E 应用解析

Kubernetes DNS 双栈解析测试基石:glibc-dns-testing 镜像的设计、实现与 E2E 应用解析

2026-09-07 12:23:58作者:傅爽业Veleda

在 Kubernetes 集群中,Pod 内应用的 DNS 解析行为并不完全由集群的 CoreDNS 配置决定,还取决于应用运行时链接的是哪一套 C 标准库。为了验证基于 glibc 的程序(如 Debian、Ubuntu、RHEL 上的 Java、Python、Ruby、PHP 应用)能正确解析 Service DNS 名称,Kubernetes 仓库内置了一个专用的测试镜像 glibc-dns-testing。本文以 test/images/glibc-dns-testing/README.md 为主线,结合其 Dockerfile、多架构 BASEIMAGE 以及 test/e2e/network/dns.go 等 E2E 测试源码,完整剖析该镜像的用途、构建方式、历史沿革,以及它如何与基于 musl 的 agnhost 镜像协同,共同保障 Kubernetes 集群 DNS 在任何 libc 环境下都稳定可用。

一、镜像定位:为 glibc 解析器补齐 DNS 验证盲区

glibc-dns-testing 是一个基于 glibc 的测试镜像,其唯一使命是验证 glibc 程序能否在 Kubernetes 集群中正确解析 Service DNS 名称。它是对 agnhost 镜像的补充:agnhost 基于 Alpine Linux(使用 musl libc),二者组合起来,确保集群 DNS 服务无论应用使用哪种 C 库都能正常工作。这一设计在 Kubernetes E2E 测试源码中有明确注释:

我们针对一系列已知基础镜像运行相同探针。目前测试覆盖 agnhost(Alpine,使用 musl libc)与 glibc-dns-testing(顾名思义,使用 glibc)。—— test/e2e/network/dns.go

从目录结构看,该镜像组件文件全部位于 test/images/glibc-dns-testing/,与 agnhostbusybox 等测试镜像同属 test/images 体系,并被 test/images/image-util.sh 列入 conformance_images 列表,作为并发测试套件(conformance image set)的组成部分随版本发布。

二、为什么 glibc 测试至关重要:两种 libc 的解析差异

DNS 解析行为会因应用链接的 C 库不同而产生显著差异。glibc 被 Debian、Ubuntu、RHEL 等主流发行版采用,而 musl 是 Alpine Linux 使用的轻量级实现,二者的关键差异包括:

维度 glibc(Debian/Ubuntu/RHEL) musl(Alpine)
nameserver 查询方式 顺序查询,逐个 nameserver 尝试 并行查询,同时向多个 nameserver 发起请求
ndots 与 search domain 处理 遵循自身规则,先按绝对/相对名与点号数量决定是否追加 search 域 处理逻辑与 glibc 不同,同名解析可能得到不同结果
hostname 命令行为 与 musl 实现存在差异(对应上游 issue #134737 的讨论) 行为与 glibc 不尽一致

在生产环境中,绝大多数工作负载运行在 glibc 系发行版之上,因此用 glibc 验证 DNS 解析可直接保障以下应用场景的兼容性:

  • Java 应用(JVM 依赖 glibc 的 getaddrinfo 等解析接口);
  • Python / Ruby / PHP 应用(解释器运行时同样经由 libc 完成域名解析);
  • 大多数企业级 Linux 发行版上的容器化业务。

换句话说,仅用基于 musl 的镜像测试通过,并不能代表基于 glibc 的应用在集群中一定解析正常;glibc-dns-testing 正是为了覆盖这条"解析器差异"导致的潜在故障面。

三、镜像构成与 Dockerfile 实现细节

README 列出的镜像内容如下,而 Dockerfile 给出了可验证的实现依据:

  • 基础镜像(Base):Debian Bookworm(glibc-based);
  • dnsutils:提供 dignslookuphost 等 DNS 排障命令;
  • CoreDNS:内嵌 DNS 服务器,供测试场景使用。

3.1 构建过程拆解

核心构建逻辑(Dockerfile)分三步完成:

ARG BASEIMAGE
FROM $BASEIMAGE

ARG TARGETARCH

RUN apt-get update && \
    apt-get install -y dnsutils && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

ADD https://github.com/coredns/coredns/releases/download/v1.5.0/coredns_1.5.0_linux_${TARGETARCH}.tgz /coredns.tgz
RUN tar -xzvf /coredns.tgz && rm -f /coredns.tgz
  • BASEIMAGE 通过构建参数注入,由 BASEIMAGE 文件按架构映射,Linux 各架构均落在 glibc 发行版上:linux/amd64=debian:bookworm-slimlinux/arm64=arm64v8/debian:bookworm-slimlinux/ppc64lelinux/s390x 同理;Windows 变体则映射到官方 busybox 的 Windows 镜像(1809 / ltsc2022 / ltsc2025),对应仓库中的 Dockerfile_windows
  • 安装 dnsutils 后立即 apt-get clean 并删除 /var/lib/apt/lists/*,缩小镜像体积。
  • 下载并解压 CoreDNS v1.5.0 发行包,为测试提供可编程的 DNS 服务端能力(对应 README 中"嵌入式 CoreDNS 用于测试"的说明)。

3.2 版本管理

镜像当前版本记录在 VERSION(值为 2.1.1),并在 E2E 镜像清单 test/utils/image/manifest.go 中以 GlibcDnsTesting 这一 ImageID 注册:

configs[GlibcDnsTesting] = Config{list.PromoterE2eRegistry, "glibc-dns-testing", "2.1.1"}

测试代码统一通过 imageutils.GlibcDnsTestingimageutils.GetE2EImage(...) 间接引用镜像,从而做到镜像地址、标签与测试用例解耦,便于镜像仓库整体迁移与版本晋级。

四、历史沿革:从 jessie-dnsutils 到 glibc-dns-testing

该镜像最初名为 jessie-dnsutils,基于 Debian Jessie 构建。随着时间推移,镜像的真实使命逐渐清晰——它验证的是 glibc 的 DNS 解析行为,而非绑定某个具体 Debian 版本,因此被更名为 glibc-dns-testing,让命名准确反映用途。

README 提到的上游 issue #10161 正是这套测试思路的起源:社区在讨论 glibc 与 musl 在 DNS 解析上的差异(顺序查询 vs 并行查询、ndots/search domain 处理差异等)时,意识到必须为 glibc 提供一套独立的 E2E 探针镜像,从而催生了该镜像。值得一提的是,镜像自带的应用层差异也影响了测试设计——例如 hostname 命令在两种 libc 下行为不同(issue #134737),因此在设计 DNS 探针命令时需要显式选择对两种环境都稳定的工具与参数。

五、在 E2E 测试中的真实用法:musl 与 glibc 双探针对照验证

该镜像不面向生产,仅用于 Kubernetes E2E 测试(README 明确提示 "for test purposes only")。它的典型用法是与 agnhost 一起,作为两个并行的 DNS 查询探针容器挂载进同一个测试 Pod,在完全相同的集群 DNS 环境下对照验证。

5.1 探针的抽象与构造

test/e2e/network/dns_common.go 中定义了 dnsQuerier 结构体,将每个探针抽象为"名字 + 镜像 + 一段 shell 命令脚本":

type dnsQuerier struct {
	name  string             // container name
	image imageutils.ImageID // container image
	cmd   string             // a shell-script in a string
}

createDNSPodtest/e2e/network/dns_common.go)会创建以 agnhosttest-webserver 为第 0 个容器的 Pod,并遍历 probers 把每个探针容器追加进去;探针容器以 sh -c <probe.cmd> 启动,并将探测结果(OK 标记文件)写入共享的 emptyDir 卷 /results,由 validateDNSResults 统一校验。

5.2 探针命令的生成逻辑

createProbeCommandtest/e2e/network/dns_common.go)为两类查询者生成近乎一致的命令,核心利用 dnsutils 提供的 dig

  • A / AAAA 记录:对每个待解析名称分别执行 dig +notcp +noall +answer +search <name> A|AAAA(UDP)与 dig +tcp +noall +answer +search <name> A|AAAA(TCP),若返回结果非空则写入 OK 标记;名称以 _ 开头时改用 SRV 记录;
  • /etc/hosts 条目:通过 getent hosts <host> 校验 Pod hostname 与 subdomain 生成的 FQDN(Windows 上改用 grep 检查 hosts 文件);
  • PTR 反向解析:使用 dig ... <reverse-addr> PTR 验证 Service ClusterIP 的反向记录,支持 IPv6(ClusterIsIPv6() 为真时以 AAAA 记录探测)。

整个命令被包裹在 for i in seq 1 600 循环中,最多重试约 600 秒,兼顾了 DNS 记录传播延迟下的测试稳定性。可见,dig/getent 这些 glibc 工具正是该镜像存在的意义——同样的逻辑在 musl(agnhost)与 glibc(glibc-dns-testing)两套环境各自跑一遍。

5.3 被验证的 DNS 测试场景

test/e2e/network/dns.goSIGDescribe("DNS") 套件中,几乎所有核心用例都同时挂载 musl 与 glibc 两个探针:

  • "should provide DNS for the cluster"(Conformance 用例):解析 kubernetes.default.svc.<clusterDomain> 等集群核心记录,test/e2e/network/dns.go
  • "should provide /etc/hosts entries for the cluster":校验 hostname/subdomain 在 hosts 文件中的条目,test/e2e/network/dns.go
  • "should provide DNS for services" 等用例:验证 headless Service 的 A/AAAA/SRV 记录解析、CNAME 与 PTR 反向解析(针对 foo.example.com.bar.example.com. 及 ClusterIP 反向记录,见 test/e2e/network/dns.go)。

以 Conformance 用例为例(test/e2e/network/dns.go),两个探针被这样组织:

muslProbeCmd, muslFileNames := createProbeCommand(namesToResolve, nil, "", "musl", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
muslProber := dnsQuerier{name: "musl", image: imageutils.Agnhost, cmd: muslProbeCmd}
glibcProbeCmd, glibcFileNames := createProbeCommand(namesToResolve, nil, "", "glibc", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
glibcProber := dnsQuerier{name: "glibc", image: imageutils.GlibcDnsTesting, cmd: glibcProbeCmd}

pod := createDNSPod(f.Namespace.Name, []dnsQuerier{muslProber, glibcProber}, dnsTestPodHostName, dnsTestServiceName)
validateDNSResults(ctx, f, pod, append(muslFileNames, glibcFileNames...))

只有 musl 与 glibc 两套文件全部写出 OK,用例才判定通过——这正是"无论应用链接哪种 libc,集群 DNS 都必须可用"这条质量红线的落地方式。

5.4 其他 E2E 场景中的复用

除 DNS 套件外,该镜像还被复用于校验非 DNS 场景下的主机名/镜像行为,例如 test/e2e/common/node/pod_hostnameoverride.go 中通过 imageutils.GetE2EImage(imageutils.GlibcDnsTesting) 构造使用自定义 hostname 的 Pod。可以推断,凡是在 E2E 中需要一个"标准 glibc 环境 + DNS 工具集"的 Linux 容器,测试框架都会优先复用该镜像,避免重复维护多套 glibc 测试底座的成本。

六、使用与注意事项

  1. 仅供测试:该镜像内嵌了调试工具链与 CoreDNS 服务端,体积与安全面都不符合生产容器要求,README 与 Dockerfile 注释均明确其为测试用途。
  2. 架构覆盖:构建时需通过 BASEIMAGE 按目标架构传入对应基础镜像;本地复现可参考其映射关系(如 linux/amd64=debian:bookworm-slim),Windows 测试节点则使用独立的 Windows 变体镜像。
  3. 版本跟随:镜像 tag 由 VERSIONtest/utils/image/manifest.go 中的 Config 保持一致,升级镜像后需同步两处。
  4. 与 agnhost 配套:单独的 glibc 验证并不充分,正确姿势是像 test/e2e/network/dns.go 那样让 glibc 探针与 musl(agnhost)探针在同一个测试 Pod 内并行对照,才能覆盖两种主流 libc 的解析差异。

结语

glibc-dns-testing 表面上是几十行 Dockerfile 组成的小镜像,实质上是 Kubernetes 对"解析器差异"这一隐性故障域的工程化应对:通过将 glibc 与 musl 并列为 DNS E2E 探针的固定矩阵,仓库得以在每次发布前确认集群 DNS 对两类主流 C 库都可用。理解它的用途、构建与调用链,既有助于排查线上 glibc 应用的 DNS 偶发问题,也能为自建集群的 DNS 质量验证提供一个低成本的对照思路——以 test/e2e/network/dns.go 为蓝本,复刻一套 musl + glibc 双探针即可。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390