原文连接:fuckcloudnative.io/posts/insta…html
CoreDNS 是 Golang 编写的一个插件式 DNS 服务器,是 Kubernetes 1.13 后所内置的默认 DNS 服务器。CoreDNS 的目标是成为 cloud-native 环境下的 DNS 服务器和服务发现解决方案,即:linux
Our goal is to make CoreDNS the cloud-native DNS server and service discovery solution.nginx
它有如下几个特性:git
插件化(Plugins)github
基于 Caddy 服务器框架,CoreDNS 实现了一个插件链的架构,将大量应用端的逻辑抽象成 plugin 的形式(如 Kubernetes 的 DNS 服务发现,Prometheus 监控等)暴露给使用者。CoreDNS 以预配置的方式将不一样的 plugin 串成一条链,按序执行 plugin 的逻辑。从编译层面,用户选择所需的 plugin 编译到最终的可执行文件中,使得运行效率更高。CoreDNS 采用 Go 编写,因此从具体代码层面来看,每一个 plugin 其实都是实现了其定义的 interface 的组件而已。第三方只要按照 CoreDNS Plugin API 去编写自定义插件,就能够很方便地集成于 CoreDNS。web
配置简单化macos
引入表达力更强的 DSL,即 Corefile
形式的配置文件(也是基于 Caddy 框架开发)。json
一体化的解决方案windows
区别于 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 步逻辑:
请求被当前插件处理
插件将生成对应的响应并回给客户端,此时请求结束,下一个插件将不会被调用,如 whoami 插件;
请求被当前插件以 Fallthrough 形式处理
若是请求在该插件处理过程当中有可能将跳转至下一个插件,该过程称为 fallthrough,并以关键字 fallthrough
来决定是否容许此项操做,例如 host 插件,当查询域名未位于 /etc/hosts,则调用下一个插件;
请求在处理过程被携带 Hint
请求被插件处理,并在其响应中添加了某些信息(hint)后继续交由下一个插件处理。这些额外的信息将组成对客户端的最终响应,如 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
端口。其逻辑图可以下所示:
每一个进入到某个 server 的请求将按照 plugin.cfg
定义顺序执行其已经加载的插件。
从上图,咱们须要注意如下几点:
.:53
配置了 health
插件,可是它并为在上面的逻辑图中出现,缘由是:该插件并未参与请求相关的逻辑(即并无在插件链上),只是修改了 server 配置。更通常地,咱们能够将插件分为两种:
health
,tls
等插件;既然 CoreDNS 如此优秀,我用它来抵御伟大的防火长城岂不美哉?研究了一圈,发现技术上仍是可行的,惟一的一个缺点是不支持使用代理,不过你能够经过 proxychians-ng 或 proxifier 来强制使用代理。下面开始折腾。
具体的思路其实很是简单,就是将国内的域名查询请求转发到 114 等国内的公共 DNS 服务器,将国外的域名查询请求转发到 8.8.8.8 等国外的公共 DNS 服务器。然而 CoreDNS 的插件链有点反直觉,同一个插件链上的每个插件只能出现一次,若是只使用 forward
插件是知足不了需求的。
CoreDNS 原来还有个插件叫 proxy
,功能和 forward
相似,目测好像同时利用 proxy
和 forward
插件就能够实现咱的需求了。但理想与现实的差距老是很大,不知道从何时开始,CoreDNS 官方编译的二进制文件已经没有 proxy
插件了,真是气人。
偶然间发现了一个第三方插件 dnsredir,目测能够解决个人全部问题。该插件综合了 proxy
和 forward
插件的全部优势,支持 UDP、TCP、DNS-over-TLS 和 DNS-over-HTTPS,也支持多个后端,还具有健康检查和故障转移的功能,真是太香了!
它的语法是这样的:
dnsredir FROM... {
to TO...
}
复制代码
FROM...
是一个文件列表,包含了匹配的域名和解析该域名的服务器,说白了就是 dnsmasq 所使用的格式,直接看例子:
server=/0-100.com/114.114.114.114
server=/0-100.com/114.114.114.114
复制代码
为何要用这种格式呢?固然是为了方便啦。
为何这样会方便呢?固然是为了能够直接用上 FelixOnMars的大陆区域名列表了。。。FelixOnMars 同时还提供了 Google
和 Apple
的域名列表,这在某些地区某些ISP能够获得国内镜像的 IP,从而加速访问,想一想就刺激。
固然,除了使用文件列表外,还可使用 .
,相似于上面所说的根域。这个插件最大的亮点是能够在插件链中重复使用 dnsredir 插件,只要 FROM...
不重复就行。
to TO...
用来将 DNS 解析请求发给上游 DNS 服务器。支持几乎全部 DNS 协议,例如:
dns://1.1.1.1
8.8.8.8
tcp://9.9.9.9
udp://2606:4700:4700::1111
tls://1.1.1.1@one.one.one.one
tls://8.8.8.8
tls://dns.quad9.net
doh://cloudflare-dns.com/dns-query
json-doh://1.1.1.1/dns-query
json-doh://dns.google/resolve
ietf-doh://dns.quad9.net/dns-query
复制代码
dnsredir 虽香,但你们别忘了,它是第三方插件,官方默认的二进制文件是不包含该插件的。你能够选择本身编译,但若是常常须要升级怎么办?总不能每次都手动编译吧,也太累了。
好在有位大佬已经经过 CI/CD
流程将所需的第三方插件都集成编译进去了,并按期更新,简直就是我等的福音。大佬的项目地址为:
如今只须要下载对应操做系统的二进制文件,处处拷贝,就能够运行了。
下面通通以 MacOS 为例做讲解。Openwrt
的玩法也同样,参考本文的方法论便可,具体本文就不展开了。
直接下载二进制文件:
$ wget 'https://appveyorcidatav2.blob.core.windows.net/missdeer-15199/coredns-custom-build/1-7-1-514/idbodwxwywg1xgdg/distrib/coredns-linux-amd64.zip?sv=2015-12-11&sr=c&sig=BhMWcOVtDuaETyz2DcjpOr9GdvkpNVOqoIa7iWFpFNQ%3D&st=2020-12-23T15%3A26%3A19Z&se=2020-12-23T15%3A32%3A19Z&sp=r'
$ $ tar zxf coredns-linux-amd64.zip
$ mv coredns-linux-amd64/coredns /usr/local/bin/
复制代码
要深刻了解 CoreDNS,请查看其文档,及 plugins 的介绍。下面是个人配置文件:
cat > /usr/local/etc/Corefile <<EOF # https://coredns.io/plugins/cache/ (global_cache) { cache { # [5, 60] success 65536 3600 300 # [1, 10] denial 8192 600 60 prefetch 1 60m 10% } } .:7913 { ads { default-lists blacklist https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt whitelist https://files.krnl.eu/whitelist.txt log auto-update-interval 24h list-store ads-cache } errors hosts { fallthrough } health prometheus :9153 import global_cache template ANY AAAA { rcode NXDOMAIN } dnsredir accelerated-domains.china.conf google.china.conf apple.china.conf mydns.conf { expire 15s max_fails 3 health_check 3s policy round_robin path_reload 2s to 114.114.114.114 223.5.5.5 119.29.29.29 } dnsredir . { expire 60s max_fails 5 health_check 5s policy random spray to tls://8.8.8.8@dns.google tls://8.8.4.4@dns.google to tls://1.1.1.1@1dot1dot1dot1.cloudflare-dns.com tls://1.0.0.1@1dot1dot1dot1.cloudflare-dns.com # Global TLS server name # tls_servername cloudflare-dns.com } log loop reload 6s } EOF
复制代码
hosts
是 CoreDNS 的一个 plugin,这一节的意思是加载 /etc/hosts
文件里面的解析信息。hosts 在最前面,则若是一个域名在 hosts 文件中存在,则优先使用这个信息返回;hosts
中找不到,则进入下一个 plugin 继续。缺乏这一个指令,后面的 plugins 配置就无心义了;mydns.conf
。第二段 dnsredir 配置表示默认的解析配置,能够理解为故障转移,若是某个域名没有匹配到任何一个文件列表,就使用第二段 dnsredir 的上游 DNS 服务器进行解析。经过这样的配置方式,就实现了将国内的域名查询请求转发到 114 等国内的公共 DNS 服务器,将国外的域名查询请求转发到 8.8.8.8 等国外的公共 DNS 服务器。讲一下我本身的理解:
fallthrough
关键字流向下一个 plugin;注意:该方案的前提是可以强制让 CoreDNS 使用代理,或者更精确一点,让 8.8.8.8 和 8.8.4.4 使用代理。这里的方法比较复杂一点,本文就不介绍了。若是你实在不知道怎么办,能够将 8.8.8.8 这一行删除,直接使用 Cloudflare 提供的 DNS 服务,虽然响应有点慢,但好在能够访问。
若是你没法忍受 Cloudflare 的响应速度,能够考虑使用国内的无污染 DNS:红鱼 DNS。而后直接一劳永逸:
cat > /usr/local/etc/Corefile <<EOF # https://coredns.io/plugins/cache/ (global_cache) { cache { # [5, 60] success 65536 3600 300 # [1, 10] denial 8192 600 60 prefetch 1 60m 10% } } .:7913 { ads { default-lists blacklist https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt whitelist https://files.krnl.eu/whitelist.txt log auto-update-interval 24h list-store ads-cache } errors hosts { fallthrough } health prometheus :9153 import global_cache template ANY AAAA { rcode NXDOMAIN } dnsredir accelerated-domains.china.conf google.china.conf apple.china.conf mydns.conf { expire 15s max_fails 3 health_check 3s policy round_robin path_reload 2s to 114.114.114.114 223.5.5.5 119.29.29.29 } dnsredir . { expire 60s max_fails 5 health_check 5s policy random spray to doh://13800000000.rubyfish.cn } log loop reload 6s } EOF
复制代码
这样 CoreDNS 就不用担忧走代理的问题了。
大陆域名列表天天都会更新,因此还须要写个脚原本更新文件列表。不用检查文件是否存在了,直接简单粗暴无脑更新:
$ cat > /usr/local/bin/update_coredns.sh <<EOF #!/bin/bash rm accelerated-domains.china.conf wget https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf -O /usr/local/etc/accelerated-domains.china.conf rm apple.china.conf wget https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf -O /usr/local/etc/apple.china.conf rm google.china.conf wget https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/google.china.conf -O /usr/local/etc/google.china.conf 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";
);
};
复制代码
查看端口号:
$ sudo ps -ef|egrep -v grep|grep coredns
0 81819 1 0 2:54下午 ?? 0:04.70 /usr/local/bin/coredns -conf /usr/local/etc/Corefile
$ sudo lsof -P -p 81819|egrep "TCP|UDP"
coredns 81819 root 5u IPv6 0x1509853aadbdf853 0t0 TCP *:5302 (LISTEN)
coredns 81819 root 6u IPv6 0x1509853acd2f39ab 0t0 UDP *:5302
coredns 81819 root 7u IPv6 0x1509853aadbdc493 0t0 TCP *:53 (LISTEN)
coredns 81819 root 8u IPv6 0x1509853acd2f5a4b 0t0 UDP *:53
coredns 81819 root 9u IPv6 0x1509853ac63bfed3 0t0 TCP *:5301 (LISTEN)
coredns 81819 root 10u IPv6 0x1509853acd2f5d03 0t0 UDP *:5301
复制代码
大功告成,如今你只须要将系统的 DNS IP 设置为 127.0.0.1
就能够了。
$ doggo www.youtube.com @udp://127.0.0.1
NAME TYPE CLASS TTL ADDRESS NAMESERVER
www.youtube.com. CNAME IN 293s youtube-ui.l.google.com. 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.14.110 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.11.174 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.5.206 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.5.78 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.14.78 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 142.250.72.238 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 216.58.193.206 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 142.250.68.110 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 142.250.68.78 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 172.217.4.142 127.0.0.1:53
youtube-ui.l.google.com. A IN 293s 142.250.68.14 127.0.0.1:53
复制代码
搞定。
什么?你问我 doggo
是个啥?扫描下方二维码关注公众号:
公众号后台回复 doggo 便可获取你想要的东西😬