Contents

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

该插件有两个用途:

  1. 导入其它配置文件到主配置文件
  2. 导入配置片段

格式: 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