3. OpenShift DNS与Service发现
在 OpenShift 中,Pod 之间、Service 之间以及外部客户端访问集群内服务,绝大多数场景并不直接依赖 IP 地址,而是依赖 DNS 名称。集群 DNS 是服务发现的中枢:它把 Service 名称、命名空间、端口协议等逻辑标识,解析成可路由的 ClusterIP 或 Pod IP。理解 DNS 架构与解析链路,是排查“服务名解析失败”“跨命名空间访问异常”“Headless Service 返回结果不符合预期”等问题的前提。
一、集群 DNS 的整体架构
OpenShift 的 DNS 由两部分协同完成:CoreDNS 作为集群内权威 DNS 服务器,负责解析集群内部域名;dnsmasq 作为节点本地的 DNS 缓存与转发器,负责把节点上 Pod 的 DNS 查询先做本地缓存,再转发给 CoreDNS。两者分工明确:CoreDNS 掌握集群服务与端点的权威数据,dnsmasq 负责降低查询延迟、减少 CoreDNS 压力,并处理节点级别的 DNS 转发策略。
从查询路径看,一个 Pod 内的进程发起 DNS 请求后,请求先到达所在节点的 dnsmasq(监听在节点本地地址),dnsmasq 若命中缓存则直接返回;未命中则转发到 CoreDNS Service(通常是 openshift-dns/dns-default 对应的 ClusterIP)。CoreDNS 根据查询的域名类型,决定是从 Kubernetes API 获取 Service/Endpoint 记录,还是转发给上游 DNS 解析外部域名。
二、CoreDNS 与 dnsmasq 的职责边界
CoreDNS 以 Deployment 形式运行在 openshift-dns 命名空间中,通常有 2 个副本,通过 dns-default Service 暴露。它的配置由 ConfigMap dns-default 管理,核心插件包括 kubernetes(解析集群 Service/Pod 记录)、forward(转发外部域名)、cache(缓存)、prometheus(指标)等。当 Service 或 Endpoint 发生变化时,CoreDNS 通过 watch API 实时感知,无需重启。
dnsmasq 则以 DaemonSet 形式运行在每个节点上,监听节点本地地址(如 169.254.25.10 或节点 IP),为节点上的 Pod 提供第一跳解析。它的主要价值在于:缓存高频查询、按节点维度做 DNS 转发策略、在 CoreDNS 短暂不可用时提供一定缓冲。需要注意的是,dnsmasq 不掌握集群权威数据,它只是缓存与转发层,真正的解析逻辑仍在 CoreDNS。
cat /etc/resolv.conf 确认 nameserver 指向,再用 dig 或 nslookup 分别测试节点本地地址和 CoreDNS Service 地址,从而判断问题出在 dnsmasq 转发、CoreDNS 解析还是上游 DNS。三、Service DNS 记录格式
Kubernetes 为每个 Service 自动生成 DNS 记录,格式为:
<service-name>.<namespace>.svc.cluster.local
例如,在 prod 命名空间中有一个名为 payment 的 Service,集群内其他 Pod 可以通过以下任一名称访问:
payment:同命名空间内短名称,依赖 resolv.conf 中的 search 域自动补全。payment.prod:跨命名空间访问时使用。payment.prod.svc.cluster.local:完全限定域名(FQDN),最明确、最不易出错。
对于普通 ClusterIP Service,DNS 返回的是 Service 的 ClusterIP 地址。如果 Service 定义了多个端口,还可以通过 SRV 记录查询端口信息,格式为 _<port-name>._<protocol>.<service>.<namespace>.svc.cluster.local。例如 _http._tcp.payment.prod.svc.cluster.local 可以返回端口号和目标主机。
四、Headless Service 与普通 Service 的差异
Headless Service 是指 clusterIP: None 的 Service。它不分配 ClusterIP,DNS 查询不会返回单一虚拟 IP,而是返回该 Service 后端所有就绪 Pod 的 A/AAAA 记录。这一特性使它非常适合有状态应用、数据库集群、需要客户端自行选择后端或需要感知每个 Pod 地址的场景。
| 对比项 | 普通 ClusterIP Service | Headless Service |
|---|---|---|
| ClusterIP | 自动分配虚拟 IP | None,不分配 |
| DNS 返回 | 单个 ClusterIP | 多个 Pod IP 列表 |
| 负载均衡 | 由 kube-proxy 或 OVN 承担 | 由客户端自行选择 |
| 典型用途 | 无状态服务、统一入口 | StatefulSet、数据库集群、服务发现 |
对于 StatefulSet 管理的 Pod,Headless Service 还会为每个 Pod 生成稳定的 DNS 名称:<pod-name>.<service-name>.<namespace>.svc.cluster.local。例如 mysql-0.mysql.prod.svc.cluster.local 始终指向 mysql-0 这个 Pod,即使 Pod 重建、IP 变化,名称仍然稳定。这是有状态服务实现稳定网络标识的关键机制。
五、DNS 策略与自定义解析
Pod 的 DNS 行为由 dnsPolicy 控制,常见取值包括:
ClusterFirst:默认策略,优先使用集群 DNS 解析集群域名,外部域名转发上游。Default:继承节点 DNS 配置,不使用集群 DNS,通常只在特殊调试场景使用。None:完全自定义,必须配合dnsConfig指定 nameserver、search 和 options。ClusterFirstWithHostNet:Pod 使用 hostNetwork 时,仍希望走集群 DNS,需显式设置。
当需要为特定域名指定自定义解析时,可以通过 dnsConfig 增加 search 域或修改 ndots 等参数。例如,将 ndots 调小可以减少不必要的 search 域拼接查询,降低解析延迟;增加自定义 search 域可以让短名称优先匹配内部域名。对于需要覆盖某个外部域名的场景,更推荐在 CoreDNS 的 ConfigMap 中增加 hosts 或 rewrite 插件配置,而不是在每个 Pod 上单独修改 dnsConfig。
六、典型排查思路
当遇到服务名无法解析时,可以按以下顺序定位:首先在 Pod 内确认 /etc/resolv.conf 的 nameserver 和 search 域是否符合预期;其次用 dig payment.prod.svc.cluster.local 测试 FQDN 是否可解析;若 FQDN 正常但短名称失败,检查 search 域和 ndots 设置;若 FQDN 也失败,检查 CoreDNS Pod 是否正常运行、ConfigMap 是否被误改、Service 与 Endpoint 是否存在。对于 Headless Service,还要确认后端 Pod 是否处于 Ready 状态,因为只有就绪端点才会出现在 DNS 返回结果中。
掌握集群 DNS 的层次结构、记录格式与策略配置,能够帮助我们在 OpenShift 中更高效地实现服务发现,也能在解析异常时快速缩小排查范围,避免把 DNS 问题误判为网络连通性问题。