前述
CoreDNS 的插件非常丰富,在文章 《Rocky Linux 9 从入门到精通007 — DNS管理(CoreDNS 集群部署篇)》中对此有详细介绍,本文主要是对一些常用插件配置进行讲解,后续也会陆续补充其他插件的使用技巧。
Hosts 解析配置
hosts
插件可以实现 Hosts 解析,类似于本地主机上的 Hosts 文件绑定。在 Linux 系统中,可以通过修改 /etc/hosts
文件实现。在 Windows 系统中,则通过修改 C:\Windows\System32\drivers\etc\hosts
文件实现。默认情况下,hosts
插件默认每隔 5
秒钟重新加载一次 hosts 文件。
[root@coredns-001 ~]# cat > /etc/coredns/Corefile << \EOF
.:53 {
log # 启用日志记录
loop # 防止 DNS 查询在多个 DNS 服务器之间循环,导致无限查询循环。如果检测到循环,CoreDNS 会中止查询。
errors # 启用错误日志记录
reload 30s # 通过 reload 插件实现热加载功能,确保在不重启 CoreDNS 服务的情况下,动态应用新的配置,每隔 30 秒重载一次 Corefile 配置文件。
cache 300s # 配置 DNS 查询的缓存时间为 300 秒,减少重复查询,提高响应速度和性能。
ready 0.0.0.0:8181 # 在指定地址和端口上提供 readiness(就绪)探针。
health 0.0.0.0:8080 # 在指定地址和端口上提供健康检查(health check)。
prometheus 0.0.0.0:9253 # 在指定地址和端口上启用 Prometheus metrics。
loadbalance round_robin # 使用轮询模式进行负载均衡。
hosts /etc/coredns/hosts { # hosts 解析插件
fallthrough # 当在 hosts 解析中没有获取到解析信息,将 DNS 查询传给其它插件。
}
forward . 223.6.6.6 114.114.114.119 # DNS 转发
}
EOF
# hosts 文件配置
[root@coredns-001 ~]# cat > /etc/coredns/hosts << \EOF
192.168.2.1 a.rockylinux.cn
192.168.2.2 b.rockylinux.cn
EOF
Corefile
)中被依次传递给插件来处理。对于 hosts
和 forward
插件的顺序,通常 hosts
插件应放在 forward
插件之前。这是因为 hosts
插件根据静态文件内容处理 DNS 请求,而 forward
插件则将请求转发到上游 DNS 服务器。如果 hosts
插件在 forward
插件之后,任何匹配 hosts
文件中的请求将不会有机会被 hosts
插件处理,因为这些请求已经被 forward
插件转发出去了。客户端测试验证,因为 reload
插件会每隔 30
秒加载一次 Corefie
文件,所以不需要重启 coredns
服务,等待 30
秒即可测试验证。
# host 解析验证
[root@client-001 ~]# dig @192.168.1.1 a.rockylinux.cn
; <<>> DiG 9.10.6 <<>> @192.168.1.1 a.rockylinux.cn
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- \opcode: QUERY, status: NOERROR, id: 59996
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.rockylinux.cn. IN A
;; ANSWER SECTION:
a.rockylinux.cn. 3600 IN A 192.168.2.1 # 获取解析信息
;; Query time: 1 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Tue Jul 09 17:10:25 CST 2024
;; MSG SIZE rcvd: 71
# 怎么知道是不是从 hosts 解析直接返回的了?可以使用 tcpdump 抓包验证。
[root@client-001 ~]# tcpdump -n -i any port 53
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
18:41:05.345118 enp6s0f0 In IP 192.168.3.1.51685 > 192.168.1.1.domain: 5458+ [1au] A? a.rockylinux.cn. (42) # 客户端请求 A 记录解析
18:41:05.345390 enp6s0f0 Out IP 192.168.1.1.domain > 192.168.3.1.51685: 5458*- 1/0/1 A 192.168.2.1 (71) # 服务器直接返回对应解析记录,没有去到任何上级 DNS 服务器进行解析,说明通过 hosts 解析。
Forward 域名转发器配置
Forward 域名转发器插件,主要用于将指定域名解析转发至指定 DNS 服务器进行解析。它支持 UDP、TCP 和 DNS-over-TLS,并自带健康检查。健康检查循环运行,每 0.5
秒进行一次检查,只要上游报告不健康,就会持续进行。一旦上游恢复健康,将停止健康检查(直到下一次错误)。健康检查使用递归 DNS 查询(. IN NS
)来获取上游健康状况。任何非网络错误的响应(REFUSED
、NOTIMPL
、 SERVFAIL
等)都被视为上游健康。健康检查使用与 TO
中指定的相同协议。如果 max_fails
设置为 0
,则不进行检查,上游将始终被视为健康。当所有上游都关闭时,它会认为健康检查作为一种机制已经失败,并会尝试连接到一个随机的上游(也许可用,也许不可用)。
[root@coredns-001 ~]# cat > /etc/coredns/Corefile << \EOF
.:53 {
log # 启用日志记录
loop # 防止 DNS 查询在多个 DNS 服务器之间循环,导致无限查询循环。如果检测到循环,CoreDNS 会中止查询。
errors # 启用错误日志记录
reload 30s # 通过 reload 插件实现热加载功能,确保在不重启 CoreDNS 服务的情况下,动态应用新的配置,每隔 30 秒重载一次 Corefile 配置文件。
cache 300s # 配置 DNS 查询的缓存时间为 300 秒,减少重复查询,提高响应速度和性能。
ready 0.0.0.0:8181 # 在指定地址和端口上提供 readiness(就绪)探针。
health 0.0.0.0:8080 # 在指定地址和端口上提供健康检查(health check)。
prometheus 0.0.0.0:9253 # 在指定地址和端口上启用 Prometheus metrics。
loadbalance round_robin # 使用轮询模式进行负载均衡。
hosts /etc/coredns/hosts { # hosts 解析插件
fallthrough # 当在 hosts 解析中没有获取到解析信息,将 DNS 查询传给其它插件。
}
forward . 223.6.6.6 114.114.114.119 # DNS 转发
}
# 域名转发器配置有两种写:多个域名指向同一个转发器或单个域名指向一个转发器
google.com:53 facebook.com:53 youtube.com:53 {
forward . 8.8.8.8 4.4.4.4
log
errors
}
cloudflare.com:53 {
forward . 1.1.1.1 1.0.0.1
log
errors
}
EOF
cloudflare.com:53
优化级高于 .:53
。在这个配置中,cloudflare.com:53
配置块具有更高的匹配优先级,因为它更具体,仅针对 cloudflare.com
及其子域名。而 .:53
配置块更泛,匹配所有域名。因此,对于解析 cloudflare.com
及其子域名(例如 www.cloudflare.com
)的请求,会先匹配到 cloudflare.com:53
配置块,并使用 1.1.1.1
和 1.0.0.1
作为上游 DNS 服务器。而对于其他所有域名的请求,会匹配到 .:53
配置块,使用 8.8.8.8
和 4.4.4.4
作为上游 DNS 服务器。客户端测试验证,因为 reload
插件会每隔 30
秒加载一次 Corefie
文件,所以不需要重启 coredns
服务,等待 30
秒即可测试验证。
[root@client-001 ~]# dig @192.168.1.1 www.youtube.com
; <<>> DiG 9.10.6 <<>> @192.168.1.1 www.youtube.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- \opcode: QUERY, status: NOERROR, id: 19199
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.youtube.com. IN A
;; ANSWER SECTION:
www.youtube.com. 300 IN CNAME youtube-ui.l.google.com.
youtube-ui.l.google.com. 300 IN A 172.217.160.110
youtube-ui.l.google.com. 300 IN A 172.217.163.46
youtube-ui.l.google.com. 300 IN A 142.251.43.14
youtube-ui.l.google.com. 300 IN A 142.251.42.238
;; Query time: 26 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Tue Jul 09 18:24:11 CST 2024
;; MSG SIZE rcvd: 252
# 同样通过抓包可以看到对应 DNS 解析请求,转发至 8.8.8.8 进行解析。
[root@client-001 ~]# tcpdump -n -i any port 53
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
18:24:11.484957 enp6s0f0 In IP 192.168.3.1.54716 > 192.168.1.1.domain: 19199+ [1au] A? www.youtube.com. (44)
18:24:11.485225 enp6s0f0 Out IP 192.168.1.1.64080 > 8.8.8.8.domain: 20107+ [1au] A? www.youtube.com. (44) # 在这里可以明确看到 DNS 服务器地址 8.8.8.8
18:24:11.510638 enp6s0f0 In IP 8.8.8.8.domain > 192.168.1.1.64080: 20107 5/0/1 CNAME youtube-ui.l.google.com., A 172.217.160.110, A 172.217.163.46, A 142.251.43.14, A 142.251.42.238 (142)
18:24:11.510830 enp6s0f0 Out IP 192.168.1.1.domain > 192.168.3.1.54716: 19199 5/0/1 CNAME youtube-ui.l.google.com., A 172.217.160.110, A 172.217.163.46, A 142.251.43.14, A 142.251.42.238 (252)
Header 配置
Header 插件,主要用于标记处理 DNS 查询和响应所需要的状态。修改对于客户端和后续插件而言是透明的。当前支持的标记包括:
aa
– 权威(答案)ra
– 递归可用rd
– 需要递归
那么在哪些场景需要用到这个插件了?
在使用 nslookup
测试 DNS 解析过程中,发现当使用 hosts
插件进行 Hosts 解析时,nslookup
会提示主 DNS 服务器无法进行递归查询,尝试下一个服务器(如下所示)。实际上当您指定 DNS 解析服务器时,是不会存在此问题的。
[root@client-001 ~]# nslookup a.rockylinux.cn
;; Got recursion not available from 192.168.1.1, trying next server # 报错信息
Server: 192.168.1.2
Address: 192.168.1.2#53
Name: a.rockylinux.cn
Address: 192.168.2.1
指定主 DNS 服务器 IP 进行解析,一切正常。
[root@client-001 ~]# nslookup a.rockylinux.cn 192.168.1.1
Server: 192.168.1.1
Address: 192.168.1.1#53
Name: a.rockylinux.cn
Address: 192.168.2.1
另外通过 dig
进行解析不会存在此问题。
[root@client-001 ~]# dig a.rockylinux.cn
; <<>> DiG 9.10.6 <<>> a.rockylinux.cn
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- \opcode: QUERY, status: NOERROR, id: 63643
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.rockylinux.cn. IN A
;; ANSWER SECTION:
a.rockylinux.cn. 3600 IN A 192.168.2.1
;; Query time: 0 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Wed Aug 14 17:56:19 CST 2024
;; MSG SIZE rcvd: 95
查看 CoreDNS 解析日志会发现,两台服务器都同时响应了对应的 DNS 请求(CoreDNS 集群对于此请求放大了 N 倍,N 值的大小取决于 CoreDNS 集群的大小)。
[root@coredns-001 ~]# journalctl -f -u coredns | grep a.rockylinux.cn
Aug 14 17:47:50 coredns-001 coredns[79104]: [INFO] 192.168.3.1:56640 - 18234 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd 84 0.00007369s
Aug 14 17:47:51 coredns-001 coredns[79104]: [INFO] 192.168.3.1:50982 - 51134 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd 84 0.0000588s
[root@coredns-002 ~]# journalctl -f -u coredns | grep a.rockylinux.cn
Aug 14 17:47:50 coredns-002 coredns[125676]: [INFO] 192.168.3.1:60336 - 18234 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd 84 0.000122s
Aug 14 17:47:51 coredns-002 coredns[125676]: [INFO] 192.168.3.1:54437 - 51134 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd 84 0.000117659s
实际上这是 nslookup
的问题,man nslookup
查看帮忙时,会看到如下信息:
[root@client-001 ~]# man nslookup
[no]recurse
Tell the name server to query other servers if it does not have the information.
(Default = recurse; abbreviation = [no]rec)
也就是 DNS 服务器没有这条解析记录时,就会查询下一台 DNS 服务器,本质在于 nslookup
解析时,不认为 hosts
插件查询是支持递归查询的结果。这时候,如果将客户端的 DNS 服务器设置成单个主 DNS 服务器地址: 192.168.1.1
,再去使用 nslookup
解析就不会存在此问题了。
至此,Header
插件就可以发挥作用了,实际上只需要使用 CoreDNS 的 Header
插件设置响应头值为 ra
即递归可用即可。
同时在 coredns-001 及 coredns-002 添加以下配置:
.:53 {
log # 启用日志记录
loop # 防止 DNS 查询在多个 DNS 服务器之间循环,导致无限查询循环。如果检测到循环,CoreDNS 会中止查询。
errors # 启用错误日志记录
reload 30s # 通过 reload 插件实现热加载功能,确保在不重启 CoreDNS 服务的情况下,动态应用新的配置,每隔 30 秒重载一次 Corefile 配置文件。
cache 300s # 配置 DNS 查询的缓存时间为 300 秒,减少重复查询,提高响应速度和性能。
ready 0.0.0.0:8181 # 在指定地址和端口上提供 readiness(就绪)探针。
health 0.0.0.0:8080 # 在指定地址和端口上提供健康检查(health check)。
prometheus 0.0.0.0:9253 # 在指定地址和端口上启用 Prometheus metrics。
loadbalance round_robin # 使用轮询模式进行负载均衡。
hosts /etc/coredns/hosts { # hosts 解析插件
fallthrough # 当在 hosts 解析中没有获取到解析信息,将 DNS 查询传给其它插件。
}
header {
response set ra # 设置 Header 头 response 为 ra 即可
}
forward . 223.6.6.6 114.114.114.119 # DNS 转发
}
这时候客户端再通过 nslookup
解析正常。
[root@client-001 ~]# nslookup a.rockylinux.cn
Server: 192.168.1.1
Address: 192.168.1.1#53
Name: a.rockylinux.cn
Address: 192.168.2.1
从服务器端日志来看,解析时响应结果会由 qr,aa,rd
变成 qr,aa,rd,ra
,也就是告诉客户端此结果为递归查询结果。此时,只会从主 DNS 服务器进行解析,不会再出现转到从 DNS 服务器解析的情况。
[root@coredns-001 ~]# journalctl -f -u coredns | grep a.rockylinux.cn
Aug 14 18:50:18 coredns-001 coredns[79104]: [INFO] 192.168.3.1:60322 - 65343 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd,ra 84 0.000129409s
Aug 14 18:50:31 coredns-001 coredns[79104]: [INFO] 192.168.3.1:58872 - 25669 "A IN a.rockylinux.cn. udp 43 false 512" NOERROR qr,aa,rd,ra 84 0.000101711s
显然在使用 hosts
插件时,header
插件的使用,可以有效降低 CoreDNS 集群的资源消耗。当然 header
插件还有很多其它使用场景。