【kubernetes/k8s源码分析】coredns 源码分析之一解读源码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zhonglinzhang/article/details/99679323

        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 所示函数

扫描二维码关注公众号,回复: 7593013 查看本文章
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 包含三个参数

  • context.Context;
  • dns.ResponseWriter that is basically the client’s connection;
  • *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.

    失败在尝试其他插件

      

猜你喜欢

转载自blog.csdn.net/zhonglinzhang/article/details/99679323