coredns
CoreDNS
在内网服务中,需要部署内部的 dns,用于各种服务的 dns 解析。常见的 dns server 有 bind,dnsmasq,coredns 等。coredns 出名于用于 kubernetes 中 service 到 ip 的解析,由于是使用 go 开发的,构建的二进制很发布部署使用,同时 coredns 也兼容 bind 的域名解析配置文件。
官网:https://coredns.io/
参考链接:https://blog.gmem.cc/coredns-study-note
一、基本使用
常用插件
bind
指定服务器监听的网络接口(IP地址): bind ADDRESS …
. {
bind 127.0.0.1 ::1
}
. {
bind 127.0.0.1
bind ::1
}
autopath
允许服务器端进行的搜索后缀(search domain)补全。如果插件发现客户端查询的名称,匹配search path的第一个元素,则自动遍历search path中的domain链,并返回第一个非NXDOMAIN结果。如果出现失败,则返回原始查询的应答。
由于autopath的应答中的名称,和原始问题不匹配,因此他会在CoreDNS中添加一个CNAME,从原始名称指向应答中的名称。
# ZONE autopath权威负责的Zone
# RESOLV-CONF 包含search domain的配置文件。或者指向其它插件,例如@kubernetes,这时从其它插件读取search domain
# 配置文件中必须有 search domain1 domain2 ... 这样的行
autopath [ZONE...] RESOLV-CONF
cache
实现前端缓存,用于查询后端(Upstream、Database…)成本较高的场景。启用此插件后,除了Zone transfers / Metadata以外的记录会被缓存默认3600s。
# TTL 缓存有效期,单位秒,默认3600
# ZONES 哪些Zone支持缓存
cache [TTL] [ZONES...] {
# 成功的DNS应答的缓存配置
success CAPACITY [TTL] [MINTTL]
# Denial of existence应答的缓存配置
denial CAPACITY [TTL] [MINTTL]
prefetch AMOUNT [[DURATION] [PERCENTAGE%]]
}
loop
能够检测简单的forwarding循环并终止服务器。
debug
能够从Panic中恢复,用于调试用途
errors
启用错误日志记录,格式:
errors {
# 在DURATION期间抓取匹配REGEXP的错误日志,聚合为单条日志
consolidate DURATION REGEXP
}
. {
errors {
consolidate 5m ".* i/o timeout$"
consolidate 30s "^Failed to .+"
}
}
forward
将DNS请求转发给上游DNS服务器,支持DNS / TCP / DNS over TLS。该插件代替原先的proxy插件。
# FROM 匹配此后缀的DNS查询会被转发
# TO 上游服务器的端点,支持指定协议,例如tls://9.9.9.9
forward FROM TO... {
# 空格分隔的,不进行转发的域名列表
except IGNORED_NAMES...
# 强制基于TCP协议
force_tcp
# 优先使用UDP
prefer_udp
# 多久后丢弃连接,
expire DURATION
# 判定为不健康需要的连续失败辞书
max_fails INTEGER
# DNS over TLS配置
tls CERT KEY CA
tls_servername NAME
# 选取上游服务器的算法,默认random
policy random|round_robin|sequential
# 健康检查周期
health_check DURATION
}
直接转发,用于兜底的示例:
forward . 223.5.5.5 1.1.1.1
使用TLS的示例:
forward . tls://9.9.9.9 {
tls_servername dns.quad9.net
health_check 5s
}
强制TCP转发:
svc.k8s.gmem.cc {
forward . 127.0.0.1:5353 {
force_tcp
}
}
从文件中读取上游DNS:
forward . /etc/resolv.conf
如果CoreDNS运行在K8S中,则CoreDNS的Pod的/etc/resolv.conf内容的基础,取决于kubelet的–resolv-conf配置,默认值指向宿主机的/etc/resolv.conf文件。
上游健康检查
首次转发,随机选取一个上游服务器,后续一直使用,直到它不健康了。
当出现一个错误 —— 任何DNS响应都不看作错误(REFUSED, NOTIMPL, SERVFAIL … )—— 则CoreDNS启动健康检查循环(默认0.5s一次),直到上游服务器恢复健康。
如果max_fails设置为0则不进行健康检查,总是认为上游服务器是健康的。
CoreDNS不向不健康的上游服务器转发请求,如果所有上游服务器都不健康,则随机选取一个转发。
health
启用进程级别的监控检查。示例: health :8080
,你可以访问:8080/health获取健康状态。
ready
提供readiness探针。示例: ready localhost:8091
hosts
以/etc/hosts风格提供Zone数据,格式:
# FILE 从文件中读取Zone数据,默认从/etc/hosts读取
# ZONES 此插件的权威Zone
hosts [FILE [ZONES...]] {
# 内联的HOSTS条目
[INLINE]
# 修改生成的DNS记录的DNS TTL
ttl SECONDS
# 禁止自动生成in-addr.arpa或ip6.arpa条目
no_reverse
# 重新载入文件的间隔,例如 300ms 1.5h 2h45m
reload DURATION
# 对于匹配的ZONES,如果此插件没有记录,则由下一个插件处理
fallthrough [ZONES...]
}
hosts {
172.21.0.1 kdc-1
fallthrough
}
import
该插件有两个用途:
- 导入其它配置文件到主配置文件
- 导入配置片段
格式: import PATTERN
log
记录查询日志,格式:
# NAMES 匹配的DNS查询被记录
# FORMAT 日志格式,
log [NAMES...] [FORMAT]
log [NAMES...] [FORMAT] {
class CLASSES...
}
CLASSES
指定哪些RCode会被记录
取值 | 说明 |
---|---|
success | 记录成功的请求 |
denial | 记录NXDOMAIN的请求、NOERROR但是没有数据的(nodata,域名存在,但是请求的记录类型没有) |
error | 记录SERVFAIL、NOTIMP、REFUSED等等,任何提示远程服务器不愿意解析请求的应答都包含在内 |
all | 默认,记录所有请求 |
rewrite
执行内部的消息重写。格式
# FIELD 请求/应答的什么字段需要被重写
# type 请求的TYPE字段
# class 消息的类型
# name 请求中的DNS名称
# answer name 应答中的DNS名称
# ttl TTL值
rewrite [continue|stop] FIELD [FROM TO|FROM TTL]
要重写DNS请求中的名称,使用格式:
rewrite [continue|stop] name [exact|prefix|suffix|substring|regex] STRING STRING
示例:
rewrite name substring k8s.gmem.cc k8s.gmem.site
rewrite name regex (.*)\.gmem\.cc {1}.gmem.site
rewrite name suffix .gmem.cc. .gmem.site.
要重写DNS响应中的名称,参考:
rewrite stop {
name regex (.*)\.gmem\.site {1}.gmem.site
answer name (.*)\.gmem\.site {1}.gmem.site
}
template
提供一个模板,基于请求来动态的生成响应。格式
# CLASS 查询分类,IN或ANY
# TYPE 查询类型,A、PTR... ANY匹配所有类型
# ZONE 此模板的Zone
template CLASS TYPE [ZONE...] {
# 匹配请求DNS名称的正则式
match REGEX...
# DNS应答
answer RR
additional RR
authority RR
rcode CODE
# 用于解析CNAMEs的上有集群
upstream
fallthrough [ZONE...]
}
泛域名
使用template插件可以实现泛域名解析,下面是一个例子:
template IN A mesh.gmem.cc {
match .*\.mesh\.gmem\.cc
answer "{{ .Name }} 60 IN A 10.0.11.11"
fallthrough
}
当前版本有一个奇怪的行为: 上述配置导致hosts插件指定的10.0.11.1 mesh.gmem.cc条目失效,必须指定fallthrough才能避免此问题。
启动服务
docker run -d --restart=always --name coredns-srv -p 53:53/udp -v `pwd`/conf:/Conf coredns/coredns -conf /Conf/corefile.conf
(common) {
log
cache 120
loop
errors {
consolidate 5m ".* i/o timeout$" warning
consolidate 30s "^Failed to .+"
}
}
local.com:53 {
import common
file db.local.com {
reload 30s
}
minimal
}
ccc {
auto {
directory /etc/coredns/zones/org
}
}
sugar.io:53 {
file db.local.com
log
errors
}
.:1053 {
# 使用DNS-over-TLS (DoT)
forward . tls://9.9.9.9 tls://1.0.0.1 {
tls_servername dns.quad9.net
health_check 5s
}
cache 30
}
# 主从配置,查询失败则到10.1.2.1上去查
example.org {
secondary {
transfer from 10.0.1.1 10.1.2.1
}
}
# 重定向到另外一台服务器查询
example.net {
secondary {
transfer from 10.1.2.1
}
transfer {
to *
}
}
.:53 {
health {
lameduck 5s
}
# 绑定interface ip
bind 127.0.0.1
# 先走本机的hosts
# https://coredns.io/plugins/hosts/
hosts {
# 自定义sms.service search.service 的解析
# 因为解析的域名少我们这里直接用hosts插件即可完成需求
# 如果有大量自定义域名解析那么建议用file插件使用 符合RFC 1035规范的DNS解析配置文件
127.0.0.1 git.local.com
127.0.0.1 drone.local.com
# ttl
ttl 60
# 重载hosts配置
reload 1m
# 继续执行
fallthrough
}
# file enables serving zone data from an RFC 1035-style master file.
# https://coredns.io/plugins/file/
# file service.signed service
# 最后所有的都转发到系统配置的上游dns服务器去解析
#forward . 114.114.114.114 223.5.5.5:53 [2400:3200::1]:53
forward . /etc/resolv.conf {
max_concurrent 1000
except example.org
}
#
acl {
block type A net 100.100.100.100/32
}
chaos CoreDNS-001 info@coredns.io
# 缓存时间ttl
cache 120
# 开启prometheus的mertics
# prometheus 0.0.0.0:0153
# 自动加载配置文件的间隔时间
reload 6s
# 输出日志
log
# 检测并停止死循环解析
loop
# 随机化 A/AAAA/MX 记录的顺序以实现负载均衡, forwald有多个时候。
# 因为 DNS resolver 通常使用第一条记录,而第一条记录是随机的。这样客户端的请求就能被随机分配到多个后端。
loadbalance round_robin
# 输出错误
errors
}
.:853 {
# 使用DNS-over-TLS (DoT)
forward . tls://223.5.5.5 tls://223.6.6.6 tls://2400:3200::1 tls://2400:3200:baba::1 {
tls_servername dns.alidns.com
health_check 5s
}
cache 30
}
#.:853 {
# # 使用DNS-over-TLS (DoT)
# forward . tls://8.8.8.8 tls://8.8.8.8 tls://2001:4860:4860::8888 tls://2001:4860:4860::8844 {
# tls_servername dns.google
# health_check 5s
# }
# cache 30
#}
可行的配置
参考链接:https://segmentfault.com/a/1190000022179401
Corefile
.:53 {
health {
lameduck 5s
}
auto {
directory ./zones
reload 1m
}
hosts {
127.0.0.1 local.io
ttl 120
reload 1m
fallthrough
}
#chaos CoreDNS-001 info@coredns.io
# prometheus 0.0.0.0:0153
log
#cache 120
loop
errors
forward . 114.114.114.114:53 8.8.8.8:53 [2400:3200::1]:53
loadbalance
}
db.local.com
$TTL 3600 ; 记录超时时间
$ORIGIN local.com. ; 指定 origin,下面的@符号可以作为他的别名,注意后面的.
; SOA 格式 [domain_name] IN SOA [域主服务器或主DNS服务器名] [管理员email] (时间信息)
@ IN SOA ns1.local.com. admin.local.com. (
2019071601 ; Serial
4H ; Refresh
1H ; Retry
7D ; Expire
4H ) ; Negative Cache TTL
; 配置 DNS 记录,指向 ns1.local.com
@ IN NS ns1
; 配置 ns1.local.com 的 A 记录, 指向coredns所在的机器
ns1 IN A 192.168.78.51
; 配置 local.com 的 A 记录,指向网站或其他用途的机器
@ IN A 192.168.78.51
git IN A 192.168.78.51
drone IN A 192.168.78.51
drone-runner IN A 192.168.78.51
www IN A 192.168.78.51
ccc IN A 192.168.78.51
; 配置泛域名,没有准确的三级子域名的域名全部指向此IPV4地址
* IN A 192.168.78.50
启动服务
docker run -tid -p 53:53/udp -v /yaml/coredns/Corefile:/Corefile -v /yaml/coredns/zones:/zones --name=coredns coredns/coredns
二、增加和编译插件
编译安装coredns:
coredns官方对于插件的分类基本可以分为三种:Plugins、External Plugins和其他。其中Plugins一般都会被默认编译到coredns的预编译版本中,而External Plugins则不会。官方的文档对外部插件的定义有着明确的解释,主要要求大概是有用、高效、符合标准、文档齐全、通过测试等。
官方给出了一个详细的文档说明,编译插件基本可以分为修改源码和修改编译的配置文件这两种方式,这里我们采用简单高效的修改配置文件的方式进行测试。
1、编译
下载源码:https://github.com/coredns/coredns.git
在我们前面下载的官方源码中,有一个plugin
的目录,里面是各种插件的安装包,同时还有一个plugin.cfg
的文件,里面列出了会编译到coredns中的插件,
[root@sugar2 coredns]# tail plugin.cfg
secondary:secondary
etcd:etcd
loop:loop
forward:forward
grpc:grpc
erratic:erratic
whoami:whoami
on:github.com/coredns/caddy/onevent
sign:sign
git:github.com/miekg/coredns-git
添加一个git插件
git:github.com/miekg/coredns-git
对于在plugin目录下已经存在的插件,则可以直接写成plugin中的目录名,不在的则写插件的仓库,可以使用go get下载:
sign:sign
下载插件:
go get github.com/miekg/coredns-git
然后我们开始编译
[root@sugar2 coredns]# make
2、验证插件
可以使用-plugins
输出包含的插件
[root@sugar2 coredns]# ./coredns -plugins
Server types:
dns
Caddyfile loaders:
flag
default
Other plugins:
dns.acl
dns.any
dns.auto
dns.autopath
dns.azure
dns.bind
dns.bufsize
dns.cache
dns.cancel
dns.chaos
dns.clouddns
dns.debug
dns.dns64
dns.dnssec
dns.dnstap
dns.erratic
dns.errors
dns.etcd
dns.file
dns.forward
dns.geoip
dns.git
dns.grpc
dns.header
dns.health
dns.hosts
dns.k8s_external
dns.kubernetes
dns.loadbalance
dns.local
dns.log
dns.loop
dns.metadata
dns.minimal
dns.nsid
dns.pprof
dns.prometheus
dns.ready
dns.reload
dns.rewrite
dns.root
dns.route53
dns.secondary
dns.sign
dns.template
dns.tls
dns.trace
dns.transfer
dns.whoami
on
1)使用git插件
建立存储zones文件的的git仓库:git@local.io:sugar/coredns_zone.git
配置文件模板
.:53 {
health {
lameduck 5s
}
auto {
directory /usr/local/coredns/zones
reload 1m
}
hosts {
ttl 120
reload 1m
fallthrough
}
#chaos CoreDNS-001 info@coredns.io
prometheus 0.0.0.0:9153
log
cache 300
loop
errors
forward . 114.114.114.114:53 8.8.8.8:53 [2400:3200::1]:53
loadbalance
git git@local.io:sugar/coredns_zone.git /usr/local/coredns/zones {
branch master
interval 3000 # pull的时间间隔
args --depth=1
pull_args --force
}
}
supervisord
[root@ftp coredns]# cat /etc/supervisord.d/coredns.ini
[program:coredns]
directory=/usr/local/coredns
command=/usr/local/coredns/coredns -conf /usr/local/coredns/Corefile
autostart=true
autorestart=true
startsecs=7
user = root
stderr_logfile=/var/log/coredns/coredns-err.log
stdout_logfile=/var/log/coredns/coredns.log
redirect_stderr = true
stdout_logfile_maxbytes = 100MB
stdout_logfile_backups = 4
stopasgroup=true
killasgroup=true