概述
DNS 是网络中非常重要的一个服务和话题,在平时工作中使用的也非常多,之前我也写过一篇介绍 DNS 以及系统设置的文章:DNS 以及 Linux 下的相关配置文件,但是今天我要聊一聊的是自己部署一个 DNS 服务器。
在之前我也写过自建 DNS 服务器的教程:Mac 搭建本地 DNS 服务器,但是这篇文章中用的是 DNSMasq,其实我之前的工作中也用的是这个,因为之前的产品是偏 IaaS,所以选型是相对比较偏传统的。但是,最近因为产品更倾向于云原生,所以换成了 CoreDNS,于是这里就简单做下总结。
CoreDNS 概念
CoreDNS 的实现有别于其他的 DNS 服务器(我从文档里面抄的,实际上其他服务器的实现有何特别之处我没有去了解过😂),CoreDNS 的特点就是非常的灵活,它的灵活来自于插件系统,也就是说,CoreDNS 将大部分的功能够交给一个个插件来完成,然后通过配置来组合插件从而实现我们需要的功能。
在 CoreDNS 中,有两个关于插件的配置非常重要,分别是:
plugin.cfg
:这个是编译时使用的配置文件,用于决定需要使用 CoreDNS 的哪些插件;Corefile
:这个是运行时配置,用于决定 CoreDNS 如何响应 DNS 查询请求;
插件
插件是 CoreDNS 的核心概念,它实际上就是一个实现了特定接口的代码,每当有一个 DNS 查询进来时,被配置的插件都将被调用,并传递给它三个参数:
context.Context
dns.ResponseWriter
:用于写入响应数据;*dns.Msg
:DNS 请求的 Client 信息;
需要哪些插件是通过编译时的 plugin.cfg
来配置的,并且需要注意的是,这个配置文件里面的顺序很重要,因为这也是插件在实际运行中的顺序,所以在 Corefile 中也有插件的定义顺序,但是那个顺序是没意义的,真正地顺序是 plugin.cfg
中配置的,例如这是一个官方的配置:
[root@liqiang.io]# cat plugin.cfg
root:root
metadata:metadata
geoip:geoip
cancel:cancel
tls:tls
timeouts:timeouts
reload:reload
nsid:nsid
bufsize:bufsize
bind:bind
debug:debug
trace:trace
ready:ready
health:health
pprof:pprof
prometheus:metrics
errors:errors
log:log
dnstap:dnstap
local:local
dns64:dns64
acl:acl
any:any
chaos:chaos
loadbalance:loadbalance
tsig:tsig
cache:cache
rewrite:rewrite
header:header
dnssec:dnssec
autopath:autopath
minimal:minimal
template:template
transfer:transfer
hosts:hosts
route53:route53
azure:azure
clouddns:clouddns
k8s_external:k8s_external
kubernetes:kubernetes
file:file
auto:auto
secondary:secondary
etcd:etcd
loop:loop
forward:forward
grpc:grpc
erratic:erratic
whoami:whoami
on:github.com/coredns/caddy/onevent
sign:sign
view:view
配置
CoreDNS 在默认的情况下会在运行目录中寻找 Corefile 作为启动配置,但是你可以通过 -conf
指定启动配置。Corefile 配置也很简单,它由很多的 Server Blocks 组成(当然,你不指定或者只指定一个也是可以),每个 Server Block 的模式为:
<zones> {
# Plugins defined here.
}
可以看到,Server Block 包含两个部分,分别是 zone
和 plugins
:
zone
:监听的域名类型,协议和端口- 例如你想监听所有的域名,那么可以用一个
.
- 你只关注 google 这个域名,那么可以用
google.com
- 如果只关注 https 的 dns 查询(HoD):
https://google.com
- 例如你想监听所有的域名,那么可以用一个
plugin
:- 对于满足
zone
条件的域名,你希望用哪些插件来响应这个域名,下面可以加入插件的列表,但是,需要注意的是,你可以随便安排这个插件的列表,但是实际的执行顺序并不是按照你安排的顺序,而是在plugin.cfg
中的顺序;
- 对于满足
一个配置的示例:
[root@liqiang.io]# cat Corefile
dns://google.com:53 {
errors
forward . 8.8.8.8
}
# 兜底配置,前面没有满足的都会使用这个配置
dns://.:53 {
errors
forward . 223.5.5.5:53
}
实践
安装
CoreDNS 的安装支持多种方式,但是一般来说可以分为预编译程序和容器两种方式,一般来说我们都是在 K8S 环境下运行的,所以用容器的情况比较多,并且可能平时我们需要在本地运行来调试一下问题,所以这里给一个简单的使用 Docker 运行的示例:
[root@liqiang.io]# docker run -d --rm --name coredns \
--volume=/tmp/coredns:/root/ \
-p 53:53/udp \
coredns/coredns \
-conf /root/Corefile
这样,我们就跑起来一个 CoreDNS 实例了,因为 CoreDNS 是一个无状态的服务,所以,我们可以快速地进行横向扩展,而无需考虑其他额外的配置。
验证
当我们跑起来之后,可以通过 DNS 相关的命令指定 DNS 服务器进行验证,例如我这里用 dig:
[root@liqiang.io]# dig @127.0.0.1 google.com
; <<>> DiG xxxxxx <<>> @127.0.0.1 google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30520
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 754b24dbebe1a964 (echoed)
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 30 IN A 142.251.175.113
google.com. 30 IN A 142.251.175.102
google.com. 30 IN A 142.251.175.101
google.com. 30 IN A 142.251.175.138
google.com. 30 IN A 142.251.175.139
google.com. 30 IN A 142.251.175.100
;; Query time: 11 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Mon Jul 22 00:20:15 UTC 2024
;; MSG SIZE rcvd: 207