CoreDNS:如何把 Kubernetes 服务发现写进 DNS

核心观点:CoreDNS 是 CNCF 毕业的插件化权威 DNS 服务器。在 Kubernetes 中,它通过 kubernetes 插件监听 API Server,将 Service / EndpointSlice 动态合成为 DNS 记录,承担集群内服务发现的首跳解析;流量转发与治理由 kube-proxy / CNI / Gateway / Mesh 承接。


0. 核心结论

维度 结论
范式定位 声明式平台发现(Service + CoreDNS)替代集群内应用级注册中心;非简单换地址
定义 Go 实现的插件化权威 DNS;CNCF 毕业项目;Kubernetes 默认集群 DNS(≥1.13)
控制面职责 kubernetes 插件 watch API,将 Service / EndpointSlice 合成 A/AAAA/SRV 记录
数据面衔接 解析结果交付 kube-proxy / CNI,完成 ClusterIP → Pod 的流量转发
标准调用 <service>.<namespace>.svc.cluster.local
跨 NS 短名 <service>.<namespace>(依赖 search 域补全)
排障路径 应用配置 → resolv.conf → 解析验证 → Service/EndpointSlice → CoreDNS
非目标 服务注册 · 流量治理 · 灰度路由 · 业务级健康裁决

1. 背景与问题定义

1.1 典型迁移场景

工作负载由 VM 迁至容器时,常见第一步并非拆分微服务,而是将 Web 与 API 分别容器化,例如 portal-weborder-api

环境 服务定位方式 核心矛盾
VM 静态 IP 或反向代理转发 实例地址相对稳定
Kubernetes 工作负载映射为 Pod Pod IP 随重建、扩缩容、调度而漂移

待解问题portal-web 如何以稳定方式定位 order-api

传统路径中,服务实例向 Eureka / Nacos / Consul 注册,调用方通过 SDK 完成发现。迁移至 Kubernetes 后,若继续固化 IP 或强绑定注册中心 SDK,将与平台原生的声明式服务发现机制产生冲突——二者解决的是同一类问题,但架构哲学不同(详见 §3)。

职责划分Service 声明稳定入口;CoreDNS 解析服务标识;kube-proxy/CNI 完成负载均衡——三者组合,在集群内覆盖注册中心的基础发现能力。

1.2 文档结构

# 章节 阅读收益
§3 范式对比 注册中心 vs Service + CoreDNS 能力边界与选型
§4 CoreDNS 本体 架构、插件模型、与 kube-dns 差异
§5–7 解析机制 链路、记录类型、Pod 侧查询
§8–10 迁移与运维 注册中心剥离 · 排障 · 容量

2. 对象模型

阅读前提:先厘清 Kubernetes 控制面对象及其与 DNS 的映射关系,再深入 CoreDNS 实现。

数据面

DNS层

工作负载

控制面

解析完成后

Service
稳定入口声明

EndpointSlice
后端端点集合

Pod

kubernetes 插件

A / AAAA / SRV

kube-proxy / CNI

对象 职责 DNS 层关联
Service 声明 ClusterIP 或 Headless 语义 决定 FQDN 结构与记录类型
EndpointSlice 维护后端 Pod IP:Port 集合 Headless / SRV 记录的数据源
CoreDNS 插件化 DNS 服务进程 kubernetes 插件监听并合成应答
kube-proxy / CNI 执行四层转发 承接 DNS 解析之后的数据路径

说明:EndpointSlice 已成为 Service 后端发现的主路径;CoreDNS 通过 Kubernetes API 按配置 watch Service、EndpointSlice、Namespace、Pod 等对象,按 DNS 规范合成应答。


3. 服务发现范式对比

本章目标:厘清注册中心与 Service + CoreDNS 是否解决同一问题能力如何拆分何时保留注册中心何时应迁移

行业共识(Kubernetes 官方文档、CNCF 实践):在 Kubernetes 集群内,Service + CoreDNS 是默认且推荐的服务发现基座;引入 Eureka / Nacos / Consul 并行运行,往往意味着与平台能力重复,增加运维负担。高级治理应叠加 Gateway 或 Service Mesh,而非用注册中心替代 DNS。(参考:NILUS、Uplatz 架构分析、HashiCorp Consul 社区讨论)

3.1 范式转变:从「实例注册」到「平台调和」

维度 注册中心范式 Kubernetes 范式
哲学 命令式:实例主动上报「我在哪」 声明式:平台声明「我要什么」,控制器持续调和
发现单元 实例(IP:Port) 服务(Service 身份)
状态来源 应用心跳 + 注册 API API Server + EndpointSlice 控制器
消费方式 SDK / HTTP API 查实例列表 标准 DNS 解析服务名
负载均衡 客户端(Ribbon、自研) 服务端(kube-proxy / IPVS / eBPF)
耦合度 业务代码依赖注册中心客户端 业务仅依赖主机名,与平台解耦

本质变化:发现责任从应用层下沉到编排平台——这不是「把 Nacos 地址换成 CoreDNS 地址」,而是服务发现模型的替换

3.2 双路径架构对照

K8s_Service_CoreDNS路径

创建 Service + Deployment

EndpointSlice 控制器同步 Pod

CoreDNS watch API 合成 DNS

payment-service

DNS 解析 payment-api.payment.svc...

获得 ClusterIP

kube-proxy/CNI 转发至就绪 Pod

注册中心路径

order-service 启动

注册 IP:Port 至 Nacos

Nacos 维护实例列表

payment-service

SDK 查询 Nacos

客户端负载均衡选实例

直连 Pod/VM IP

3.3 注册中心完整链路(Eureka / Nacos / Consul)

以电商 order-service 调用 payment-service 为例:

阶段 参与方 动作
1 启动 payment-service 向注册中心上报 10.10.8.21:8080、元数据、健康状态
2 续约 payment-service 周期性心跳,维持租约
3 发现 order-service 通过 Nacos SDK 查询 payment-service 实例列表
4 选路 order-service Ribbon / 自研策略在实例间负载均衡
5 调用 order-service 直连选中实例 IP
6 剔除 注册中心 心跳超时后移除实例

注册中心额外能力(超出基础 DNS 的部分):

能力 说明 典型产品
动态配置 配置中心、热推送 Nacos Config
元数据路由 版本、权重、标签路由 Nacos / Consul
跨环境统一目录 VM + K8s + 多云实例同一视图 Consul / Nacos
显式健康模型 应用自定义健康检查逻辑 Eureka / Consul
CAP 取向 Eureka 偏 AP;Consul 偏 CP 架构选型相关

3.4 Service + CoreDNS 完整链路

同等场景,Kubernetes 原生路径:

阶段 参与方 动作
1 声明 平台工程师 创建 payment-api Service(selector 关联 Pod)
2 调和 EndpointSlice 控制器 根据 Ready Pod 自动维护后端地址集合
3 合成 CoreDNS kubernetes 插件 watch API,生成 payment-api.payment.svc.cluster.local → ClusterIP
4 解析 order-service 标准 DNS 查询(无需 SDK)
5 转发 kube-proxy / CNI ClusterIP 负载均衡至就绪 Pod
6 剔除 Readiness 探针 不健康 Pod 自动移出 EndpointSlice,DNS/转发同步更新

关键差异:应用无需注册代码、无需发现 SDK、无需客户端负载均衡库——平台已内建。

3.5 多维能力对比

维度 注册中心 Service + CoreDNS 说明
集群内基础发现 K8s 原生方案足够覆盖
语言 / 框架无关 DNS 为标准协议;SDK 绑定语言
应用零侵入 注册中心需 SDK 或 Sidecar
实例级元数据 DNS 仅返回 IP;元数据需 Mesh/标签
权重 / 灰度路由 需 Gateway / Istio / Argo Rollouts
客户端负载均衡 ✗(服务端 LB) K8s 默认服务端均衡
跨集群统一目录 单集群 DNS 足够;多集群用 MCS/Mesh
VM + K8s 混合 外部依赖用 ExternalName / 注册中心桥接
配置中心一体化 ●(Nacos) K8s 用 ConfigMap / Secret
运维组件数 +1 集群 0(平台内置) 并行注册中心增加 HA、升级、监控成本
一致性模型 最终一致(AP)或 CP 控制面调和(声明式) 依赖控制器而非心跳
TTL / 缓存延迟 秒级(SDK 缓存) 秒级(DNS TTL + 客户端缓存) 二者均有传播延迟
健康检查 应用自定义 Readiness 探针 + Endpoint 语义不同:基础设施 vs 业务
Spring Cloud 集成 原生 需改造(去 Eureka/Ribbon) 见 §8 迁移框架

图例:● 强项 · ○ 可覆盖 · △ 部分覆盖 / 需补充 · ✗ 非职责

3.6 能力归属:谁解决什么问题

需求 注册中心方案 K8s 原生方案 推荐叠加
集群内服务互调 SDK + 注册 Service DNS + CoreDNS
负载均衡 客户端 Ribbon kube-proxy / IPVS / eBPF
实例健康剔除 心跳超时 Readiness + EndpointSlice
金丝雀 / 权重发布 元数据路由 Argo Rollouts / Mesh
熔断 / 重试 / 超时 Hystrix / Sentinel Mesh / 应用框架
mTLS / 零信任 Consul Connect Istio / Linkerd
跨命名空间隔离 逻辑服务名 Namespace + DNS NetworkPolicy
VM 遗留系统互通 统一注册 ExternalName / Ingress 注册中心桥接(过渡期)
多集群服务发现 全局注册 单集群 DNS MCS-API / 多集群 Mesh
动态配置 Nacos Config ConfigMap + 控制器 Nacos / Vault(按需)

结论:注册中心是应用级服务目录 + 治理平面;Service + CoreDNS 是基础设施级寻址层。二者层级不同,不应在同一维度简单类比「谁更好」。

3.7 DNS 方案的局限与 Kubernetes 如何补足

纯 DNS 发现的已知局限(行业文献共识)及 K8s 侧的补偿机制:

DNS 局限 传统 DNS 环境 Kubernetes 环境中的补偿
TTL 导致变更传播延迟 客户端缓存过期前仍访问旧 IP EndpointSlice 更新 + 短 TTL(5–30s);ClusterIP 屏蔽 Pod IP 变化
DNS 不做健康检查 死实例仍在记录中 Readiness 探针 → 不健康 Pod 移出 Endpoint
客户端缓存不可控 JVM / libc / 语言运行时缓存策略不一 统一运行时 DNS 策略;压测中验证连接池与缓存刷新
无实例元数据 仅返回 IP 需 Mesh 或 Gateway 提供版本/权重路由
负载均衡能力弱 DNS 轮询 kube-proxy / CNI 在 Service 层做均衡
查询放大 search 域补全 autopath / NodeLocal DNSCache / FQDN 规范

注意:CoreDNS 解决的是名字 → 入口地址入口 → 健康后端由 EndpointSlice + 探针保证;流量策略不属于 DNS 层。

3.8 注册中心仍不可替代的场景

场景 原因 建议架构
VM + K8s 混合部署 需要跨运行时统一服务目录 注册中心桥接 + K8s Service 同步(过渡期)
多集群无 Mesh 单集群 DNS 无法跨集群 Consul / Nacos 全局视图,或 MCS-API
Spring Cloud / Dubbo 存量 框架深度绑定注册中心 分阶段剥离 SDK,见 §8
配置 + 发现一体化 Nacos 同时承担配置中心 发现迁 K8s DNS;配置保留 Nacos 或迁 ConfigMap
非 HTTP RPC 治理 Dubbo 路由依赖注册元数据 保留 Nacos 或迁 Mesh
合规审计级路由 需显式可查询的服务目录 注册中心或 Mesh 控制面

行业建议(HashiCorp、NILUS):Kubernetes 集群内默认不引入并行注册中心;异构或多集群场景再评估 Consul / Nacos 作为补充层,而非替代 CoreDNS。

3.9 三种发现模式定位

模式 定位 适用
Registry(注册中心) 应用级目录 + 跨运行时治理 混合云、多集群、框架绑定
DNS(Service + CoreDNS) 平台级寻址,集群内默认 东西向流量、无状态微服务
Mesh(Istio / Linkerd) 发现 + 流量策略 + 安全 金丝雀、mTLS、全链路治理

异构补充

按需叠加

集群内默认

过渡期

Service + CoreDNS
基础寻址

Gateway / Ingress
南北向

Service Mesh
流量治理

注册中心
跨运行时目录

选型原则:集群内从 DNS 开始;治理需求叠加 Mesh/Gateway;异构环境注册中心作桥接——避免三套并行。

3.10 选型决策

服务发现需求

调用方与被调方
均在同一 K8s 集群?

仅需基础互调?

需要跨 VM/K8s/多集群统一目录?

Service + CoreDNS

需要灰度/mTLS/熔断?

DNS + Gateway / Mesh

注册中心桥接
+ 逐步迁 K8s DNS

框架强绑定 Nacos/Dubbo?

分阶段:DNS 发现 + 保留配置/治理

结论 条件
首选 Service + CoreDNS 同集群东西向、无状态服务、标准 HTTP/gRPC
DNS + Mesh 需版本路由、mTLS、重试熔断,且愿承担 Mesh 运维成本
保留注册中心 VM 混合、多集群无 Mesh、Dubbo/Spring Cloud 存量
反模式 K8s 集群内同时跑 Nacos + CoreDNS 做同一层发现

4. CoreDNS 深度解析

本章目标:阐明 CoreDNS 的定义、演进路径、插件架构及在 Kubernetes 中的部署与配置模型。

4.1 定义与定位

CoreDNS 是基于 Go 实现的插件化权威 DNS 服务器(Authoritative DNS Server),具备双重定位:

定位 说明
Kubernetes 集群 DNS 自 1.13 起为默认方案,全面替代 kube-dns
通用 DNS 引擎 可独立部署,后端支持 etcd、Consul、Zone 文件及上游转发
CNCF 毕业项目 2017 纳入 → 2018 Incubating → 2019 Graduated

权威 DNS:对指定 Zone 拥有最终应答权。*.svc.cluster.local 由 CoreDNS 权威解析;集群外域名经 forward 插件转交上游递归解析器。

设计原则:相较 BIND、Knot、PowerDNS 等单体架构,CoreDNS 以插件链组合能力——单二进制、可编排、可扩展。

4.2 技术演进

2014  SkyDNS2      基于 etcd 的服务发现 DNS(Kubernetes 早期)
         ↓         扩展性与可观测性不足
2016  CoreDNS      SkyDNS 继任者;插件链架构(Miek Gieben)
         ↓         CNCF 孵化;kubernetes 插件成熟
2017  kube-dns     三容器架构(kube-dns + dnsmasq + sidecar)
         ↓         1.11 可选 CoreDNS;1.13 默认;kube-dns 退役
2019  CoreDNS      CNCF 毕业;成为 Kubernetes 默认集群 DNS 标准方案
代际 代表方案 架构特征 主要局限
第一代 SkyDNS etcd 后端服务发现 难以集成监控、缓存与多后端
第二代 kube-dns 三容器 Sidecar 模式 架构复杂、缓存隐患、定制困难
当前 CoreDNS 单进程 + 插件链 需掌握 Corefile 与插件语义

4.3 插件架构:Server Block 与 Plugin Chain

配置基本单元为 Server Block(监听地址 + Zone 集合),每个 Server Block 挂载一条 Plugin Chain

命中

fallthrough / 非集群域

入站 DNS 查询

最长后缀 Zone 匹配
选择 Server Block

按编译时插件顺序
执行已启用插件

kubernetes
集群域权威应答

返回记录

forward
转发上游

cache / prometheus / errors
缓存、指标、日志

机制 行为描述 工程含义
Server Block 匹配 按最长 Zone 后缀选择配置块 cluster.local. 可拥有不同处理链
插件启用 Corefile 声明某插件及参数 未写入 Corefile 的插件不会参与本 Server Block
插件执行顺序 由 CoreDNS 编译时插件顺序决定 Corefile 行顺序主要表达配置,不等同于精确执行顺序
终止应答 插件生成响应并结束链路 kuberneteshostsfile
Fallthrough 插件在指定未命中场景继续下游 kubernetes 处理反向域、Pod 域常用
旁路观测 插件记录指标、日志或健康状态 prometheuserrorshealth

要点:Corefile 决定「启用什么、参数是什么」;编译时插件链决定「相对执行顺序」。因此生产调优应关注插件语义与参数,不应依赖移动 Corefile 行位置来改变链路行为。

4.4 常用内置插件

CoreDNS 默认内置约 30+ 插件。Kubernetes 生产环境高频使用:

插件 分类 功能说明
kubernetes 数据源 监听 API Server,合成 Service / Pod 记录
forward 转发 非集群域查询转上游 DNS
cache 性能 应答缓存,降低重复查询负载
errors 可观测 错误级日志输出
health 运维 Liveness 端点(:8080/health
ready 运维 Readiness;informer 同步完成后置位
prometheus 可观测 指标暴露(:9153/metrics
reload 运维 Corefile 热重载
loop 安全 转发环路检测
loadbalance 性能 A 记录随机打散,均衡客户端选路
autopath 性能 服务端 search 补全,抑制查询放大
rewrite 策略 查询名 / 应答重写
hosts / file 数据源 静态记录(类 hosts / Zone 文件)
etcd 数据源 etcd 后端(兼容 SkyDNS 模式)

扩展:支持编译第三方插件,如 multicluster(基于 MCS-API 的多集群 DNS)。

4.5 与 kube-dns 对照

维度 kube-dns(已退役) CoreDNS
运行时 三容器 Pod 单进程
配置模型 多段 ConfigMap 统一 Corefile DSL
扩展机制 几乎不可扩展 插件链可组合
缓存实现 dnsmasq cache 插件
可观测性 有限 prometheus 指标完备
Stub 域 stubDomains 独立 Server Block + forward
默认版本 ≤1.12 ≥1.13
Service 命名 kube-dns 保留 kube-dns(向后兼容)

4.6 Kubernetes 部署拓扑

通常作为集群 DNS add-on 部署于 kube-system。不同发行版可能由 kubeadm、托管云控制面或平台 Addon Manager 管理,但核心资源形态一致:

资源类型 名称 职责
Deployment coredns 多副本运行;监听 :53 UDP/TCP
Service kube-dns ClusterIP;Pod nameserver 指向此处
ConfigMap coredns 承载 Corefile
ServiceAccount coredns 访问 API Server 的 RBAC 主体

kubelet 注入参数(决定 Pod DNS 行为):

参数 默认值 含义
--cluster-dns kube-dns ClusterIP Pod nameserver
--cluster-domain cluster.local 集群 DNS 后缀
kubectl -n kube-system get deploy,svc,cm,sa -l k8s-app=kube-dns
kubectl -n kube-system get cm coredns -o jsonpath='{.data.Corefile}'

4.7 Corefile 配置模型

<zone>[:<port>] {
    <plugin> [<args>]
    ...
}

官方默认配置

.:53 {
    errors
    health { lameduck 5s }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}
指令 语义
.:53 全接口监听 53 端口
kubernetes cluster.local ... 对集群域及反向域权威解析
pods insecure 启用 Pod IP 形式的正向查询(兼容 kube-dns)
fallthrough ... 反向域未命中时透传下游
forward . /etc/resolv.conf 非集群域转发至节点上游
cache 30 插件层缓存 30s
loadbalance 多条 A 记录随机排序
reload ConfigMap 变更自动生效
loop 环路检测与阻断

冷启动:启动后 informer 同步窗口默认 5s;未同步记录可能返回 SERVFAILready 插件在缓存就绪后报告 Ready;大规模集群可显式调大 startup_timeout

4.8 Stub Domain 与上游解析

通过追加 Server Block 实现域级转发(等价于 kube-dns stubDomains):

.:53 {
    kubernetes cluster.local in-addr.arpa ip6.arpa { ... }
    forward . 172.16.0.1
    ...
}
consul.local:53 {
    errors
    cache 30
    forward . 10.150.0.1
}
需求 配置策略
指定全局上游 forward . <ip>
域级专用解析器 独立 Server Block
阻断特定域 template / rewrite 返回 NXDOMAIN

约束:forward 上游不支持 FQDN 形式(如 ns.example.com 将被忽略)。

4.9 能力边界

职责范围内 职责范围外
集群内外 DNS 解析与转发 服务注册与心跳维护
基于 K8s 对象的动态记录合成 灰度 / 金丝雀 / 熔断 / 限流
缓存、指标、健康探测 替代 Nacos / Consul 治理平面
Stub 域与记录重写 HTTP 级业务健康裁决
DNS over TLS / HTTPS 替代 kube-proxy 负载均衡

4.10 Corefile 变更工作流

原则:CoreDNS 是全集群关键路径组件;Corefile 变更必须像控制面变更一样灰度、可回滚、可观测。

阶段 动作 命令 / 检查
1 备份 保存当前 Corefile 与 Deployment kubectl -n kube-system get cm coredns -o yaml > coredns.cm.bak.yaml
2 校验 在测试集群或临时 Pod 中验证语法 coredns -conf Corefile -dns.port=1053
3 小步发布 仅修改必要插件参数 优先改 cacheforwardkubernetes 子参数
4 观察 关注 SERVFAIL、NXDOMAIN、延迟、CoreDNS 重启 Prometheus + kubectl -n kube-system logs deploy/coredns
5 回滚 恢复 ConfigMap 并触发重载 kubectl apply -f coredns.cm.bak.yaml

推荐:在生产集群中使用 GitOps 管理 Corefile,所有变更带审阅、Diff、回滚记录;禁止直接手工编辑 ConfigMap 后离开现场。


5. 解析链路与生产实践

5.1 端到端时序

上游 DNS API Server CoreDNS kube-dns Service /etc/resolv.conf 业务容器 上游 DNS API Server CoreDNS kube-dns Service /etc/resolv.conf 业务容器 kube-proxy / CNI 完成后续转发 查询 order-api.order.svc.cluster.local 请求导向 ClusterIP:53 路由至 CoreDNS Pod 插件链处理(缓存 / kubernetes / forward) 读取 Service / EndpointSlice 返回 A 记录(ClusterIP) 查询 api.example.com 外部域查询 forward 插件处理 转上游递归解析 返回公网记录

5.2 分层模型

层级 组件 职责
L1 /etc/resolv.conf kubelet 按 dnsPolicy 注入解析配置
L2 kube-dns Service 集群 DNS 统一入口(后端为 CoreDNS)
L3 CoreDNS 集群内 kubernetes;集群外 forward
L4 API Server Service / EndpointSlice 数据源

5.3 生产增强手段

手段 机制 适用场景
NodeLocal DNSCache 节点级 DNS 缓存 DaemonSet 大规模集群、高 QPS
autopath 服务端 search 优化 pods verified;抑制查询放大
水平扩容 增加副本 + 反亲和 CoreDNS CPU 或延迟接近阈值
Cluster Proportional Autoscaler 按节点数 / Core 数调整副本 集群规模变化频繁
Pod 反亲和 跨节点分布 规避单点故障
PDB 升级过程最低可用保障 生产环境标配
forward 并发控制 max_concurrent 限制上游并发 上游 DNS 抖动或外部域洪峰
上游隔离 内外域拆分 Server Block 企业 DNS、Consul、私有域混合

5.4 查询放大与 NodeLocal DNSCache

默认 ndots:5 会让短名和多数外部域先走 search 域补全。例如容器内查询 api.example.com 时,可能先尝试:

api.example.com.<ns>.svc.cluster.local
api.example.com.svc.cluster.local
api.example.com.cluster.local
api.example.com
问题 影响 处理
search 补全过多 单次业务解析放大为多次 DNS 查询 外部域使用尾点:api.example.com.
节点到 CoreDNS 跨节点访问 网络抖动放大 DNS 延迟 部署 NodeLocal DNSCache
UDP conntrack 压力 高 QPS 下丢包或超时 NodeLocal DNSCache 将本地查询转为 TCP/本地缓存
重复 NXDOMAIN 无效短名持续冲击 CoreDNS 规范配置名;监控 NXDOMAIN TopN

实践建议:大规模集群优先启用 NodeLocal DNSCache;应用侧将外部域名写成带尾点 FQDN,跨命名空间服务写成 <svc>.<ns> 或完整 FQDN。

5.5 解析链路中的缓存层

层级 缓存主体 可控性 关注点
L1 应用 / 语言运行时 差异较大 JVM、Go、glibc、连接池各有行为
L2 NodeLocal DNSCache 平台可控 节点级命中率、DaemonSet 健康
L3 CoreDNS cache 插件 平台可控 正向 / 负向缓存 TTL、命中率
L4 上游企业 DNS 外部依赖 超时、递归策略、企业域分流

注意:DNS TTL 只约束 DNS 缓存,不会自动刷新应用连接池中已建立的 TCP 连接。服务下线、灰度切换、证书轮转等场景必须同时考虑连接池生命周期。


6. DNS 记录与命名规范

6.1 FQDN 结构

order-api . order . svc . cluster.local
└─ Svc ─┘ └─ NS ┘ └┘ └──── cluster-domain(默认 cluster.local)────┘

6.2 记录类型(DNS-Based Service Discovery 规范)

类型 应答行为 典型场景
ClusterIP Service A/AAAA → ClusterIP 无状态微服务互调
Headless Service A/AAAA → 就绪 Pod IP 列表 StatefulSet 成员发现
ExternalName Service CNAME → 外部主机名 VM / 外部依赖过渡
SRV _port._proto.<svc>.<ns>.svc.<domain> 命名端口发现
Pod IP 10-244-1-5.<ns>.pod.cluster.local 调试(pods 非 disabled)
Pod hostname <hostname>.<subdomain>.<ns>.svc.<domain> Headless + subdomain

StatefulSet 稳定标识:

<pod-name>.<service-name>.<namespace>.svc.cluster.local
示例:mysql-0.mysql.data.svc.cluster.local  →  固定路由至 mysql-0

6.3 Headless + StatefulSet 参考配置

apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: data
spec:
  clusterIP: None
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: data
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
Pod 稳定 FQDN
mysql-0 mysql-0.mysql.data.svc.cluster.local
mysql-1 mysql-1.mysql.data.svc.cluster.local

约束:Pod 处于 Ready 状态方生成 A 记录;publishNotReadyAddresses: true 可覆盖此行为。

6.4 kubernetes 插件参数

参数 语义 默认 / 建议
pods disabled 拒绝 Pod IP 类查询 插件默认
pods insecure 无校验返回 A 记录 官方默认 Corefile
pods verified 校验 Pod 存在性 autopath 前置;内存开销较高
endpoint_pod_names A 记录优先使用 Pod 名 StatefulSet 场景推荐
ignore empty_service 无就绪 Endpoint 时 NXDOMAIN 允许 search 继续匹配
ttl N 记录 TTL(0–3600s) 默认 5s;生产常设 30s
namespaces 限定暴露的命名空间 多租户隔离
labels 按标签过滤资源 精细化 DNS 暴露

6.5 ClusterIP Service 参考

apiVersion: v1
kind: Service
metadata:
  name: payment-api
  namespace: payment
spec:
  selector:
    app: payment-api
  ports:
    - name: http
      port: 8080
      targetPort: 8080
调用上下文 推荐地址
同命名空间 http://payment-api:8080
跨命名空间 http://payment-api.payment.svc.cluster.local:8080
kubectl run dnsutils --image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
  --restart=Never -- sleep 3600
kubectl exec dnsutils -- nslookup payment-api.payment.svc.cluster.local

7. Pod 侧解析机制

7.1 resolv.conf 结构

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
字段 语义
nameserver 指向 kube-dns ClusterIP
search 短名补全域列表(≤32 条,总长 ≤2048)
ndots:5 标签内 . 少于 5 且无尾点时,优先 search 补全

7.2 解析规则(官方语义)

规则 示例(Pod 位于 test NS) 结果
R1 查询 data(服务在 prod 限定 test NS → 未命中
R2 查询 data.prod search 补全 → 命中 prod/data
R3 查询 payment-api 依次 search 补全 → 命中

7.3 命名书写规范

场景 推荐格式
同命名空间 payment-api
跨命名空间 payment-api.payment 或完整 FQDN
外部域名 api.partner.example.com.(FQDN + 尾点)

统一约定:业务配置文件中优先使用完整 FQDN,代码示例和同命名空间临时调用可使用短名。这样可以减少跨命名空间迁移、灰度环境复制和 search 域差异带来的误解析。

7.4 dnsPolicy 策略

策略 行为 适用
ClusterFirst(默认) 优先集群 DNS;外部域 forward 常规工作负载
ClusterFirstWithHostNet HostNetwork 下仍走集群 DNS hostNetwork: true 必配
Default 继承节点 resolv.conf 特殊网络需求
None + dnsConfig 完全自定义 精细化 DNS 控制

注:Windows 节点解析语义与 Linux 存在差异,混合集群需独立验证。

7.5 dnsConfig 示例

需要缩短外部域解析路径或注入企业内网搜索域时,可显式配置 dnsConfig

apiVersion: v1
kind: Pod
metadata:
  name: dns-demo
spec:
  dnsPolicy: ClusterFirst
  dnsConfig:
    options:
      - name: ndots
        value: "2"
      - name: timeout
        value: "2"
      - name: attempts
        value: "2"
    searches:
      - corp.example.com
  containers:
    - name: app
      image: registry.k8s.io/e2e-test-images/agnhost:2.39
参数 作用 风险
ndots 控制何时先按绝对域名查询 过低可能改变短名优先级
timeout 单次 DNS 查询超时 过低会放大瞬时抖动
attempts 重试次数 过高会放大故障流量
searches 追加搜索域 过多会增加查询次数

7.6 客户端运行时注意事项

运行时 / 组件 关注点 建议
JVM DNS 缓存受 networkaddress.cache.ttl 影响 显式设置合理 TTL,避免永久缓存
Go 默认使用系统解析器或 Go 解析器 容器内压测验证 GODEBUG=netdns 行为
glibc 遵循 resolv.conf,受 ndots/search 影响明显 外部域使用尾点
HTTP 连接池 DNS 变更不等于连接立即重建 配置连接最大生存期与空闲回收
gRPC 长连接会隐藏后端变更 配置 keepalive、连接重建策略

8. 迁移实践

前提:迁移目标不是「停用 Nacos」,而是将发现层从应用级注册中心切换为平台级 Service DNS(见 §3)。

8.1 三阶段迁移框架(注册中心 → K8s DNS)

阶段 名称 动作 注册中心状态
P1 并行运行 K8s 内创建 Service;应用仍走 Nacos,验证 DNS 可达 保留,作兜底
P2 切换发现 调用方改 Service DNS;移除 @EnableDiscoveryClient、Ribbon 只保留配置/治理(可选)
P3 下线注册 剥离 SDK 依赖;Nacos 仅保留跨集群/VM 桥接(若需要) 缩减或退役

8.2 四层改造清单

层级 注册中心时代 K8s 时代 改造动作
L1 发现 Nacos / Eureka 查实例 Service DNS 删除注册代码 · 改主机名
L2 负载均衡 Ribbon 客户端 LB Service ClusterIP 移除 Ribbon 依赖
L3 配置 Nacos Config ConfigMap / Secret 按需保留或迁移
L4 治理 Sentinel / Hystrix Gateway / Mesh 评估是否叠加 Mesh

8.3 Spring Cloud 对照改造

Spring Cloud 组件 Kubernetes 替代 迁移要点
@EnableDiscoveryClient 无需注解 删除;直接 HTTP 调用 Service 名
spring-cloud-starter-netflix-eureka-client CoreDNS + Service 移除依赖
Ribbon / LoadBalancerClient kube-proxy 服务端 LB 移除;单地址 http://svc:port
spring-cloud-starter-alibaba-nacos-discovery Service DNS 发现剥离;配置可暂留 Nacos
Spring Cloud Gateway + Eureka Ingress / Gateway API 入口层独立迁移
Feign + 服务名 Feign + K8s DNS 名 URL 从逻辑名改为 http://order-api.order:8080

改造前(Eureka + Ribbon):

@FeignClient(name = "payment-service")
public interface PaymentClient { ... }
// 底层:查 Eureka → 选实例 → 直连 IP

改造后(K8s DNS):

@FeignClient(name = "payment-api", url = "http://payment-api.payment:8080")
public interface PaymentClient { ... }
// 底层:DNS 解析 → ClusterIP → kube-proxy 转发

或配置化:

# application.yml
payment:
  url: http://payment-api.payment.svc.cluster.local:8080

8.4 参考案例:VM → Kubernetes

portal-web → user-service → order-service → mysql
遗留配置 目标地址 对应改造
http://user-service.prod.company.local user-api.user.svc.cluster.local 建 Service · 改 URL
http://10.10.8.21:8080 order-api.order.svc.cluster.local 建 Service · 去 IP
MYSQL_HOST=10.10.12.30 mysql-0.mysql.data.svc.cluster.local Headless + StatefulSet
nacos://payment-service payment-api.payment.svc.cluster.local 发现走 DNS;治理走 Mesh

8.5 依赖映射

旧依赖 新入口 动作
http://10.10.8.21:8080 order-api.order.svc.cluster.local:8080 建 SVC · 改配置 · 删注册
nacos://payment-service payment-api.payment.svc.cluster.local 剥离 discovery SDK
eureka://order-service order-api.order.svc.cluster.local 移除 Eureka 客户端

8.6 ExternalName 过渡(VM 遗留)

apiVersion: v1
kind: Service
metadata:
  name: legacy-user
  namespace: user
spec:
  type: ExternalName
  externalName: user-service.prod.company.local

应答类型为 CNAME。限制:仅主机名 · 无端口映射 · 部分客户端兼容性受限。适用于 P1 并行阶段。

8.7 协作分工

角色 职责
平台工程 DNS 命名规范 · CoreDNS 运维 · 迁移节奏把控
应用团队 剥离 SDK · 配置改用 Service 名
架构 明确发现/配置/治理三层归属(见 §3.6)
SRE 监控 SERVFAIL / NXDOMAIN · 迁移期双轨验证

9. 场景决策

完整选型逻辑见 §3.10。本章为速查摘要。

服务发现需求

需要固定 Pod 身份?

ClusterIP Service

Headless + StatefulSet

需要流量治理?

CoreDNS 标准 DNS

叠加 Gateway / Mesh

VM/多集群混合?

注册中心桥接 + DNS

跨集群?

MCS-API + multicluster

Pod 级 DNS

场景 匹配度 关键实践
同集群无状态微服务 高度匹配 Service DNS,无需注册中心
StatefulSet 匹配 Headless + Pod FQDN
VM + K8s 混合 分阶段 注册中心桥接 → 逐步 DNS
Spring Cloud 存量 分阶段 P1 并行 → P2 剥离 SDK → P3 下线
流量治理 仅基础层 DNS + Gateway / Mesh,非 Nacos 路由
多集群 按需 MCS / Mesh / 全局注册中心

10. 运维与排障

10.1 容量规划

维度 建议基线
副本 ≥2;按 QPS、P99 延迟、CPU 饱和度水平扩展
资源 小型集群 100–300m CPU / 128–256Mi;大型集群按压测上调
拓扑 podAntiAffinity 跨节点分布
可用性 PDB:minAvailable: 1
API 压力 大规模集群调优 apiserver_qps / apiserver_burst
节点本地缓存 高 QPS 集群启用 NodeLocal DNSCache

容量判断信号

信号 含义 动作
CPU 持续 > 70% CoreDNS 处理能力接近瓶颈 增加副本或启用 NodeLocal DNSCache
P99 延迟升高 上游慢、缓存低命中或 CoreDNS 饱和 拆分内外域、调缓存、检查上游
SERVFAIL 增长 API / 上游 / CoreDNS 自身异常 先看 CoreDNS 日志与 forward 指标
NXDOMAIN 增长 错误域名、search 放大、服务缺失 统计 Top 查询名,回查应用配置
Pod 重启 / OOM watch 对象过多或资源不足 调资源、减少 pods verified、扩容

10.2 观测指标

类别 指标 / 端点 关注点
延迟 coredns_dns_request_duration_seconds P95/P99 与上游波动
吞吐 coredns_dns_requests_total typercodezone 分组
错误码 SERVFAILNXDOMAINREFUSED 区分系统异常与业务误配
API 客户端 coredns_kubernetes_rest_client_requests_total API Server 访问失败、限流
缓存 coredns_cache_hits_total / coredns_cache_misses_total 命中率、负向缓存
转发 coredns_proxy_request_duration_seconds{proxy_name="forward"}coredns_forward_max_concurrent_rejects_total 上游 DNS 延迟、错误与并发拒绝
记录编程 coredns_kubernetes_dns_programming_duration_seconds Service 变更到 DNS 可见的延迟
进程 process_cpu_seconds_totalprocess_resident_memory_bytes CPU / 内存容量
健康 :8080/health:8181/ready 存活与 informer 同步状态

PromQL 参考

# CoreDNS QPS
sum(rate(coredns_dns_requests_total[5m]))

# SERVFAIL 比例
sum(rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m]))
/
sum(rate(coredns_dns_responses_total[5m]))

# P99 解析延迟
histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le))

10.3 故障定位流程

「服务不可达」→ 按序排查,避免跳步

检查项 操作 期望
1 目标主机名 审查环境变量 / 配置 使用 <svc>.<ns> 或完整 FQDN
2 DNS 配置 kubectl exec <pod> -- cat /etc/resolv.conf nameserver 指向集群 DNS
3 解析结果 kubectl exec <pod> -- nslookup <fqdn> 返回 ClusterIP / Pod IP / CNAME
4 Service kubectl get svc -n <ns> <svc> -o wide Service 存在,端口正确
5 EndpointSlice kubectl get endpointslice -n <ns> -l kubernetes.io/service-name=<svc> 存在就绪 endpoint
6 CoreDNS Pod kubectl -n kube-system get pod -l k8s-app=kube-dns -o wide 多副本 Running / Ready
7 CoreDNS 日志 kubectl -n kube-system logs deploy/coredns --tail=100 无 loop、panic、API 错误
8 Corefile kubectl -n kube-system get cm coredns -o yaml Corefile 符合预期
9 指标 kubectl -n kube-system port-forward deploy/coredns 9153 查看 QPS、rcode、延迟

分叉判断:

现象 定位方向
解析失败 DNS 链路(本章)
解析成功、连接超时 Endpoint · NetworkPolicy · 数据面

10.4 典型故障模式

现象 根因倾向 处置
SERVFAIL 激增 冷启动 / API 不可达 检查 API 连通性 · 调整 startup_timeout
NXDOMAIN 激增 命名错误或 Service 缺失 核对配置与对象存在性
外部域解析慢 ndots 放大 · 缓存不足 FQDN 尾点 · 调优 cache
CoreDNS OOM pods verified + 大规模 watch 评估 pods insecure 或扩容
变更后 DNS 中断 Corefile 语法错误 变更前用 coredns -conf Corefile -dns.port=1053 试启动
CoreDNS CrashLoop loop 检测到转发环路 检查 forward . /etc/resolv.conf 是否指回集群 DNS
仅外部域失败 上游 DNS 不可达或企业域分流错误 检查 forward 上游、NetworkPolicy、防火墙
仅某命名空间失败 Service / EndpointSlice 不存在或无 Ready Pod 检查 selector、Readiness、命名空间
随机超时 UDP 丢包、conntrack、节点网络抖动 启用 NodeLocal DNSCache,检查节点网络
Headless 返回不完整 Pod 未 Ready 或未设置 subdomain 检查 publishNotReadyAddresses 与 StatefulSet 配置

10.5 常用诊断命令

# 查看 CoreDNS 资源
kubectl -n kube-system get deploy,svc,cm,pod -l k8s-app=kube-dns -o wide

# 从业务 Pod 内验证解析
kubectl exec -n <app-ns> <pod> -- cat /etc/resolv.conf
kubectl exec -n <app-ns> <pod> -- nslookup <svc>.<ns>.svc.cluster.local

# 临时启动调试 Pod
kubectl run dnsutils --image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
  --restart=Never -- sleep 3600
kubectl exec dnsutils -- nslookup kubernetes.default.svc.cluster.local

# 查看 Service 与 EndpointSlice
kubectl get svc -n <ns> <svc> -o yaml
kubectl get endpointslice -n <ns> -l kubernetes.io/service-name=<svc> -o wide

# 查看 CoreDNS Corefile 与日志
kubectl -n kube-system get cm coredns -o jsonpath='{.data.Corefile}'
kubectl -n kube-system logs deploy/coredns --tail=200

# 暴露指标
kubectl -n kube-system port-forward deploy/coredns 9153:9153

11. 快速参考

核心定义

CoreDNS = Go · 插件化权威 DNS · CNCF Graduated · K8s 默认集群 DNS
配置载体:Corefile | 集群内:kubernetes | 集群外:forward

FQDN 模板

<svc>.<ns>.svc.cluster.local           # ClusterIP
<svc>.<ns>                             # 跨 NS 短名
<pod>.<svc>.<ns>.svc.cluster.local     # StatefulSet
_<port>._<proto>.<svc>.<ns>.svc...      # SRV

常用命令

kubectl -n kube-system get deploy,svc,cm -l k8s-app=kube-dns
kubectl -n kube-system logs deploy/coredns --tail=100
kubectl -n kube-system get cm coredns -o jsonpath='{.data.Corefile}'
kubectl exec <pod> -- cat /etc/resolv.conf
kubectl exec <pod> -- nslookup <fqdn>

范式对比速记

注册中心 = 应用级目录 + SDK + 客户端 LB + 治理
K8s DNS  = 平台级寻址 + 零侵入 + 服务端 LB(kube-proxy)
治理需求 = Gateway / Mesh(不是 Nacos 替代 CoreDNS 的理由)

反模式

反模式 风险
K8s 内 Nacos 与 CoreDNS 做同层发现 重复运维、与平台对抗
只改地址不删 SDK 双轨发现、排障困难
用注册中心做金丝雀 应使用 Mesh / Rollouts
未验证即修改 Corefile 全集群 DNS 不可用
固化 Pod IP 与 Pod 生命周期冲突
跨 NS 仅使用短服务名 解析至错误命名空间
将 CoreDNS 用作治理平面 超出组件职责边界

附录 · 参考资料

资源 链接
CoreDNS 官网 https://coredns.io/
CoreDNS Manual https://coredns.io/manual/toc/
CNCF CoreDNS https://www.cncf.io/projects/coredns/
kubernetes 插件 https://coredns.io/plugins/kubernetes/
插件目录 https://coredns.io/plugins/
K8s DNS 概念 https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
自定义 DNS https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/
DNS 发现规范 https://github.com/kubernetes/dns/blob/master/docs/specification.md
DNS 调试 https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/
NodeLocal DNSCache https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/
部署清单 https://github.com/coredns/deployment/tree/master/kubernetes
服务发现范式对比(NILUS) https://www.nilus.be/blog/service_discovery_patterns_compared_in_kubernetes/
Consul 在 K8s 中的用例 https://discuss.hashicorp.com/t/what-are-advantages-use-consul-in-kubernetes-use-cases-without-service-mesh/9901
Spring Cloud → K8s 迁移 https://elamranioussama.me/blog/spring-cloud-to-kubernetes/
DNS vs Consul/Eureka 架构分析 https://uplatz.com/blog/an-architectural-analysis-of-service-discovery-patterns-a-comparative-study-of-consul-eureka-and-dns-based-implementations/
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐