CoreDNS - 轻量级高性能的 DNS 服务在 MacOS 下的安装部署
DNS 的原理相信大家都了解。树形结构,根服务器,递归溯源,UDP 协议(现在也有 TCP 协议甚至 http 协议的)。搭建一台自己的 DNS 也是稀松平常的事情。
我遇到的场景是这样的。
- 公司有内网机房,研发用,研发环境和测试环境都在内网机房;
- 公司的域名是『company.com』,在公司内网有专门的 DNS(bind 搭建)做解析;
- 研发/测试环境的服务器也用顶级域名指向,例如:test1.mod-a.company.com。这类解析都是通过 bind 实现的。公司外网解析不到这个地址;
- 我自己需要一个安全的 DNS 环境,对 DNS 服务器溯源这个细节,优选 TCP 协议;
- 对『company.com』顶级域名的解析还是走公司内部的 DNS 服务器,即 bind;
- 之前用 ss 的 chinadns,可以实现第 4 条,但是无法实现第 5 条。
找了一圈,发现 CoreDNS 挺好的。推荐之。
一、安装
CoreDNS 是 golang 写的,所以只需要下载对应操作系统的二进制文件,到处拷贝,就可以运行了。
下面统统以 MacOS 为例作讲解。
cd ~/Downloads
curl -LO "https://github.com/coredns/coredns/releases/download/v1.1.2/coredns_1.1.2_darwin_amd64.tgz" && \
tar zxf coredns_1.1.2_darwin_amd64.tgz && \
mv ./coredns /usr/local/bin/
这里补充一句,CoreDNS 的二进制版本已经安装了所有的插件(plugins),不需要你自己编译。推荐下载二进制版本。
二、配置
要深入了解 CoreDNS,请查看其文档,及 plugins 的介绍。
cat <<EOF > /usr/local/etc/Corefile
. {
hosts {
fallthrough
}
forward . 1.1.1.1 8.8.8.8 119.29.29.29 223.5.5.5 {
force_tcp
max_fails 3
expire 10s
health_check 5s
policy sequential
except company.com
}
cache 120
reload 6s
log
errors
}
company.com {
hosts {
fallthrough
}
forward . 192.168.88.101 119.29.29.29 114.114.114.114 {
max_fails 3
expire 5s
health_check 3s
policy sequential
}
}
EOF
其中 192.168.88.101
是公司内网 DNS 服务器(bind)的 IP 地址。
对配置中的一些选项稍作解释。
hosts
:hosts
是 CoreDNS 的一个 plugin,这一节的意思是加载/etc/hosts
文件里面的解析信息。hosts
在最前面,则如果一个域名在 hosts 文件中存在,则优先使用这个信息返回;fallthrough
:如果hosts
中找不到,则进入下一个 plugin 继续。缺少这一个指令,后面的 plugins 配置就无意义了;forward
:这是另外一个 plugin。.
代表所有域名,后面的 IP 代表上游 DNS 服务器的列表。按照什么顺序溯源,由下面的policy
指令决定;force_tcp
:强制使用 TCP 协议溯源。这要求上游 DNS 必须支持 TCP 协议;expect
:指定哪些域名不按照本 plugin 配置溯源;cache
:溯源得到的结果,缓存指定时间。类似 TTL 的概念;reload
:多久扫描配置文件一次。如有变更,自动加载;log
:打印/存储访问日志;errors
:打印/存储错误日志;company.com { }
:另外一个『服务』,只服务针对『company.com』的域名解析;
我讲一下我自己的理解。
- 配置文件类似于 nginx 配置文件的格式;
- 最外面一级的大括号,对应『服务』的概念。多个服务可以共用一个端口;
- 往里面一级的大括号,对应 plugins 的概念,每一个大括号都是一个 plugin。这里可以看出,plugins 是 CoreDNS 的一等公民;
- 服务之间顺序有无关联没有感觉,但 plugins 之间是严重顺序相关的。某些 plugin 必须用
fallthrough
关键字流向下一个 plugin; - plugin 内部的配置选项是顺序无关的;
- 从 plugins 页面的介绍看,CoreDNS 的功能还是很强的,既能轻松从 bind 迁移,还能兼容 old-style dns server 的运维习惯;
- 从 CoreDNS 的性能指标看,适合做大型服务。
三、运行
# 前台运行方式
/usr/local/bin/coredns -conf /usr/local/etc/Corefile
NOTE(simon): 新增-log
参数,将日志打到 stdout,日志集中处理。
UPDATE(simon): 更新 coredns 到最新的 1.2.2 版本,已经没有 -log 这个参数了。日志默认也是直接打到 stdout 上面。
如果没有问题,这时候应该看到 CoreDNS 持续运行。
四、部署
在用 chinadns 的时候,遇到过 chinadns 崩掉的情况。作为基础服务,DNS 还是要能稳定持续提供服务的。此外,开机自动启动也是个必要的功能。
综合考虑,熟悉的 supervisor
是个好的选择。
设置服务配置目录
mkdir -p /usr/local/etc/supervisord.ini.d
修改 supervisor 配置
sed -i .bak ‘s@files = .@files = /usr/local/etc/supervisord.ini.d/.ini@g’ /usr/local/etc/supervisord.ini
为 supervisorctl 做映射
alias supervisorctl=’/usr/local/bin/supervisorctl -c /usr/local/etc/supervisord.ini’ cat «EOF » ~/.bash_profile alias supervisorctl=’/usr/local/bin/supervisorctl -c /usr/local/etc/supervisord.ini’ EOF
为 CoreDNS 写配置文件
cat «EOF > /usr/local/etc/supervisord.ini.d/coredns.ini [program:coredns] command=/usr/bin/sudo /usr/local/bin/coredns -conf /usr/local/etc/Corefile ;process_name=%(program_name)s ; process_name expr (default %(program_name)s) numprocs=1 ; number of processes copies to start (def 1) directory=/usr/local ; directory to cwd to before exec (def no cwd) ;umask=022 ; umask for process (default None) ;priority=999 ; the relative start priority (default 999) autostart=true ; start at supervisord start (default: true) autorestart=unexpected ; whether/when to restart (default: unexpected) startsecs=1 ; number of secs prog must stay running (def. 1) startretries=9999 ; max # of serial start failures (default 3) ;exitcodes=0,2 ; ‘expected’ exit codes for process (default 0,2) stopsignal=QUIT ; signal used to kill process (default TERM) ;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) ;stopasgroup=false ; send stop signal to the UNIX process group (default false) ;killasgroup=false ; SIGKILL the UNIX process group (def false) ;user=chrim ; setuid to this UNIX account to run the program ;redirect_stderr=true ; redirect proc stderr to stdout (default false) stdout_logfile=/usr/local/var/log/supervisor/coredns.stdout.log ; stdout log path, NONE for none; default AUTO stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) stdout_capture_maxbytes=1MB ; number of bytes in ‘capturemode’ (default 0) stdout_events_enabled=false ; emit events on stdout writes (default false) stderr_logfile=/usr/local/var/log/supervisor/coredns.stderr.log ; stderr log path, NONE for none; default AUTO stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) stderr_capture_maxbytes=1MB ; number of bytes in ‘capturemode’ (default 0) stderr_events_enabled=false ; emit events on stderr writes (default false) ;environment=A="1”,B="2” ; process environment additions (def no adds) ;serverurl=AUTO ; override serverurl computation (childutils)
EOF
设置 supervisord 开机自启动
brew service start supervisor
查看 CoreDNS 是否正常运行
supervisorctl status
</strike>
> NOTE(simon, 2018-05-30):
> 放弃使用 supervisor 的原因是,MacOS 作为生产力工具,supervisor 最友好方式的安装还是通过 brew。而 brew 安装的 supervisor 启动时,是当前用户权限,不是 root 身份。试了下,也没办法通过配置,提权到 root。再则,supervisor 的配置中,大量文件写到 `/usr/local` 目录下,如果以 root 身份启动 supervisord 进程,这些文件势必也是 root 权限的。而按照 brew 的指导意见,`/usr/local` 下还是要保留当前用户权限的,否则 brew 可能会挂。
> 所以兜兜转换,又用回到老的土办法。毕竟,稳定就好。
<strike>
```bash
cat <<EOF > ~/.bash_profile
# CoreDNS
COREDNS_PROCESS_COUNT=$(ps aux | grep coredns | grep -v grep | wc -l)
[ ${COREDNS_PROCESS_COUNT} -lt 1 ] && \
nohup sudo /usr/local/bin/coredns -conf /usr/local/etc/Corefile &
EOF
NOTE(simon, 2018-11-20): 更新一下脚本,实现下面几个功能:
- coredns 进程的 stderr 输出转到 stdout;
- coredns 进程不绑定到当前 tty 上,运行
jobs
命令不显示 coredns 进程;- 显式指定 nohup 将 coredns 进程的 stdout 输出打到 ~/nohup.out 文件;
COREDNS_PROCESS_COUNT=$(ps aux | grep coredns | grep -v grep | wc -l)
[ ${COREDNS_PROCESS_COUNT} -lt 1 ] && \
(2>&1 nohup sudo /usr/local/bin/coredns -conf /usr/local/etc/Corefile >> ~/nohup.out &)
五、验证
nslookup www.qq.com 127.0.0.1
nslookup www.facebook.com 127.0.0.1
nslookup test1.mod-a.company.com 127.0.0.1
公司内网 IP 几乎秒出。非死不可也能出。
搞定。
六、系统设置
在『系统偏好设置』->『网络』中,把 DNS 里面添加一行,127.0.0.1,并把新增这项移动到最前面,即可。