如果你厌倦了那些老古董的DNS服务 , 那么可以试试Coredns, 因为Caddy出色的插件设计, 所以Coredns的骨架基于caddy构建, 也就继承了良好的扩展性, 又因为Go语言是一门开发效率比较高的语言 , 所以开发一个自定义的插件是比较简单的事情 , 但是大多数使用都不需要自己编写插件 , 因为默认的插件以及外部的插件足够大多数场景了 。
本文主要分为四个部分
- 源码阅读
- 自定义插件编写
- 一些非常有用的工具函数
这里假设启动命令为
./coredns
并且当前工作目录有一个名称是Corefile的文本文件, 内容如下. {forward . 8.8.8.8 1.1.1.1logerrorscache}
首先看看coredns的函数入口// coredns.gofunc main() { coremain.Run()}// coremainrun.gofunc Run()flag.StringVar(&conf, "conf", "", "Corefile to load (default ""+caddy.DefaultConfigFile+"")") // 注册一个加载配置文件函数, 如果指定了-conf参数, confLoader就能加载参数对应的配置文件 caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))// 如果不指定 , 自然也没关系, 那就在注册一个默认的配置文件加载函数 caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader)) if version {showVersion()os.Exit(0) } if plugins {fmt.Println(caddy.DescribePlugins())os.Exit(0) } // Get Corefile input corefile, err := caddy.LoadCaddyfile(serverType) // Start your engines instance, err := caddy.Start(corefile) // Twiddle your thumbs instance.Wait()}
coredns的启动流程还是比较简洁的,, 可以看到coredns没有太多参数选项, 除了打印插件列表, 显示版本的命令参数之外 , 就是启动流程了 , 而启动流程概括起来也不负载 , 加载配置文件 , 基于配置文件启动 , 但是在在深入caddy.LoadCaddyfile和caddy.Start之前要先看看在此之前运行的init方法.// corednsserverregister.gofunc init() { caddy.RegisterServerType(serverType, caddy.ServerType{Directives: func() []string { return Directives },DefaultInput: func() caddy.Input {// 如果配置文件找不到会加载配置了whoami, log插件的配置文件return caddy.CaddyfileInput{Filepath:"Corefile",Contents:[]byte(".:" + Port + " {nwhoaminlogn}n"),ServerTypeName: serverType,}},NewContext: newContext, })}
因为caddy是一个http/s web服务器 , 而不是一个dns服务器 , 所以我们需要在调用caddy启动流程之前注入一个用于dns的ServerType , 后续创建的Server等对象都是基于此 , 并且这个ServerType设置了一个静态的配置文件".:" + Port + " {nwhoaminlogn}n", 也就是说在没有指定配置文件路径以及本地没有Corefile的情况下 , 还是能够启动一个默认的dns服务器 , 这个服务加载了whoami, log两个插件 。加载配置文件在入口函数可以知道, 注入了以下两个配置文件加载函数
// 该函数比较简单, 就是将函数追加到caddyfileLoaders切片中caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))// 如果caddyfileLoaders切片中所有函数都没有加载到配置文件, 就会使用默认加载函数caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
前者的加载函数就是读取参数-conf指定的配置文件 。后者就是读取本地的Corefile, 如果存在的话 。
confLoader的代码如下:
func confLoader(serverType string) (caddy.Input, error) { if conf == "" {return nil, nil } if conf == "stdin" {return caddy.CaddyfileFromPipe(os.Stdin, serverType) } contents, err := os.ReadFile(filepath.Clean(conf)) return caddy.CaddyfileInput{Contents:contents,Filepath:conf,ServerTypeName: serverType, }, nil}
可以看到逻辑比较简单, 如果指定了-conf参数就通过参数值找到对应的配置文件并返回因为我们没有指定-conf参数, 所以调用默认加载函数 。
LoadCaddyfile加载逻辑如下:
// vendorgithub.comcorednscaddycaddy.gofunc LoadCaddyfile(serverType string) (Input, error) { // 通过注册的配置文件加载函数, 默认加载函数加载配置文件 cdyfile, err := loadCaddyfileInput(serverType)// 函数找不到就用 if cdyfile == nil {cdyfile = DefaultInput(serverType) } return cdyfile, nil}// vendorgithub.comcorednscaddyplugins.gofunc loadCaddyfileInput(serverType string) (Input, error) { var loadedBy string var caddyfileToUse Input// 这里只注册一个从命令行参数加载的loader// caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))// 因为没有指定参数, 所以没哟配置文件会加载 for _, l := range caddyfileLoaders {cdyfile, err := l.loader.Load(serverType) }// 继而调用默认的加载函数 if caddyfileToUse == nil && defaultCaddyfileLoader.loader != nil {cdyfile, err := defaultCaddyfileLoader.loader.Load(serverType)if cdyfile != nil {loaderUsed = defaultCaddyfileLoadercaddyfileToUse = cdyfile} } return caddyfileToUse, nil}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 下嘴唇发麻什么病兆
- 2021电视机排行榜前十名 2021最好的电视机
- 虾皮补肾吗
- 右肩关节疼痛的原因
- 后腰部有横纹是肾虚吗
- 如果是你就好了日语歌?如果是你就好了 李正
- 胡萝卜减肥汁
- 如果那天我再勇敢一点作文?那天如果我再勇敢一些的作文600字
- 徐庶最后回到刘备身边了吗?徐庶如果一直辅佐刘备_1
- 如果关羽守荆州?如果关羽守住了荆州