Coredns 源码阅读(导读)

周末看了一下 coredns 的源代码,目前为止只是差不多搞清楚了这个代码库的逻辑。写篇博客记录一下,如果你也想要阅读这个库的源代码的话,这篇博客可以节省你的一些时间。

coredns 介绍

代码库地址:https://github.com/coredns/coredns

coredns 是一个 dns server,简单来说就是这个软件启动之后可以监听一个端口,然后你将 dns 查询请求发给这个端口,它可以告诉你 dns 解析的结果。所以作为任意一种 dns server(DNS Authoritative Nameserver, 或者 Recursive Resolver Server) 工作,我认为都是没有问题的。

这个代码库值得一读的理由有:

  1. coredns 以 plugin 的形式工作,除了 plugin 之外部分的代码很少,而且那部分代码其实不必阅读也可以(在读完本文之后);plugin 作为 first-class citizen 的好处是,职责清晰,一个 plugin 只做一件事情。比如 metrics,trace 这种东西,都是以 plugin 的形式存在的。这样,阅读起来非常方便;
  2. 每个 plugin 完成自己的事情,阅读起来难度低。而且这个库要求的背景知识很少,不需要懂很多网络的协议。DNS 相关的协议部分,看到哪里不懂的时候再查就好了。

不好的地方:

  1. 这个服务是基于一个 coredns 自己 fork 维护的 caddy server 来实现的,就导致可能需要去看 caddy 部分的代码。而且 coredns 自己维护的 caddy 已经脱离最新版了,我发现用的 caddy plugin 已经在官方的代码库中删除了。所以有些地方理解起来可能不简单。

看代码之前的准备工作(推荐)

如果之前没有用过的话,建议看代码之前先:

  1. 看完 manual:https://coredns.io/manual/toc/,可以知道使用方法,和大体的工作原理;
  2. 看下 plugin 的写法:https://coredns.io/2016/12/19/writing-plugins-for-coredns/

编译方法

因为 golang 是编译型的语言,所以无法像 Python 那样动态安装、加载插件。要新增插件,必须重新编译,将 plugin 的代码编译进二进制。

插件的列表在 plugin.cfg 中。如果新安装插件,需要将新插件写入这个列表,然后运行 go generate coredns.go 命令,重新生成这两个文件:

编译的命令是: CGO_ENABLED=0 go build -v -ldflags="-s -w -X github.com/coredns/coredns/coremain.GitCommit=3288b111-dirty" -o coredns. GitCommit 作为变量注入进 binary,运行的时候打印。

程序入口

coredns.go 里面 import 了 plugin,然后调用了 coremain.Run

coremain.Run 里面只是处理了一些和 Version(用于 Print)的信息,和命令和参数。最后启动了 Caddy server。

coredns server 的逻辑在 coredns/core/dnsserver. 但是中间涉及和 caddy v1 的交互,比如 MakeServers() , 是 caddy 里面的接口。应该也不是很重要。

server 里面的入口应该是 Serve()。基本的逻辑是拿到 plugin chain,然后调用第一个 Plugin, 调用 Plugin 的 ServeDNS()

Plugins

Plugin Chain, 顾名思义,是 Chain 在一起的。并不是在 server 里面一个 for 循环调用所有的 Plugins,而是 Server 只会调用第一个 Plugin。

第一个 Plugin 可以处理 DNS 请求,返回结果。如果像是 metrics 这样不负责逻辑的 Plugin,可以在完成自己要做的事情之后,去调用 coredns/plugin/plugin.go 里面的 NextOrFailure 函数,交给下一个 Plugin 去处理。和 ASGI 一样,turtles all the way down.

Plugin 主要做两件事情:

  1. 通过 init() 函数将自己注册进去,也可以做一些初始化的工作。比如支持配置。Corefile 中的配置可以在 init 的时候通过 setup 接口读到;
  2. ServeDNS() 主要的函数入口。处理 DNS 请求。

whoami 这个 Plugin 返回查询者的 IP 端口等信息,逻辑比较简单,建议从这个 plugin 开始看。

Leave a comment

您的电子邮箱地址不会被公开。 必填项已用*标注