2. CoreDNS 架构解析:插件机制、核心组件与启动流程

CoreDNS 是 Kubernetes 集群默认的 DNS 解析组件,其设计哲学是“通过插件组合实现 DNS 服务”。理解 CoreDNS 的架构是排查 DNS 性能瓶颈和进行亲和性调优的前提。本章将深入拆解其插件机制、三大核心组件(Server / Plugin / Zone)以及完整的启动流程。

2.1 插件机制:链式处理与组合

CoreDNS 的核心是一个插件链(Plugin Chain)。每个插件实现一个独立的 DNS 处理逻辑,多个插件按顺序串联,形成请求处理流水线。这种设计使得 CoreDNS 功能高度可扩展,用户只需在 Corefile 中声明插件顺序即可定制行为。

关键特性: 插件链是顺序执行的,前一个插件的输出作为后一个插件的输入。如果某个插件返回“未命中”(如 kubernetes 插件未找到记录),请求会继续传递给下一个插件;如果返回“拒绝”(如 acl 插件拦截),则直接终止。

常见的插件分类如下:

类别 代表插件 功能说明
核心查询 kubernetes 从 Kubernetes Service / Pod 资源生成 DNS 记录
转发/上游 forward 将未解析的请求转发到外部 DNS 服务器(如 8.8.8.8)
缓存 cache 对 DNS 响应进行 TTL 缓存,减少上游查询压力
健康检查 health 暴露 HTTP 端点供 kubelet 或 Prometheus 探测存活
指标暴露 prometheus 提供 DNS 请求量、延迟、错误率等 Prometheus 指标
访问控制 acl 基于源 IP 或请求类型进行白名单/黑名单过滤
日志/调试 log / errors 记录请求日志和错误信息,用于故障排查

2.2 核心组件:Server / Plugin / Zone

CoreDNS 的运行时由三个抽象层构成,它们共同决定了请求如何被接收、处理和响应。

  • Server(服务器):负责监听 UDP/TCP 端口(默认 53),接收 DNS 查询请求,并将请求分发给对应的 Zone 处理。CoreDNS 可以同时运行多个 Server,每个 Server 绑定不同的地址或端口。
  • Zone(区域):一个 Zone 对应一个 DNS 域名空间(如 cluster.local)。Zone 由一组插件链定义,Corefile 中每个 zone { ... } 块就是一个 Zone 配置。请求的域名匹配到哪个 Zone,就由该 Zone 的插件链处理。
  • Plugin(插件):Zone 内部的具体处理单元。每个插件实现 Plugin 接口,包含 ServeDNS 和 Name 方法。插件链中的每个插件按顺序执行,直到某个插件返回“成功”或“拒绝”。
架构类比: Server 相当于“接线员”,Zone 相当于“部门”,Plugin 相当于“部门内的处理专员”。接线员接到电话(DNS 请求),根据号码(域名)转接到对应部门,部门内的专员们按流程依次处理。
CoreDNS 核心组件架构图 CoreDNS 核心组件架构 外部 DNS 客户端 Server(监听 :53,接收请求) UDP/TCP 端口管理 · 请求分发 Zone 匹配(按域名:cluster.local / in-addr.arpa / .) Zone: cluster.local Zone: in-addr.arpa Zone: . (根域) Plugin Chain(插件链:kubernetes → cache → forward → log → ...)

2.3 启动流程:从 Corefile 到服务就绪

CoreDNS 的启动过程分为四个阶段,理解每个阶段有助于定位启动失败或配置加载错误的问题。

  1. 配置解析阶段:读取 Corefile(默认路径 /etc/coredns/Corefile),解析 Zone 块和插件参数。如果 Corefile 语法错误,进程直接退出并报错。
  2. 插件初始化阶段:按 Corefile 中声明的顺序,依次调用每个插件的 setup 函数。插件在此阶段完成内部状态初始化(如建立 Kubernetes 客户端连接、打开缓存存储等)。
  3. Server 启动阶段:创建 UDP/TCP 监听 socket,绑定到配置的地址和端口(默认 :53)。启动 goroutine 循环接收 DNS 请求。
  4. 就绪与健康检查阶段:如果配置了 health 插件,CoreDNS 会启动 HTTP 端点(默认 :8080/health)。kubelet 或负载均衡器通过该端点确认服务是否可用。
常见启动故障: 如果 CoreDNS 启动后 CrashLoopBackOff,通常原因包括:Corefile 语法错误、kubernetes 插件无法连接 API Server(RBAC 权限不足)、forward 插件配置的上游 DNS 不可达。检查日志时重点关注 plugin/kubernetes: failed to create client 或 dial tcp: lookup xxx on xxx:53: read udp: connection refused 等关键字。
CoreDNS 启动流程时序图 CoreDNS 启动流程(四阶段) 阶段 1:配置解析 读取 Corefile → 解析 Zone 块 → 校验插件参数语法 阶段 2:插件初始化 按顺序调用插件 setup() → 建立 API Server 连接 / 初始化缓存 阶段 3:Server 启动 创建 UDP/TCP socket → 绑定 :53 → 启动 goroutine 接收请求 阶段 4:就绪与健康检查 启动 health HTTP 端点 → 等待 kubelet 探测 → 标记 Ready

2.4 Corefile 配置示例与插件链解读

以下是一个生产环境常见的 Corefile 配置,展示了 Zone、插件链和参数组合:

.:53 {
    # 启用日志,记录所有 DNS 请求
    log . {
        class all
    }
    # 记录错误
    errors
    # 健康检查端点
    health {
        lameduck 5s
    }
    # 指标暴露
    prometheus :9153
    # 缓存,TTL 30s,最多 10000 条记录
    cache {
        success 30 10000
        denial 5 5000
    }
    # Kubernetes 插件,从集群资源生成 DNS 记录
    kubernetes cluster.local. in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    # 转发未解析的请求到上游 DNS
    forward . /etc/resolv.conf {
        max_concurrent 1000
    }
    # 循环负载均衡
    loadbalance
}
插件链执行顺序解读: 当请求到达时,先经过 log 记录日志 → errors 捕获错误 → health 不处理查询(仅暴露端点)→ prometheus 记录指标 → cache 检查缓存命中 → kubernetes 尝试解析集群域名 → 如果未命中且 fallthrough 允许,则继续到 forward 转发到外部 DNS → 最后 loadbalance 对多 A 记录做随机排序。理解这个顺序是调优和排查的基础。

2.5 架构设计对性能的影响

CoreDNS 的插件链架构在带来灵活性的同时,也引入了性能敏感点:

  • 插件顺序:将 cache 放在 kubernetes 之前可以大幅减少对 API Server 的查询压力;反之,如果 log 插件放在最前面且日志级别过高,会显著增加延迟。
  • Zone 匹配开销:CoreDNS 使用前缀树(Trie)匹配域名,Zone 数量过多或域名层级过深会增加匹配时间。生产环境建议将 Zone 数量控制在 10 个以内。
  • goroutine 模型:每个 DNS 请求由一个 goroutine 处理,默认无限制。当并发量超过节点 CPU 核数时,goroutine 调度开销会急剧上升,此时需要配合 max_concurrent 参数进行限流。