在上一篇文章中,我们了解了 CoreDNS 的基本概念、安装和配置文件的说明。在本文将深入探讨 CoreDNS 的插件 (Plugins),这是 CoreDNS 强大功能的核心所在。通过理解插件机制和核心插件的工作原理,我们将为后续开发自定义插件和构建 DNS 平台奠定坚实基础。
插件系统设计理念
通常情况下,CoreDNS Plugins在设计上围绕下面的原则进行的
- 单一职责:每个插件只负责自己负责的功能
- 链式处理:插件按配置顺序执行链处理请求
- 可插拔性:插件可以灵活组合和替换
- 扩展性:支持用户自定义插件开发插件来扩展功能
基于这些原则,使得 CoreDNS 非常强大,非常易于扩展性(对比与最流行的两款开源 DNS 产品来说,Bind, PowerDNS)。
CoreDNS与主流DNS服务产品的对比
下表是调研了三款最流行的 DNS 开源产品来对最符合本项目的后端作为对比,CoreDNS的灵活性相对比较适宜
特性 | CoreDNS | BIND9 | PowerDNS |
---|---|---|---|
类型 | 权威/递归 | 权威/递归 | 权威/递归 |
AXFR/IXFR 支持 | 支持, trasfer 插件 | 支持 | 支持 |
view | 支持(geo, view插件) | 原生支持(view 指令) | 支持(仅仅LMDB后端) |
数据库支持 | 支持(通过自定义插件 mysql, redis) | 有限 DLZ模块 (Dynamically Loadable Zones) [1] | 原生有限支持 [2] |
DNSSEC | 支持(NSEC) | 全面支持(NSEC/NSEC3) | 全面支持(NSEC/NSEC3) |
扩展性 | 极佳(插件架构) | 有限扩展,支持c语言库作为plugins | 良好 |
易用性 | 高(简单配置,现代化) | 中(配置复杂,需经验) | 高(Web 界面、API) |
社区与生态 | 活跃(CNCF 项目,Kubernetes 生态) | 非常活跃(ISC 维护) | 活跃(商业支持) |
与本项目需求契合度 | 极高(插件化支持View, AXFR/IXFR, GEO) | 高(原生支持VIEW, AXFR/IXFR) | 高(数据库支持强,API 同步简单) |
CoreDNS插件的类型
CoreDNS插件分为两种类型插件,“In-tree Plugins” [3] 和 “External Plugins” [4];“In-tree Plugins” 是 CoreDNS 官方在提供 coredns 二进制文件时就内置编译到程序内的插件,用户可以自己去配置使用这些插件;“External Plugins” 是包含 CoreDNS 官方与三方作者维护的插件,用户如果想使用的话,需要自行编译 coredns 版本使用。
核心插件说明
cache
cache 插件是性能优化的核心组件,通过缓存 DNS 查询结果显著提高响应速度。当 cache 插件在启用后,所有的记录都会被缓存 3600s(除了 transfer 和 metadata 外); cache插件常被用于的场景是当从 backend (上游dns,数据库后端) 中拿取数据代价高时可以提高查询效率。
配置如下
|
|
- TTL 为秒,如果未指定,则使用最大 TTL,对于 NOERROR 的相应为 3600,拒绝存在 (denial of existence) 则为 1800.
- ZONE 为要缓存的域名 (ZONE),如果为空,则使用 “配置块” 的zone
如果需要更多控制可以参考下面配置
|
|
上面配置说明了,每一个 cache 部分的详细配置,缓存中的每个元素都根据其TTL缓存,在默认情况下,一个缓存被分为 256 和分块 (shares),每个分块可防止 39 个条目。每个缓存的总大小为 9984 个条目 (TTL最大情况下)。
上面的 “{}” 配置是针对每种类型相应进行缓存的说明:
- success: 覆盖缓存成功响应的设置。CAPACITY 指示在开始驱逐(随机)之前我们缓存的数据包的最大数量。TTL 覆盖缓存的最大 TTL。MINTTL 覆盖缓存的最小 TTL(默认 5),可以用来限制对后端的查询。
- CAPACITY:缓存的最大数据包数,超过后随机逐出(eviction)。
- TTL:覆盖缓存的最大 TTL,控制成功响应的最长缓存时间。
- MINTTL:覆盖缓存的最小 TTL(默认 5 秒),用于限制对后端的查询频率。
- denial: 覆盖缓存拒绝存在 (NXDOMAIN 或 NODATA)响应的设置。CAPACITY 指示在开始驱逐(LRU)之前我们缓存的数据包的最大数量。TTL 覆盖缓存的最大 TTL。MINTTL 覆盖缓存的最小 TTL(默认 5),可以用来限制对后端的查询。第三个类别(
error
),不被缓存。- CAPACITY:缓存的最大数据包数,超过后使用 LRU(Least Recently Used) 逐出策略。
- TTL:覆盖缓存的最大 TTL。
- MINTTL:覆盖缓存的最小 TTL(默认 5 秒),用于减少后端查询。
- 错误响应(error)不被缓存。
- prefetch: 当热门项目即将从缓存中清除时将预取该项目。
- Item 在 DURATION(默认 1 分钟)内收到 AMOUNT 次查询,且无超过 DURATION 的查询间隔。
- 预取在 TTL 低于 PERCENTAGE(默认 10%,范围 10%-90%,需带 % 符号)或 TTL 剩余 1 秒时触发。
- PERCENTAGE:作为整数处理,例如 “10%” 被视为 10。
- serve_stale: 当启用 serve_stale 时,缓存会向客户端返回已过期但未超过 DURATION(默认 1 小时)的条目。
- 默认情况下,发送过期条目后,缓存插件会尝试刷新条目。
- 响应的 TTL 设为 0。
- REFRESH_MODE (immediate|verify)
- immediate(默认):立即返回过期条目,再检查源是否可用。
- verify:先验证条目是否在源不可用,再返回过期条目(可能增加延迟,但避免返回过时数据)。
- servfail: 缓存 SERVFAIL 响应的时间。
- DURATION 设置为 0 禁用 SERVFAIL 缓存。
- 默认缓存 5 秒,最大不超过 5 分钟。
- disable: 禁用指定 ZONES 的成功 (success) 或拒绝存在 (denial) 的缓存。如果未指定 ZONES,则对所有 ZONES禁用指定的缓存类型。
- keepttl: 从缓存返回响应时不减少 TTL(即返回原始 TTL,而不是剩余 TTL)。
更多配置可以参考官方文档 [5]
详细配置示例
|
|
forward
forward 插件实现 DNS 查询转发功能,是 CoreDNS 与上游 DNS 服务器交互的核心。
基本配置语法
|
|
- FROM 是用于匹配需要转发的请求的基础域。使用展开为多个反向区域的 CIDR 表示法的域不受完全支持;仅使用第一个展开的区域。
- TO… 是转发到的目标端点。TO 语法允许你指定协议、
tls://9.9.9.9
或dns://
(或不指定协议)以获取纯 DNS。上游数量限制为 15 个。
配置示例
forward 中转发策略 (Policy) 还支持多种类型的负载均衡策略
配置示例
|
|
将 “example.org.” 所有请求代理到不同端口上运行的名称服务器
|
|
转发除 example.org
域之外的请求
|
|
forward 插件支持 DNS over TLS (DoT):
|
|
更多配置说明可以参考官网说明 [6]
kubernetes
kubernetes plugin 是 CoreDNS 在云原生环境中的核心优势,提供与 Kubernetes 集群的深度集成,该插件实现了 “基于 DNS 的 Kubernetes 服务发现规范 [7]
配置语法如下:
|
|
kubernetes 插件在配置时,如果仅指定插件 (kubernetes),那该插件使用服务器块(server block)中定义的 ZONE作为默认的权威 ZONE。例如下面所示
|
|
kubernetes 插件会处理这个 “ZONE” 下面的所有 DNS 查询。在这种场景下不会为 “Service” 提供 PTR记录 (Reverse DNS Lookups) 或 “Pod” 的 A 记录。这意味着,在默认配置下,仅仅提供 Service 的 “DNS 解析”。
如果为插件指定了 “ZONE”,kubernetes 会成为这些指定 “ZONE” 的权威DNS。如下面配置所示,
|
|
kubernetes 插件的配置如下
|
|
示例配置
|
|
这是 coredns 官方提供的 coredns 配置文件 [8],启动存在几个变量,通过查看脚本可以得到他的具体信息。
- UPSTREAMNAMESERVER 是从本机
/etc/resovle.conf
中读取的 - CLUSTER_DOMAIN 默认为 cluster.local
- REVERSE_CIDRS 设置一些反向DNS的域,通常我们一个集群使用的就是 CLUSTER_DOMAIN
|
|
总结:
kubernetes 插件提供多种服务发现模式:
- 服务发现:
service.namespace.svc.cluster.local
- Pod 发现:
pod-ip.namespace.pod.cluster.local
- 端点发现:
endpoint.service.namespace.svc.cluster.local
- K8S中 域名负载均衡模式使用的是 loadbalance 插件实现的
File
该示例采自官网的实例,通过使用内置的 file 插件实现一个 Authoritative Server,使用了 example.org.
作为示例 zone ,他的数据将被存储到文件内。
file 插件的域名为
|
|
DBFILE 部分为 CoreDNS 读取和解析的数据库文件
ZONES 为指定授权 Zone,如果为空,则继承 Server 块的 Zone
他的参数如下所示:
|
|
reload 表示 SOA 版本更改时执行 ZONE 重新加载的间隔。默认值 1 分钟。 0
表示不扫描更改并重新加载。
例如上面配置的扩展,example.org 的数据库由 file 模块提供,transfer 则是提供了
|
|
那么 example.org.db 数据库文件内应该配置的信息如下
|
|
|
|
另外在 bind9 中也有对应的配置
|
|
Auto
CoreDNS 的 auto 插件用于从磁盘上的 RFC 1035 格式的主文件(zone file)中自动加载和提供 DNS 区域数据,特别适合传统 DNS 服务器的场景。也可以将 auto 插件视作是 file 插件的扩展,支持所有 file 插件的指令(directive),但增加了自动加载和动态重新加载的功能。
|
|
ZONES:CoreDNS 会对这些区域的查询返回权威响应。
directory DIR [REGEXP ORIGIN_TEMPLATE] 指定 CoreDNS 从哪个 directory 加载 RFC 1035 格式的区域文件。
- REGEXP 用于匹配文件名,文件名匹配的会将他作为提取来源。
- ORIGIN_TEMPLATE 将用作来源模板,例如
{1}
是第一个匹配项,{2}
是第二个。和正则用法类似。
reload DURATION 指定 CoreDNS 扫描 directory 指定的频率,以检测区域文件的添加、删除或修改。
- 如果 ZONE 文件的 SOA 记录中的序列号 (serial number) 发生变化,CoreDNS 会自动重新加载该 ZONE 的数据。
- 默认值 1m
示例说明
- 默认的 REGEXP 为 db.(.*),默认的 ORIGIN_TEMPLATE 为 {1}
- 例如,路径为 db.example.com 时,REGEXP db.(.*) 匹配,ORIGIN_TEMPLATE “(.*)” 提取出 example.com,通过 {1} 转换为 ZONE 名称 example.com。
- CoreDNS 将 db.example.com 识别为区域 example.com 的区域文件。
|
|
上面示例提到了,这里会对文件例如,example.org 和 example.com 文件拥有权威响应,每 30 秒检查目录,重新加载发生变化的区域文件。
这里的目录文件必须为
|
|
再一个示例:从目录 /etc/coredns/zones/org 加载 org 域,并将文件名视为 www.db.example.org
,其中 example.org 为来源。每 45 秒刷新文件一次。
|
|
根据这个示例我们来测试 auto 插件
准备 example.org 文件
|
|
准备 example.top 文件
|
|
coredns 配置文件为
|
|
他的查询结果如下
|
|
总结
在本章节中,通过 forward, kubernetes, auto, file 展开了核心插件的功能特性。插件是 CoreDNS 强大功能的基础,通过合理配置和组合不同插件,可以构建满足各种需求的 DNS 服务。
在通过这些插件,我们可以大致了解出,在定义 DNS 系统时,这些插件的实现就是作为我们系统定义开发的一个思路,auto 可以让我们自行定义并发现域名配置。以及 kubernetes DNS 部分也有了进一步的了解
在下一篇文章中,开始从 CoreDNS 插件的源码进行分析学习,学习他的定义范式,以及实际开发自定义 CoreDNS 插件,通过实战案例掌握插件开发的完整流程,为构建高性能 DNS 域名平台做好准备。
Reference
[1] Bind DLZ
[3] in-tree plugins
[4] External Plugins
[5] cache plugin
[6] forward plugin
[7] 基于 DNS 的 Kubernetes 服务发现规范
[8] coredns.yaml.sed