CoreDns 是高性能,高扩展性的 DNS 服务。解决 Kube-dns 一些问题,CoreDns 采用插件机制,所有功能都是插件形式编写,用户可以扩展自己的插件
CoreDNS 基于 Caddy 框架实现,整个项目大量使用了 Caddy 的插件功能
1. 读取 plugin.cfg 生成文件
1.1 directives_generate.go 读取 pluginFile 文件
metadata:metadata cancel:cancel tls:tls reload:reload nsid:nsid root:root bind:bind debug:debug 。。。。。。。。。。。。
1.2 genImports 方法生成文件 ore/plugin/zplugin.go
作用是:加载一大堆的插件,执行 init 方法
// generated by directives_generate.go; DO NOT EDIT
package plugin
import (
// Include all plugins.
_ "github.com/coredns/coredns/plugin/auto"
_ "github.com/coredns/coredns/plugin/autopath"
_ "github.com/coredns/coredns/plugin/bind"
_ "github.com/coredns/coredns/plugin/cache"
1.3 genDirectives 方法生成文件 core/dnsserver/zdirectives.go
// generated by directives_generate.go; DO NOT EDIT
package dnsserver
// Directives are registered in the order they should be
// executed.
//
// Ordering is VERY important. Every plugin will
// feel the effects of all other plugin below
// (after) them during a request, but they must not
// care what plugin above them are doing.
var Directives = []string{
"metadata",
"cancel",
"tls",
"reload",
"nsid",
"root",
CoreDns 采用插件机制,所有功能都是插件形式编写,用户可以扩展自己的插件,怎样为 coredns 添加插件,请看第 2 章节
2. 为 coredns 添加插件
2.1 注册插件
每一个插件目录下有个 setup.go 文件,利用了 caddy 服务框架,注册插件 caddy.RegisterPlugin,init 初始化函数以如下形式:
ServerType:设置为 dns,DNS 服务器
Action:设置为 setup, 2.2 所示函数
func init() {
caddy.RegisterPlugin("forward", caddy.Plugin{
ServerType: "dns",
Action: setup,
})
}
2.2 setup 函数
这个函数是调用 dnsserver.GetConfig(c).AddPlugin 方法将该插件加入,该插件实现了 Handler 接口:
- ServeDNS(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
- Name() string
2.3 实现 ServerDNS 和 Name 方法
Handler interface {
ServeDNS(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
Name() string
}
参考:How to Add Plugins to CoreDNS
3. corefile
通过 DSL 定义 DNS 服务,在 Corefile 中就可以定义多个插件对外提供服务,如下官方提供样例:
{} 代表一个zone,格式是 zone:port{}, 其中 . 代表默认zone
{} 插件的名称, 当解析域名时,会先匹配 zone(未匹配会执行默认 zone),zone 内的插件从上到下依次执行(是core/dnsserver/zdirectives.go内的顺序)
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
forward . 8.8.8.8
log
errors
cache
}
CoreDNS 根据每代码的区和端点提供服务,样例中暴露了两个 DNS 服务,一个监听 5300 端口,另一个 53 端口,请求会根据不同的域名选择不同区中的插件进行处理
参考:https://coredns.io/manual/toc/
4. 插件怎么被调用
每个请求都会发送给 core/dnsserver/server.go 的 ServeDNS 进行处理,ServeDNS 包含三个参数
- a
context.Context
; - a
dns.ResponseWriter
that is basically the client’s connection; - a
*dns.Msg
that is the request from the client.
// ServeDNS is the entry point for every request to the address that s
// is bound to. It acts as a multiplexer for the requests zonename as
// defined in the request so that the correct zone
// (configuration and plugin stack) will handle the request.
func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
4.1 客户端返回的错误
- SERVFAIL (dns.RcodeServerFailure)
- REFUSED (dns.RcodeRefused)
- FORMERR (dns.RcodeFormatError)
- NOTIMP (dns.RcodeNotImplemented)
5. coredns 源码编译
make 会出现很多失败的情况,翻墙失败,或者路径和 github.com 有些出入的,经过同事帮忙,推荐了 go.proxy.io,解决了编译包依赖的问题
go1.11 引入了 go module 来解决依赖管理,go module 被集成到原生的 go cmd 中,如果代码库在 $GOPATH 中,go1.11 的 module 功能是默认不会开启的,通过环境变量开启 go module:export GO111MODULE=on
设置代理,
export GOPROXY=https://goproxy.io,再次 make 就搞定
总结:
coredns 插件模板归纳如下:
- init() 注册为 caddy 中名为 "dns",参数是 setup 方法
- setup() 初始化一个插件实例,dnsContext.Plugin 加入插件列表
- ServeDns() 插件的功能实现的地方
coredns 性能损耗在尝试所有的,包括 default.svc.cluster.local. svc.cluster.local. cluster.local.
失败在尝试其他插件