浅析 CoreDNS 的工作机制

浅析 CoreDNS 的工作机制

CoreDNS 是一个开源的域名系统(DNS)服务器,用于将域名解析为 IP 地址以实现网络通信。它是一个用 Go 语言编写的可扩展 DNS 服务器,旨在取代传统的 DNS 服务器并提供更灵活、可配置的解析方案。

CoreDNS 提供了模块化的插件系统,允许用户根据需求选择和组合插件,以定制 DNS 服务器的功能和行为。通过添加不同的插件,用户可以实现缓存、转发、重写、策略路由、服务发现等功能,从而满足各种复杂的域名解析需求。

插件由设置(Setup)、**注册(Registration)处理程序(Handler)**部分组成。

  • Setup 程序解析配置和插件的指令。
  • Handler 是处理查询并实现所有逻辑的代码。
  • Registration 是在 CoreDNS 中注册插件 - 这在编译 CoreDNS 时完成。服务器可以使用所有注册的插件,每个服务器中配置哪些插件的决定在运行时进行,并在 CoreDNS 的配置文件 Corefile 中完成。

安装运行

在 macOS 上安装 CoreDNS:

brew install coredns

可以执行 coredns -plugins 来查看已经安装的插件:

coredns -plugins

Server types:
  dns

Caddyfile loaders:
  flag
  default

Other plugins:
  dns.acl
  dns.any
  dns.auto
  dns.autopath
  dns.azure
  dns.bind
  dns.bufsize
  dns.cache
  dns.cancel
  dns.chaos
  dns.clouddns
  dns.debug
  dns.dns64
  dns.dnssec
  dns.dnstap
  dns.erratic
  dns.errors
  dns.etcd
  dns.file
  dns.forward
  dns.geoip
  dns.grpc
  dns.header
  dns.health
  dns.hosts
  dns.k8s_external
  dns.kubernetes
  dns.loadbalance
  dns.local
  dns.log
  dns.loop
  dns.metadata
  dns.minimal
  dns.nsid
  dns.pprof
  dns.prometheus
  dns.ready
  dns.reload
  dns.rewrite
  dns.root
  dns.route53
  dns.secondary
  dns.sign
  dns.template
  dns.tls
  dns.trace
  dns.transfer
  dns.tsig
  dns.view
  dns.whoami
  on

CoreDNS 的运行非常简单,执行 coredns 命令即可启动服务器。为了避免端口冲突,可以指定其他的端口启动:

coredns -dns.port=1053
.:1053
CoreDNS-1.10.0
darwin/arm64, go1.19.1,

如果需要对 DNS 服务器进行配置,需要通过 -conf 指定一个 Corefile 配置文件,还可以在配置文件中启用插件。不指定配置文件的话,CoreDNS 会使用 默认的配置,仅启用 whoamilog 两个插件:

.:PORT {
   whoami
   log
}

比如我从一台虚拟机上执行 DNS 的解析请求,192.168.1.174 是运行 CoreDNS 服务器的 macOS 地址:

dig @192.168.1.174 -p 1053 example.com

; <<>> DiG 9.16.1-Ubuntu <<>> @192.168.1.174 -p 1053 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1283
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: d73ad3e9df490541 (echoed)
;; QUESTION SECTION:
;example.com.			IN	A

;; ADDITIONAL SECTION:
example.com.		0	IN	A	192.168.1.11
_udp.example.com.	0	IN	SRV	0 0 48788 .

;; Query time: 8 msec
;; SERVER: 192.168.1.174#1053(192.168.1.174)
;; WHEN: Sat Jul 15 02:38:11 UTC 2023
;; MSG SIZE  rcvd: 114

在响应的 ADDITIONAL 中可以看到 example.com 解析到了 192.168.1.11,而这个地址则是发起请求的虚拟机的 IP 地址。这就是 whoami 插件的 逻辑

whoami 会返回请求方的本地 IP 地址、端口。

源码解析

启动

Coredns 使用 fork 自 CaddyCoredns Caddy 启动 DNS 服务器。

  1. 加载指定的 Corefile 配置文件,如 /etc/coredns/Corefile coremain/run.go#L60
  2. 启动 Caddy Server coremain/run.go#L66
  3. 运行插件 1. 检查配置文件中的插件。Coredns 有一个支持的 插件列表,这个列表中插件的顺序非常重要。 2. 为各插件创建控制器(Controller) 3. 找到插件注册的启动方法 setup,如 Kubernetes 插件的 setup 方法。各插件的 setup 方法都可以在 coredns/plugin/[PLUGIN NAME]/setup.go 中找到。 4. 启动插件。
  4. 创建服务器 core/dnsserver/register.go#L134
  5. 启动服务器 github.com/coredns/caddy@v1.1.1/caddy.go:542

处理请求

  1. 服务器启动之后开始接收 DNS 的解析请求,见 github.com/coredns/caddy@v1.1.1/caddy.go:805
  2. 处理 DNS 解析请求 core/dnsserver/server.go#L173,这里会调用 方法 ServeDNS 按顺序执行配置的插件,所有插件都实现了 plugin.Handler 接口。

配置的每个插件会决定是否执行 DNS 的解析,以及下一步的操作:返回响应、报错、立即返回,亦或是调用下一个插件继续执行。详细内容,看参考 官方文档

CoreDNS 与 Kubernetes

CoreDNS 在 Kubernetes 中扮演着重要的角色,为集群内部的 DNS 解析提供服务。通过与 Kubernetes 的紧密集成,CoreDNS 能够提供可靠的服务发现和通信功能,使得容器和服务能够通过域名进行互相访问和通信,为 Kubernetes 集群的运行提供了基础设施支持。

所有功能的实现,都在 kubernetes 插件 中,该插件实现了 Kubernetes 的基于 DNS 的服务发现规范,CoreDNS 以此来替代 kube-dns。

CoreDNS 在 Kubernetes 中的配置(维护在 ConfigMap coredns 中):

.:53 {
   errors
   health {
      lameduck 5s
   }
   ready
   kubernetes cluster.local in-addr.arpa ip6.arpa {
      pods insecure
      fallthrough in-addr.arpa ip6.arpa
      ttl 30
   }
   prometheus :9153
   forward . /etc/resolv.conf {
      max_concurrent 1000
   }
   cache 30
   loop
   reload
   loadbalance
}

CoreDNS 在处理解析请求时,会按顺序执行各个插件。

插件配置

 kubernetes cluster.local in-addr.arpa ip6.arpa { #1
    pods insecure #2
    fallthrough in-addr.arpa ip6.arpa #3
    ttl 30 #4
 }
  • #1 kubernetes 插件会处理 cluster.local 域的 DNS 解析请求,如 foo.bar.svc.cluster.localin-addr.arpaip6.arpa 用于做 DNS 反向查询,如 4.4.8.8.in-addr.arpa
  • #2 将 POD 域名(如 10-244-0-2.bar.pod.cluster.local)的解析模式设置为 insecure,还支持 disabledverified 另外两种模式。
  • #3 对于反向查询的解析请求,会交给其他插件继续查询。
  • #4 解析结果的有效期,默认是 5s,这里设置为 30s。

启动

CoreDNS 启动时会延迟最多 5 秒提供 DNS 服务,直到可以连接到 Kubernetes API 并同步所有监控的对象,见 文档

kubernetes 插件将根据配置 最多启动 4 个控制器,分别持续监控 Service、Pod(解析模式设置为 verified 时启动)、Endpoint、Namespace 资源,维护本地缓存。

处理请求

kubernetes 插件实现了 plugin.ServiceBackend 接口,响应请求时从本地缓存中查找记录。

以 A 记录的查询为例,调用 plugin#A 方法 间接调用 ServiceBackend#Services 方法的实现 进行检索,返回 IP 地址。

nslookup -type=a foo.bar.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10:53

Name:	foo.bar.svc.cluster.local
Address: 10.96.60.147

(转载本站文章请注明作者和出处乱世浮生,请勿用于任何商业用途)

comments powered by Disqus