CoreDNS 是新晋的 CNCF 孵化项目,前几天已经从 CNCF 正式毕业,并正式成为 Kubernetes 的 DNS 服务器。CoreDNS 的目标是成为 cloud-native 环境下的 DNS 服务器和服务发现解决方案,即:
Our goal is to make CoreDNS the cloud-native DNS server and service discovery solution.
它有以下几个特性:
Corefile
形式的配置文件(也是基于 Caddy 框架开发)。kube-dns
,CoreDNS 编译出来就是一个单独的二进制可执行文件,内置了 cache,backend storage,health check 等功能,无需第三方组件来辅助实现其他功能,从而使得部署更方便,内存管理更为安全。其实从功能角度来看,CoreDNS 更像是一个通用 DNS 方案(类似于 BIND),然后通过插件模式来极大地扩展自身功能,从而可以适用于不同的场景(比如 Kubernetes)。正如官方博客所说:
CoreDNS is powered by plugins.
Corefile
是 CoreDNS 的配置文件(源于 Caddy 框架的配置文件 Caddyfile),它定义了:
server
以什么协议监听在哪个端口(可以同时定义多个 server 监听不同端口)zone
的权威(authoritative)DNS 解析常见地,一个典型的 Corefile 格式如下所示:
ZONE:[PORT] {
[PLUGIN] ...
}
PORT
是可选项,默认为 53;比如:
. {
chaos CoreDNS-001
}
上述配置文件表达的是:server 负责根域 .
的解析,其中 plugin 是 chaos
且没有参数。
一个最简单的配置文件可以为:
.{}
即 server 监听 53 端口并不使用插件。如果此时在定义其他 server,要保证监听端口不冲突;如果是在原来 server 增加 zone,则要保证 zone 之间不冲突,如:
. {}
.:54 {}
另一个 server 运行于 54 端口并负责根域 .
的解析。
又如:
example.org {
whoami
}
org {
whoami
}
同一个 server 但是负责不同 zone 的解析,有不同插件链。
跟其他 DNS 服务器类似,Corefile 也可以定义 Reverse Zone
(反向解析 IP 地址对应的域名):
0.0.10.in-addr.arpa {
whoami
}
或者简化版本:
10.0.0.0/24 {
whoami
}
可以通过 dig
进行反向查询:
$ dig -x 10.0.0.1
CoreDNS 除了支持 DNS 协议,也支持 TLS
和 gRPC
,即 DNS-over-TLS 和 DNS-over-gRPC 模式:
tls://example.org:1443 {
#...
}
当 CoreDNS 启动后,它将根据配置文件启动不同 server ,每台 server 都拥有自己的插件链。当有 DNS 请求时,它将依次经历如下 3 步逻辑:
fallthrough
来决定是否允许此项操作,例如 host 插件,当查询域名未位于 /etc/hosts,则调用下一个插件;metric
插件;如果 Corefile 为:
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
proxy . 8.8.8.8
log
health
errors
cache
}
从配置文件来看,我们定义了两个 server(尽管有 4 个区块),分别监听在 5300
和 53
端口。其逻辑图可如下所示:
image
每个进入到某个 server 的请求将按照 plugin.cfg
定义顺序执行其已经加载的插件。
从上图,我们需要注意以下几点:
.:53
配置了 health
插件,但是它并为在上面的逻辑图中出现,原因是:该插件并未参与请求相关的逻辑(即并没有在插件链上),只是修改了 server 配置。更一般地,我们可以将插件分为两种:health
,tls
等插件;既然 CoreDNS 如此优秀,我用它来抵御伟大的防火长城岂不美哉?研究了一圈,发现技术上还是可行的,唯一的一个缺点是不支持使用代理,不过你可以通过 proxychians-ng 或 proxifier 来强制使用代理。下面开始折腾。
CoreDNS 是 golang 写的,所以只需要下载对应操作系统的二进制文件,到处拷贝,就可以运行了。
下面统统以 MacOS 为例作讲解。
$ cd ~/Downloads
$ wget https://github.com/coredns/coredns/releases/download/v1.4.0/coredns_1.4.0_darwin_amd64.tgz
$ tar zxf coredns_1.4.0_darwin_amd64.tgz
$ mv ./coredns /usr/local/bin/
这里补充一句,CoreDNS 的二进制版本已经安装了所有的插件(plugins),不需要你自己编译。推荐下载二进制版本。
要深入了解 CoreDNS,请查看其文档,及 plugins 的介绍。下面是我的配置文件:
$ cat <<EOF > /usr/local/etc/Corefile
. {
hosts {
fallthrough
}
forward . tls://8.8.8.8 tls://8.8.4.4 {
tls_servername dns.google
force_tcp
max_fails 3
expire 10s
health_check 5s
policy sequential
except www.baidu.com
}
proxy . 117.50.11.11 117.50.22.22 {
policy round_robin
}
cache 120
reload 6s
log . "{local}:{port} - {>id} '{type} {class} {name} {proto} {size} {>do} {>bufsize}' {rcode} {>rflags} {rsize} {duration}"
errors
}
EOF
hosts
是 CoreDNS 的一个 plugin,这一节的意思是加载 /etc/hosts
文件里面的解析信息。hosts 在最前面,则如果一个域名在 hosts 文件中存在,则优先使用这个信息返回;hosts
中找不到,则进入下一个 plugin 继续。缺少这一个指令,后面的 plugins 配置就无意义了;.
代表所有域名,后面的 IP 代表上游 DNS 服务器的列表。按照什么顺序溯源,由下面的 policy 指令决定;tls_servername
指定 DNS 名称。www.baidu.com
,后面我们再通过脚本填上所有的国内域名;forward
中被排除的域名。.
代表所有域名,后面的 IP 代表上游 DNS 服务器的列表,这里我选择的是 onedns。按照什么顺序溯源,由下面的 policy 指令决定;讲一下我自己的理解:
fallthrough
关键字流向下一个 plugin;编写一个 shell 脚本,用来更新 Corefile 中排除的国内域名列表:
$ brew install gnu-sed
$ cat <<EOF > /usr/local/bin/update_coredns.sh
#!/bin/bash
chinadns=$(curl -sL https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf|awk -F "/" '{print $2}')
touch update_coredns.sed && echo "" > update_coredns.sed
for i in $chinadns; do echo "/except/ s/$/ $i/" >> update_coredns.sed; done
gsed -i "s/\(except\).*/\1/" /usr/local/etc/Corefile
gsed -i -f update_coredns.sed /usr/local/etc/Corefile
EOF
$ sudo chmod +x /usr/local/bin/update_coredns.sh
先执行一遍该脚本,更新 Corefile 的配置:
$ /usr/local/bin/update_coredns.sh
然后通过 Crontab
制作定时任务,每隔两天下午两点更新域名列表:
$ crontab -l
0 14 */2 * * /usr/local/bin/update_coredns.sh
MacOS 可以使用 launchctl 来管理服务,它可以控制启动计算机时需要开启的服务,也可以设置定时执行特定任务的脚本,就像 Linux crontab 一样, 通过加装 *.plist
文件执行相应命令。Launchd 脚本存储在以下位置, 默认需要自己创建个人的 LaunchAgents
目录:
~/Library/LaunchAgents
: 由用户自己定义的任务项/Library/LaunchAgents
: 由管理员为用户定义的任务项/Library/LaunchDaemons
: 由管理员定义的守护进程任务项/System/Library/LaunchAgents
: 由 MacOS 为用户定义的任务项/System/Library/LaunchDaemons
: 由 MacOS 定义的守护进程任务项我们选择在 /Library/LaunchAgents/
目录下创建 coredns.plist
文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>coredns</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/coredns</string>
<string>-conf</string>
<string>/usr/local/etc/Corefile</string>
</array>
<key>StandardOutPath</key>
<string>/var/log/coredns.stdout.log</string>
<key>StandardErrorPath</key>
<string>/var/log/coredns.stderr.log</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
设置开机自动启动 coredns:
$ sudo launchctl load -w /Library/LaunchAgents/coredns.plist
查看服务:
$ sudo launchctl list|grep coredns
61676 0 coredns
$ sudo launchctl list coredns
{
"StandardOutPath" = "/var/log/coredns.stdout.log";
"LimitLoadToSessionType" = "System";
"StandardErrorPath" = "/var/log/coredns.stderr.log";
"Label" = "coredns";
"TimeOut" = 30;
"OnDemand" = false;
"LastExitStatus" = 0;
"PID" = 61676;
"Program" = "/usr/local/bin/coredns";
"ProgramArguments" = (
"/usr/local/bin/coredns";
"-conf";
"/usr/local/etc/Corefile";
);
};
大功告成,现在你只需要将系统的 DNS IP 设置为 127.0.0.1
就可以了。
$ dig www.google.com
; <<>> DiG 9.10.6 <<>> www.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49942
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 64 IN A 108.177.97.147
www.google.com. 64 IN A 108.177.97.105
www.google.com. 64 IN A 108.177.97.106
www.google.com. 64 IN A 108.177.97.103
www.google.com. 64 IN A 108.177.97.104
www.google.com. 64 IN A 108.177.97.99
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Mar 06 13:23:31 CST 2019
;; MSG SIZE rcvd: 223
搞定。