CoreDNS 概述

什么是CoreDNS

CoreDNS 是一个由 Go 编写的灵活、可扩展的 DNS 服务器。他非常灵活,几乎全部功能都由 plugin 来实现,CoreDNS 官网也有说 “CoreDNS is powered by plugins.” 。Plugins 能够作为 “独立” 或和 CoreDNS “共同” 来执行 “DNS Function” 在 CoreDNS 中被设计为是一个由 “软件实现的 CoreDNS Plugin API”,例如 Kubernetes Provider 可以提供在 k8s 集群里的服务发现。再例如 file 可以提供作为一个 DB 来使用。

CoreDNS 的设计与 与 Caddy 一样也是通过 “插件” 进行扩展,并原生支持 Prometheus 也是 CoreDNS 的一大优势,这意味着我们可以将其连接到现有的 Prometheus 基础架构中进行监控、警报和仪表板管理。

CoreDNS 核心架构

  • Server:负责监听 DNS 查询请求
  • Plugins Chain:按照配置顺序串联起来的插件序列
  • Handler:每个插件实现的请求处理器
  • Middleware:在请求处理过程中的中间件

DNS 请求在 CoreDNS 中的处理流程如下:

  1. Server 接收 DNS 查询请求
  2. 请求按顺序通过插件链
  3. 每个插件决定是处理请求还是传递给下一个
  4. 如果某个插件成功处理,生成响应返回
  5. 如果整个插件链都无法处理,返回 SERVFAIL

安装 CoreDNS

由于 CoreDNS 是基于 Go语言开发的,官方提供了预编译包,再不进行插件编写的情况下可以自行部署,也可以使用官方的 Docker 镜像运行。本文基于整理文档时最新版 CoreDNS (v1.12.1) 进行演示。

coredns 的参数很少,可以使用 –help 来查看

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ ./coredns --help
Usage of ./coredns:
  -conf string
        Corefile to load (default "Corefile")
  -dns.port string
        Default port (default "53")
  -p string
        Default port (default "53")
  -pidfile string
        Path to write pid file
  -plugins
        List installed plugins
  -quiet
        Quiet mode (no initialization output)
  -version
        Show version

可以通过 -plugins 参数来查看内置的所有 “plugins” 的列表

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
$ ./coredns -plugins
acl
any
auto
autopath
azure
bind
bufsize
cache
cancel
chaos
clouddns
debug
dns64
dnssec
dnstap
erratic
errors
etcd
file
forward
geoip
grpc
header
health
hosts
k8s_external
kubernetes
loadbalance
local
log
loop
metadata
minimal
multisocket
nsid
pprof
prometheus
ready
reload
rewrite
root
route53
secondary
sign
template
timeouts
tls
trace
transfer
tsig
view
whoami
on

这里和官网实例一样使用 1053 端口来展示 coredns 测试示例

bash
1
./coredns -dns.port=1053
note
在不指定配置文件启动时,它返回的是客户端的IP和端口
bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ dig @10.0.0.1 -p 1053 a whoami.example.org

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> @10.0.0.1 -p 1053 a whoami.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61873
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;whoami.example.org.		IN	A

;; ADDITIONAL SECTION:
whoami.example.org.	0	IN	A	10.0.0.3
_udp.whoami.example.org. 0	IN	SRV	0 0 40279 .

;; Query time: 3 msec
;; SERVER: 10.0.0.1#1053(10.0.0.1)
;; WHEN: Sat May 24 00:17:50 HKT 2025
;; MSG SIZE  rcvd: 123

coredns配置原理

CoreDNS 的配置文件的配置内容要求必须是编译在 coredns 中的插件才可以使用,添加和删除插件都很容易,但是需要重新编译 coredns。

在使用配置文件来启动 coredns 时,首先可以通过 -conf 参数来指定配置文件。但当未指定时,会从当前目录下寻找 “Corefile” 作为配置文件。

配置文件内容由一个或多个 Server 块 (Blocks) 组成,每一个 Server 块包含了一个或多个插件。插件也可以通过插件的 “指令” 来对插件做更多配置。

Corefile 中插件配置的顺序并不决定插件链的执行顺序。插件执行顺序由 plugin.cfg 中的顺序决定。

配置文件中以 “#” 作为注释

note
CoreDNS 也支持在配置文件任何地方使用环境变量,Linux 中为 “{$ENV_VAR}”;Windows中为 “{%ENV_VAR%}”

coredns 配置说明

Server Block

  1. server 块的开头可以对多个域名表示权威性(authoritative 在 DNS 系统属于中通常指,可以可以正确的解析 domain 到 IP,通过上下文来理解就是对一个 zone 拥有的权威性;也可以理解为对一个域名的最终的权威性)
  2. 多个 zone 通过 “空格” 进行分开。
  3. Server 块是以 “{” (opening brace) 开始,以 “}” (closing brace) 结束。其中 “.” 表示根 zone,可以处理所有查询。
quote
This type of DNS server holds a copy of the regional phone book that matches IP addresses with domain names. These are called authoritative DNS servers [4]
text
1
2
3
. {
    # Plugins defined here.
}

下面是一个实例

text
1
2
3
4
5
example.com example.org example.net {
    forward . 8.8.8.8 8.8.4.4
    cache
    log
}

Server 部分也可以指定监听端口,默认为 “53” (标准DNS服务的端口),使用 “:” 来划分 zone 和它的监听端口,例如 1053

text
1
2
3
.:1053 {
    # Plugins defined here.
}
warning
需要注意的是,如果在这里指定的端口,那么使用选项 -dns.port 指定了参数没法覆盖配置文件中指定的端口。

使用同个 zone 指定已经分配的 Server 块,或者他们运行在同一个端口上,这个配置文件在启动时会抛出错误。例如下面配置所示。

text
1
2
3
4
5
6
7
.:1054 {

}

.:1054 {

}

可以通过 bind 插件来让他绑定到不同的网卡上,可以实现使用不同网络接口或者IP地址的情况下使用相同的端口来提供服务。

text
1
2
3
4
5
6
7
8
9
.:1054 {
    bind lo
    whoami
}

.:1054 {
    bind eth0
    whoami
}

配置协议

截至目前 CoreDNS (v1.12.1) 支持四种不同类型的协议

  1. DNS:dns://,也是默认的协议,如果 scheme 未指定,则默认为 dns 协议
  2. DNS over TLS (DoT): tls://
  3. DNS over HTTP/2 (DoH): https://
  4. DNS over gRPC: grpc://

插件配置

在一个 Server 块中,可以通过 “插件名称” 来使用对应的插件,例如

text
1
2
3
. {
    chaos
}

对于每个插件的配置,和 Server 块相同,以 “{” (opening brace) 开始,以 “}” (closing brace) 结束,来表示这个插件的配置项,如下所示

text
1
2
3
4
5
. {
    plugin {
       # Plugin Block
    }
}

下面是四个 zone 在两个不同的端口上提供服务

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
coredns.io:5300 {
    file db.coredns.io
}

example.io:53 {
    log
    errors
    file db.example.io
}

example.net:53 {
    file db.example.net
}

.:53 {
    kubernetes
    forward . 8.8.8.8
    log
    errors
    cache
}

配置示例:来自 file plugin 的 Authoritative Serving

该示例采自官网的实例,通过使用内置的 file 插件实现一个 Authoritative Server,使用了 example.org. 作为示例 zone ,他的数据将被存储到文件内。

file 插件的域名为

text
1
file DBFILE [ZONES...]

DBFILE 部分为 CoreDNS 读取和解析的数据库文件

ZONES 为指定授权 Zone,如果为空,则继承 Server 块的 Zone

他的参数如下所示:

text
1
2
3
file DBFILE [ZONES... ] {
    reload DURATION
}

reload 表示 SOA 版本更改时执行 ZONE 重新加载的间隔。默认值 1 分钟。 0表示不扫描更改并重新加载。

例如上面配置的扩展,example.org 的数据库由 file 模块提供,transfer 则是提供了

text
1
2
3
4
5
6
example.org {
    file example.org.db
    transfer {
        to * 10.240.1.1
    }
}

那么 example.org.db 数据库文件内应该配置的信息如下

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# $ORIGIN example.org. 定义了“根” zone,这里是 example.com.
# “.” 表示 FQDN
# 这里表示下面的记录都是围绕 “example.com.”
$ORIGIN example.org.

# “@”表示当前zone的根域名(因为 $ORIGIN 是 example.org.)。
# “3600” 为TTL,这条记录缓存时间为1小时(单位秒)
# “IN”表示Internet记录
# “SOA” start of authority,权威起始记录,
# sns.dns.icann.org.主名字服务器的FQDN
# noc.dns.icann.org. zone管理员邮箱,在dns配置中,用“.”替换“@”
# 2017042745 序列号(Serial),通常用于DNS同步
## AXFR (full zone transfer,官方称为 Authoritative Transfer) 理解全量同步
## IXFR (Incremental transfer),可以理解为增量同步
# “7200”表示刷新时间,从服务器每2小时向主服务器检查是否更新(单位秒)
# “3600”表示重试时间,从到主无法连接时,会在1小时后重试(单位秒)。
# “1209600” 表示过期时间“从在两周内无法从主获取更新,则数据失效。
# “3600” 表示“Minimum TTL”,定义改zone中默认的 TTL
@	3600 IN	SOA sns.dns.icann.org. noc.dns.icann.org. 2017042745 7200 3600 1209600 3600

# “NS” Name Server,查询 example.org 的信息,可以去找 a.iana-servers.net 这个DNS服务器
	3600 IN NS a.iana-servers.net.
	3600 IN NS b.iana-servers.net.

# A记录为IPV4
# AAAA记录为IPV6
www     IN A     127.0.0.1
        IN AAAA  ::1
note
下面的内容为不加注释的配置文件,也是 file plugin 中配置的数据库 “example.org.db”
text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ORIGIN example.org.
@	3600 IN	SOA sns.dns.icann.org. noc.dns.icann.org. (
				2017042745 ; serial
				7200       ; refresh (2 hours)
				3600       ; retry (1 hour)
				1209600    ; expire (2 weeks)
				3600       ; minimum (1 hour)
				)

	3600 IN NS a.iana-servers.net.
	3600 IN NS b.iana-servers.net.

www     IN A     127.0.0.1
        IN AAAA  ::1

另外在 bind9 中也有对应的配置

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
example.com. 43200 IN SOA ns1.example.com. other.example.com. (
 2011090302 ;Serial Number
 86400 ;refresh
 7200 ;retry
 1814400 ;expire
 86400 ;minimum
 )

@   SOA ns1 (   ; ns1.basiczone.com is the primary server for basiczone.com
      postmaster  ; contact email for basiczone.com is postmaster@basiczone.com
      2004041700  ; Serial ID in reverse date format
      21600   ; Refresh interval for slave servers
      1800    ; Retry interval for slave servers
      604800    ; Expire limit for cached info on slave servers
      900 )   ; Minimum Cache TTL in zone records

配置示例:transfer 和AXFR配置

transfer插件可以响应 AXFR (full zone transfer) 请求和 IXFR (incremental zone transfer) 请求,当 server 端无法通过 IXFR 更新时,会回退为 AXFR (AXFR fallback),就是如果 IXFR 客户端没法通过 IXFR 更新数据,那么服务端会返回 “整个域” 给 IXFR 客户端 [7]

配置语法

text
1
2
3
transfer [ZONE...] {
  to ADDRESS...
}

ZONE 部分表示相应 zone transfer 请求的域,如果左边为空,这些 zone 将继承于 “server 块”

to ADDRESS… 部分表示允许 trasfer 的地址,使用 “*” 表示允许 transfer 到所有的 “ADDRESS”,当 zone 改变时通知将会发送到所有 “ADDRESS” ;“ADDRESS” 可以是 IP,也可以是 IP:PORT,也可以指定多次。

例如,下面配置表示 transfer 到一个 secondary DNS server (10.240.1.1),这里可以使用一个或多个 transfer 指令,也可以使用 CIRD,在这个Zone发生任何改变时,CoreDNS将通知这些 “secondary DNS server”

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
transfer {
    to 10.240.1.1
}

foo.example {
    file db.foo.example {
        transfer to 10.0.1.53
        transfer to *
    }
}

总结

本文从零带入了 CoreDNS 的安装配置和主要功能特性。CoreDNS 作为一个现代化的 DNS 服务器,以其模块化设计、插件扩展性和云原生特性,为构建高性能 DNS 平台提供了坚实基础。

在后续文章中,将进一步探讨 CoreDNS 的插件部分,并深入研究如何开发自定义插件来扩展 CoreDNS 功能,最终实现一个完整的 DNS 域名管理平台。

Reference

[1] what-is-coredns

[2] Installation

[3] configuration

[4] What is the difference between authoritative and recursive DNS nameservers?

[5] RR TYPE IANA Considerations

[6] bind: what is the zonefile SOA RR grammar?

[7] An IXFR Fallback to AXFR Case draft-song-dnsop-ixfr-fallback-01