概述

DNS 是网络中非常重要的一个服务和话题,在平时工作中使用的也非常多,之前我也写过一篇介绍 DNS 以及系统设置的文章:DNS 以及 Linux 下的相关配置文件,但是今天我要聊一聊的是自己部署一个 DNS 服务器。

在之前我也写过自建 DNS 服务器的教程:Mac 搭建本地 DNS 服务器,但是这篇文章中用的是 DNSMasq,其实我之前的工作中也用的是这个,因为之前的产品是偏 IaaS,所以选型是相对比较偏传统的。但是,最近因为产品更倾向于云原生,所以换成了 CoreDNS,于是这里就简单做下总结。

CoreDNS 概念

CoreDNS 的实现有别于其他的 DNS 服务器(我从文档里面抄的,实际上其他服务器的实现有何特别之处我没有去了解过😂),CoreDNS 的特点就是非常的灵活,它的灵活来自于插件系统,也就是说,CoreDNS 将大部分的功能够交给一个个插件来完成,然后通过配置来组合插件从而实现我们需要的功能。

在 CoreDNS 中,有两个关于插件的配置非常重要,分别是:

插件

插件是 CoreDNS 的核心概念,它实际上就是一个实现了特定接口的代码,每当有一个 DNS 查询进来时,被配置的插件都将被调用,并传递给它三个参数:

需要哪些插件是通过编译时的 plugin.cfg 来配置的,并且需要注意的是,这个配置文件里面的顺序很重要,因为这也是插件在实际运行中的顺序,所以在 Corefile 中也有插件的定义顺序,但是那个顺序是没意义的,真正地顺序是 plugin.cfg 中配置的,例如这是一个官方的配置:

  1. [root@liqiang.io]# cat plugin.cfg
  2. root:root
  3. metadata:metadata
  4. geoip:geoip
  5. cancel:cancel
  6. tls:tls
  7. timeouts:timeouts
  8. reload:reload
  9. nsid:nsid
  10. bufsize:bufsize
  11. bind:bind
  12. debug:debug
  13. trace:trace
  14. ready:ready
  15. health:health
  16. pprof:pprof
  17. prometheus:metrics
  18. errors:errors
  19. log:log
  20. dnstap:dnstap
  21. local:local
  22. dns64:dns64
  23. acl:acl
  24. any:any
  25. chaos:chaos
  26. loadbalance:loadbalance
  27. tsig:tsig
  28. cache:cache
  29. rewrite:rewrite
  30. header:header
  31. dnssec:dnssec
  32. autopath:autopath
  33. minimal:minimal
  34. template:template
  35. transfer:transfer
  36. hosts:hosts
  37. route53:route53
  38. azure:azure
  39. clouddns:clouddns
  40. k8s_external:k8s_external
  41. kubernetes:kubernetes
  42. file:file
  43. auto:auto
  44. secondary:secondary
  45. etcd:etcd
  46. loop:loop
  47. forward:forward
  48. grpc:grpc
  49. erratic:erratic
  50. whoami:whoami
  51. on:github.com/coredns/caddy/onevent
  52. sign:sign
  53. view:view

配置

CoreDNS 在默认的情况下会在运行目录中寻找 Corefile 作为启动配置,但是你可以通过 -conf 指定启动配置。Corefile 配置也很简单,它由很多的 Server Blocks 组成(当然,你不指定或者只指定一个也是可以),每个 Server Block 的模式为:

  1. <zones> {
  2. # Plugins defined here.
  3. }

可以看到,Server Block 包含两个部分,分别是 zoneplugins

一个配置的示例:

  1. [root@liqiang.io]# cat Corefile
  2. dns://google.com:53 {
  3. errors
  4. forward . 8.8.8.8
  5. }
  6. # 兜底配置,前面没有满足的都会使用这个配置
  7. dns://.:53 {
  8. errors
  9. forward . 223.5.5.5:53
  10. }

实践

安装

CoreDNS 的安装支持多种方式,但是一般来说可以分为预编译程序和容器两种方式,一般来说我们都是在 K8S 环境下运行的,所以用容器的情况比较多,并且可能平时我们需要在本地运行来调试一下问题,所以这里给一个简单的使用 Docker 运行的示例:

  1. [root@liqiang.io]# docker run -d --rm --name coredns \
  2. --volume=/tmp/coredns:/root/ \
  3. -p 53:53/udp \
  4. coredns/coredns \
  5. -conf /root/Corefile

这样,我们就跑起来一个 CoreDNS 实例了,因为 CoreDNS 是一个无状态的服务,所以,我们可以快速地进行横向扩展,而无需考虑其他额外的配置。

验证

当我们跑起来之后,可以通过 DNS 相关的命令指定 DNS 服务器进行验证,例如我这里用 dig:

  1. [root@liqiang.io]# dig @127.0.0.1 google.com
  2. ; <<>> DiG xxxxxx <<>> @127.0.0.1 google.com
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30520
  7. ;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
  8. ;; OPT PSEUDOSECTION:
  9. ; EDNS: version: 0, flags:; udp: 1232
  10. ; COOKIE: 754b24dbebe1a964 (echoed)
  11. ;; QUESTION SECTION:
  12. ;google.com. IN A
  13. ;; ANSWER SECTION:
  14. google.com. 30 IN A 142.251.175.113
  15. google.com. 30 IN A 142.251.175.102
  16. google.com. 30 IN A 142.251.175.101
  17. google.com. 30 IN A 142.251.175.138
  18. google.com. 30 IN A 142.251.175.139
  19. google.com. 30 IN A 142.251.175.100
  20. ;; Query time: 11 msec
  21. ;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
  22. ;; WHEN: Mon Jul 22 00:20:15 UTC 2024
  23. ;; MSG SIZE rcvd: 207