乐趣区

关于云计算:使用-CoreDNS-来应对-DNS-污染

原文链接:https://fuckcloudnative.io/posts/install-coredns-on-macos/

CoreDNS 是 Golang 编写的一个插件式 DNS 服务器,是 Kubernetes 1.13 后所内置的默认 DNS 服务器。CoreDNS 的指标是成为 cloud-native 环境下的 DNS 服务器和服务发现解决方案,即:

Our goal is to make CoreDNS the cloud-native DNS server and service discovery solution.

它有以下几个个性:

  • 插件化(Plugins)

    基于 Caddy 服务器框架,CoreDNS 实现了一个插件链的架构,将大量利用端的逻辑形象成 plugin 的模式(如 Kubernetes 的 DNS 服务发现,Prometheus 监控等)裸露给使用者。CoreDNS 以预配置的形式将不同的 plugin 串成一条链,按序执行 plugin 的逻辑。从编译层面,用户抉择所需的 plugin 编译到最终的可执行文件中,使得运行效率更高。CoreDNS 采纳 Go 编写,所以从具体代码层面来看,每个 plugin 其实都是实现了其定义的 interface 的组件而已。第三方只有依照 CoreDNS Plugin API 去编写自定义插件,就能够很不便地集成于 CoreDNS。

  • 配置简单化

    引入表达力更强的 DSL,即 Corefile 模式的配置文件(也是基于 Caddy 框架开发)。

  • 一体化的解决方案

    区别于 kube-dns,CoreDNS 编译进去就是一个独自的二进制可执行文件,内置了 cache,backend storage,health check 等性能,无需第三方组件来辅助实现其余性能,从而使得部署更不便,内存治理更为平安。

其实从性能角度来看,CoreDNS 更像是一个通用 DNS 计划(相似于 BIND),而后通过插件模式来极大地扩大本身性能,从而能够实用于不同的场景(比方 Kubernetes)。正如官网博客所说:

CoreDNS is powered by plugins.

<span id=”inline-toc”>1.</span> Corefile 介绍


Corefile 是 CoreDNS 的配置文件(源于 Caddy 框架的配置文件 Caddyfile),它定义了:

  • server 以什么协定监听在哪个端口(能够同时定义多个 server 监听不同端口)
  • server 负责哪个 zone 的权威(authoritative)DNS 解析
  • server 将加载哪些插件

常见地,一个典型的 Corefile 格局如下所示:

ZONE:[PORT] {[PLUGIN] ...
}
  • <span id=inline-purple>ZONE</span> : 定义 server 负责的 zone,PORT 是可选项,默认为 53;
  • <span id=inline-purple>PLUGIN</span> : 定义 server 所要加载的 plugin。每个 plugin 能够有多个参数;

比方:

. {chaos CoreDNS-001}

上述配置文件表白的是:server 负责根域 . 的解析,其中 plugin 是 chaos 且没有参数。

定义 server

一个最简略的配置文件能够为:

.{}

即 server 监听 53 端口并不应用插件。 如果此时在定义其余 server,要保障监听端口不抵触;如果是在原来 server 减少 zone,则要保障 zone 之间不抵触, 如:

.    {}
.:54 {}

另一个 server 运行于 54 端口并负责根域 . 的解析。

又如:

example.org {whoami}
org {whoami}

同一个 server 然而负责不同 zone 的解析,有不同插件链。

定义 Reverse 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 协定,也反对 TLSgRPC,即 DNS-over-TLS 和 DNS-over-gRPC 模式:

tls://example.org:1443 {#...}

<span id=”inline-toc”>2.</span> 插件的工作模式


当 CoreDNS 启动后,它将依据配置文件启动不同 server,每台 server 都领有本人的插件链。当有 DNS 申请时,它将顺次经验如下 3 步逻辑:

  1. 如果有以后申请的 server 有多个 zone,将采纳贪婪准则抉择最匹配的 zone;
  2. 一旦找到匹配的 server,依照 plugin.cfg 定义的程序执行插件链上的插件;
  3. 每个插件将判断以后申请是否应该解决,将有以下几种可能:
  • 申请被以后插件解决

    插件将生成对应的响应并回给客户端,此时申请完结,下一个插件将不会被调用,如 whoami 插件;

  • 申请被以后插件以 Fallthrough 模式解决

    如果申请在该插件处理过程中有可能将跳转至下一个插件,该过程称为 fallthrough,并以关键字 fallthrough 来决定是否容许此项操作,例如 host 插件,当查问域名未位于 /etc/hosts,则调用下一个插件;

  • 申请在处理过程被携带 Hint

    申请被插件解决,并在其响应中增加了某些信息(hint)后持续交由下一个插件解决。这些额定的信息将组成对客户端的最终响应,如 metric 插件;

<span id=”inline-toc”>3.</span> CoreDNS 如何解决 DNS 申请


如果 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 个区块),别离监听在 530053 端口。其逻辑图可如下所示:

每个进入到某个 server 的申请将依照 plugin.cfg 定义程序执行其曾经加载的插件。

从上图,咱们须要留神以下几点:

  • 只管在 .:53 配置了 health 插件,然而它并为在下面的逻辑图中呈现,起因是:该插件并未参加申请相干的逻辑(即并没有在插件链上),只是批改了 server 配置。更个别地,咱们能够将插件分为两种:

    • Normal 插件 :参加申请相干的逻辑,且插入到插件链中;
    • 其余插件 :不参加申请相干的逻辑,也不呈现在插件链中,只是用于批改 server 的配置,如 healthtls 等插件;

<span id=”inline-toc”>4.</span> 配置 CoreDNS


既然 CoreDNS 如此优良,我用它来抵挡平凡的防火长城岂不美哉?钻研了一圈,发现技术上还是可行的,惟一的一个毛病是不反对应用代理,不过你能够通过 proxychians-ng 或 proxifier 来强制应用代理。上面开始折腾。

具体的思路其实非常简单,就是将国内的域名查问申请转发到 114 等国内的公共 DNS 服务器,将国外的域名查问申请转发到 8.8.8.8 等国外的公共 DNS 服务器。然而 CoreDNS 的插件链有点反直觉,同一个插件链上的每一个插件只能呈现一次,如果只应用 forward 插件是满足不了需要的。

CoreDNS 原来还有个插件叫 proxy,性能和 forward 相似,目测如同同时利用 proxyforward 插件就能够实现咱的需要了。但现实与事实的差距总是很大,不晓得从什么时候开始,CoreDNS 官网编译的二进制文件曾经没有 proxy 插件了,真是气人。

dnsredir

偶然间发现了一个第三方插件 dnsredir,目测能够解决我的所有问题。该插件综合了 proxyforward 插件的所有长处,反对 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 同时还提供了 GoogleApple 的域名列表,这在某些地区某些 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

增强版 CoreDNS

dnsredir 虽香,但大家别忘了,它是第三方插件,官网默认的二进制文件是不蕴含该插件的。你能够抉择本人编译,但如果常常须要降级怎么办?总不能每次都手动编译吧,也太累了。

好在有位大佬曾经通过 CI/CD 流程将所需的第三方插件都集成编译进去了,并定期更新,几乎就是我等的福音。大佬的我的项目地址为:

  • https://github.com/missdeer/coredns_custom_build

当初只须要下载对应操作系统的二进制文件,到处拷贝,就能够运行了。

上面通通以 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 : hosts 是 CoreDNS 的一个 plugin,这一节的意思是加载 /etc/hosts 文件外面的解析信息。hosts 在最后面,则如果一个域名在 hosts 文件中存在,则优先应用这个信息返回;
  • fallthrough : 如果 hosts 中找不到,则进入下一个 plugin 持续。短少这一个指令,前面的 plugins 配置就无意义了;
  • cache : 溯源失去的后果,缓存指定工夫。相似 TTL 的概念;
  • reload : 多久扫描配置文件一次。如有变更,主动加载;
  • errors : 打印 / 存储谬误日志;
  • dnsredir : 这是重点插件。第一段 dnsredir 配置应用了 4 个文件列表,均是 FelixOnMars 的大陆区域名列表,这里我还加了一个自定义的文件列表 mydns.conf。第二段 dnsredir 配置示意默认的解析配置,能够了解为故障转移,如果某个域名没有匹配到任何一个文件列表,就应用第二段 dnsredir 的上游 DNS 服务器进行解析。通过这样的配置形式,就实现了将国内的域名查问申请转发到 114 等国内的公共 DNS 服务器,将国外的域名查问申请转发到 8.8.8.8 等国外的公共 DNS 服务器。

讲一下我本人的了解:

  1. 配置文件相似于 nginx 配置文件的格局;
  2. 最里面一级的大括号,对应『服务』的概念。多个服务能够共用一个端口;
  3. 往里面一级的大括号,对应 plugins 的概念,每一个大括号都是一个 plugin。这里能够看出,plugins 是 CoreDNS 的一等公民;
  4. 服务之间程序有无关联没有感觉,但 plugins 之间是重大程序相干的。某些 plugin 必须用 fallthrough 关键字流向下一个 plugin;
  5. plugin 外部的配置选项是程序无关的;
  6. 从 plugins 页面的介绍看,CoreDNS 的性能还是很强的,既能轻松从 bind 迁徙,还能兼容 old-style dns server 的运维习惯;
  7. 从 CoreDNS 的性能指标看,适宜做大型服务。

留神:该计划的前提是可能强制让 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 即可获取你想要的货色????

<span id=”inline-toc”>5.</span> 参考资料


  • CoreDNS 应用与架构剖析
  • CoreDNS 搭建无污染 DNS

Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12 离线安装包公布地址 http://store.lameleg.com,欢送体验。应用了最新的 sealos v3.3.6 版本。作了主机名解析配置优化,lvscare 挂载 /lib/module 解决开机启动 ipvs 加载问题,修复 lvscare 社区 netlink 与 3.10 内核不兼容问题,sealos 生成百年证书等个性。更多个性 https://github.com/fanux/sealos。欢送扫描下方的二维码退出钉钉群,钉钉群曾经集成 sealos 的机器人实时能够看到 sealos 的动静。

退出移动版