原文鏈接: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.
1. Corefile 介紹
Corefile 是 CoreDNS 的組態檔(源于 Caddy 框架的組態檔 Caddyfile),它定義了:
server以什么協議監聽在哪個埠(可以同時定義多個 server 監聽不同埠)- server 負責哪個
zone的權威(authoritative)DNS 決議 - server 將加載哪些插件
常見地,一個典型的 Corefile 格式如下所示:
ZONE:[PORT] {
[PLUGIN] ...
}
- ZONE : 定義 server 負責的 zone,
PORT是可選項,默認為 53; - PLUGIN : 定義 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 協議,也支持 TLS 和 gRPC,即 DNS-over-TLS 和 DNS-over-gRPC 模式:
tls://example.org:1443 {
#...
}
2. 插件的作業模式
當 CoreDNS 啟動后,它將根據組態檔啟動不同 server ,每臺 server 都擁有自己的插件鏈,當有 DNS 請求時,它將依次經歷如下 3 步邏輯:
- 如果有當前請求的 server 有多個 zone,將采用貪心原則選擇最匹配的 zone;
- 一旦找到匹配的 server,按照 plugin.cfg 定義的順序執行插件鏈上的插件;
- 每個插件將判斷當前請求是否應該處理,將有以下幾種可能:
-
請求被當前插件處理
插件將生成對應的回應并回給客戶端,此時請求結束,下一個插件將不會被呼叫,如 whoami 插件;
-
請求被當前插件以 Fallthrough 形式處理
如果請求在該插件處理程序中有可能將跳轉至下一個插件,該程序稱為 fallthrough,并以關鍵字
fallthrough來決定是否允許此項操作,例如 host 插件,當查詢域名未位于 /etc/hosts,則呼叫下一個插件; -
請求在處理程序被攜帶 Hint
請求被插件處理,并在其回應中添加了某些資訊(hint)后繼續交由下一個插件處理,這些額外的資訊將組成對客戶端的最終回應,如
metric插件;
3. 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 個區塊),分別監聽在 5300 和 53 埠,其邏輯圖可如下所示:

每個進入到某個 server 的請求將按照 plugin.cfg 定義順序執行其已經加載的插件,
從上圖,我們需要注意以下幾點:
- 盡管在
.:53配置了health插件,但是它并為在上面的邏輯圖中出現,原因是:該插件并未參與請求相關的邏輯(即并沒有在插件鏈上),只是修改了 server 配置,更一般地,我們可以將插件分為兩種:- Normal 插件:參與請求相關的邏輯,且插入到插件鏈中;
- 其他插件:不參與請求相關的邏輯,也不出現在插件鏈中,只是用于修改 server 的配置,如
health,tls等插件;
4. 配置 CoreDNS
既然 CoreDNS 如此優秀,我用它來抵御偉大的防火長城豈不美哉?研究了一圈,發現技術上還是可行的,唯一的一個缺點是不支持使用代理,不過你可以通過 proxychians-ng 或 proxifier 來強制使用代理,下面開始折騰,
具體的思路其實非常簡單,就是將國內的域名查詢請求轉發到 114 等國內的公共 DNS 服務器,將國外的域名查詢請求轉發到 8.8.8.8 等國外的公共 DNS 服務器,然而 CoreDNS 的插件鏈有點反直覺,同一個插件鏈上的每一個插件只能出現一次,如果只使用 forward 插件是滿足不了需求的,
CoreDNS 原來還有個插件叫 proxy,功能和 forward 類似,目測好像同時利用 proxy 和 forward 插件就可以實作咱的需求了,但理想與現實的差距總是很大,不知道從什么時候開始,CoreDNS 官方編譯的二進制檔案已經沒有 proxy 插件了,真是氣人,
dnsredir
偶然間發現了一個第三方插件 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://[email protected] 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://[email protected] tls://[email protected]
to tls://[email protected] tls://[email protected]
# 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 服務器,
講一下我自己的理解:
- 組態檔類似于 nginx 組態檔的格式;
- 最外面一級的大括號,對應『服務』的概念,多個服務可以共用一個埠;
- 往里面一級的大括號,對應 plugins 的概念,每一個大括號都是一個 plugin,這里可以看出,plugins 是 CoreDNS 的一等公民;
- 服務之間順序有無關聯沒有感覺,但 plugins 之間是嚴重順序相關的,某些 plugin 必須用
fallthrough關鍵字流向下一個 plugin; - plugin 內部的配置選項是順序無關的;
- 從 plugins 頁面的介紹看,CoreDNS 的功能還是很強的,既能輕松從 bind 遷移,還能兼容 old-style dns server 的運維習慣;
- 從 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 即可獲取你想要的東西??
5. 參考資料
- 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的動態,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/242254.html
標籤:其他
