编写插件
正如手册前面提到的, 因为插件而让 CoreDNS 被选择。我们已经在previous section看到了很多配置,但是你怎么写自己的插件呢?
参见 Writing Plugins for CoreDNS有关于编写插件的一些较旧的文章。CoreDNS源码内的 plugin.md 文档也有些相关资料,在README.md还讨论了相关 styling 的内容。
简单的插件范例是 example 插件。 在 github repository 展示了很多用来创建插件的小型代码 (with tests!) 。
比如:
-
setup.go
和setup_test.go
,实现Corefile配置的解析。
当Corefile 解析器看到插件名字的时候,setup
函数(通常这样命名)被调用。在本例中, "example"。 -
example.go
(通常命名为<plugin_name>.go
),包含了处理查询的逻辑。
example_test.go
,包含了检查插件是否工作的基础单元测试。 -
README.md
,以UNIX 手册的风格展示了插件如何被配置。 - LICENSE 文件。For inclusion in CoreDNS, 这需要有一个 APL like license。
代码有着宽泛的内容;请随意fork,插件可以以其为基础开发。
插件怎么被调用
当 CoreDNS 想要使用一个插件,它会调用方法 ServeDNS
。ServeDNS
有三个参数:
-
context.Context
; -
dns.ResponseWriter
,亦即 client 连接; -
*dns.Msg
,来自 client 的请求。
ServeDNS
返回两个值: 一个 (response) code 和 一个 error。当服务器使用了errors 插件,error 会被记录到日志。
code 告诉 CoreDNS,插件链是否已经写了答复信息。在后面的案例中,CoreDNS 涉及到。对于 code 的值,我们 复用 dns 包内的DNS 返回码 return codes (rcodes)
CoreDNS treats:
- SERVFAIL (dns.RcodeServerFailure)
- REFUSED (dns.RcodeRefused)
- FORMERR (dns.RcodeFormatError)
- NOTIMP (dns.RcodeNotImplemented)
As special and will then assume nothing has been written to the client. In all other cases, it
assumes something has been written to the client (by the plugin).
查看 this post 怎么样将你的插件编译到CoreDNS
插件日志
使用 log package 来添加日志到你的插件。你可以参考如下初始化:
var log = clog.NewWithPlugin("example")
现在,你可以 log.Infof("...")
来打印信息到标准输出,以 level [INFO] plugin/example
作为前缀。Level 可以是: INFO
, WARNING
or ERROR
。
通常, logging should be left to the higher layers when returning an error. However, if there is
a reason to consume the error but still notify the user, then logging in the plugin can be acceptable.
Metrics
当输出metrics, Namespace 应该是 plugin.Namespace
(="coredns"),Subsystem 应该是插件的名字。
插件的README.md 应该包含 Metrics section 详细说明metrics。
如果插件支持readiness reporting,还必须有一个Ready section 来作详细说明。
Documentation
每个插件都应该有 README.md 文件,阐述插件的功能和如何配置。文件应该包含如下层次:
- Title: 插件的名字
- Subsection titled: "Named",
<plugin name> - <one line description>.
。比如 NAME DASH DESCRIPTION DOT. - Subsection titled: "Description",一长篇描述和插件支持的所有options。
- Subsection titled: "Syntax" ,阐述语法和支持的指令。
- Subsection titled: "Examples"。
- Optional Subsection titled: "See Also", 参考文档,比如 IETF RFCs。
- Optional Subsection titled: "Bugs" ,列出Bugs。
更多的 sections 也是可以的。
Style
我们使用Unix 手册风格:
- 在文档中的插件名字应该是斜体的:
*plugin*
. - 文档中,所有大写的用户支持的参数应该以粗体显示:
**EXAMPLE**
. - 可选的内容以中括号显示:
[optional]
. - 以三个点示意多个选项:
arg...
. - Item 以字面意义显示:
literal
.
Example Domain Names
请确保在范例和测试中使用 example.org
or example.net
。 这些是为范例/测试创建的标准domain names。 如果你不使用,有可能你设想的的domain name已经被注册了,而且被使用了。
Fallthrough
In a perfect world, the following would be true for plugins: "Either you are responsible for a zone or
not". If the answer is "not", the plugin should call the next plugin in the chain. If "yes" it
should handle all names that fall in this zone and the names below - i.e. it should handle the
entire domain and all sub domains, also see here
on how a query is process with fallthrough
enabled.
. {
file example.org db.example
}
In this example the file plugin is handling all names below (and including) example.org
. If
a query comes in that is not a subdomain (or equal to) example.org
the next plugin is called.
Now, the world isn't perfect, and there are good reasons to "fallthrough" to the next middleware,
meaning a plugin is only responsible for a subset of names within the zone. The first of these
to appear was the reverse plugin, now replaced with the generalized template plugin that can
synthesizes various responses.
The nature of the template plugin might only deal with specified record TYPEs, and then only
for a subset of the names. Ideally, you would want to layer template in front of another
plugin such as file or auto. This means template could handle some special
reverse cases and all other requests are handled by the backing plugin. This is exactly what
"fallthrough" does. To keep things explicit we've opted that plugins implementing such behavior
should implement a fallthrough
keyword.
The fallthrough
directive should optionally accept a list of zones. Only queries for records
in one of those zones should be allowed to fallthrough.