首页 > 编程笔记

CoreDNS简介(非常详细)

CoreDNS 是一种现代化的 DNS 服务器,被设计成可以与容器(如Linux和Docker容器)化环境良好地结合,尤其是在非常流行的容器编排系统Kubernetes管理的环境中。

Miek Gieben 在 2016 年编写了 CoreDNS 的初始版本,在此之前他还写过一个叫作 SkyDNS 的 DNS 服务器,以及一个用 Go 语言写的 DNS 函数库 Go DNS。与它的继任者 CoreDNS 一样,SkyDNS 的主要目的也是支持服务发现。Miek 非常欣赏一个基于 Go 的网络服务器架构 Caddy,所以他就选用 Caddy 构建了 CoreDNS。CoreDNS 继承了 Caddy 的主要优点:简单的配置语法、强大的基于插件的架构以及 Go 语言。

与 BIND 的配置文件的语法相比,CoreDNS 的 Corefile 使用起来非常简单。一个基础 CoreDNS 服务器的 Corefile 通常只有几行简单易懂的代码。

CoreDNS 使用插件来支持不同的 DNS 功能。例如,用于缓存的插件、用于转发的插件、用于配置主 DNS 服务器(从配置文件中读取区域数据)的插件,以及用于配置辅助 DNS 服务器的插件。每个插件的配置都很简单,而且如果你不需要某些插件,可以完全不用关心它们,对应的代码也不会执行。插件架构使得 CoreDNS 更快、更安全。

插件的开发也相当容易。这是非常重要的,原因有二。首先,如果想扩展 CoreDNS 的功能,你可以编写自己的插件;其次,降低开发难度有助于生态发展,所以目前已经有非常多的可用(以及更多正在实现的)插件,当有需要时,你很容易找到一个合适的现成插件。

前言中提到,Go 语言是内存安全的,这意味着它可以避免“内存访问错误”,如缓冲区溢出和悬空指针。这对于像 CoreDNS 这样的 DNS 服务器来说尤为重要,因为互联网上的任何人都可以访问它。恶意破坏的黑客可能会利用缓冲区溢出使 DNS 服务器崩溃,甚至获得对底层操作系统的控制。事实上,在 BIND 过去的几十年历史中,大量的严重漏洞都是由内存访问错误引起的。而有了 CoreDNS,你就不需要再担心这类问题了。

不过,CoreDNS 最显著的优势是它能够与容器基础设施和编排系统(如 etcd 和 Kubernetes)通信。

CoreDNS、容器和微服务

你可以将容器视为轻量级的、高效的虚拟机(Virtual Machine,VM)。得益于 hypervisor 虚拟化技术,单个物理硬件可以被多台使用单独的 OS 内核的虚拟机共享,而容器则提供了运行在相同 OS 内核下的执行环境,以及与虚拟机类似的隔离级别。容器比虚拟机小得多,可以更快地启动和停止。

容器通常用于基于微服务架构的软件中。在微服务中,一个复杂的应用程序通常被分解成许多个微小的服务,这些微服务各自负责提供一组很小的、定义清晰的功能。例如,一个微服务可能用来处理用户的身份验证,而另一个微服务则用于管理这些用户的授权。一个应用程序可能包含数十个甚至数百个微服务,同时,这些微服务可以在网络上相互通信。

通常来说,每个微服务可能由一个或多个容器提供。例如,身份验证服务可以实现为一个容器。由于启动和停止容器非常容易而且特别迅速,因此应用程序或更高级别的容器编排工具可能会随着身份验证需求的变化,动态地启动(或停止)更多的身份验证容器。

然而,在这样的动态环境中,跟踪特定服务的运行是非常具有挑战性的。假设支持数据库服务的容器需要与授权服务进行通信,从而确定是否应该允许某个特定用户执行特定的查询。而为了适应负载的变化,实现授权服务的容器会不断地动态启动或停止,那么我们该如何获得所有正在运行的授权服务容器的列表呢?

答案通常是 DNS。由于容器之间的通信都是基于IP的,而且过去的几十年中开发人员也一直在使用通过 DNS 查找资源 IP 地址这种方法,所以,使用 DNS 来标识这些提供特定服务的容器是很自然的。

这也正是 CoreDNS 真正发挥价值的地方。CoreDNS 不仅是一个灵活、安全的 DNS 服务器,而且它内置集成了包括 Kubernetes 在内的许多容器编排系统。这意味着容器化应用程序的管理员可以很容易地设置 DNS 服务器来协调和促进容器之间的通信。

CoreDNS的限制

目前 CoreDNS 仍然有一些特别的限制,使得它并不适合所有的 DNS 服务器场景。其中最主要的是,CoreDNS 不支持完整的递归(recursion)功能。换句话说,CoreDNS 不能从根 DNS 命名空间开始处理查询——查询根 DNS 服务器并跟踪引用直到从某个权威 DNS 服务器获得答案。相反,它需要依赖其他 DNS 服务器(通常称为转发器(forwarder))来实现这一点。

如果你还不确定 CoreDNS 是否满足你的需求,请参考下表,其中总结了 CoreDNS 和 BIND 功能之间的关键区别。

表:CoreDNS 和 BIND 的主要功能对比
  CoreDNS BIND
完整递归 不支持 支持
动态更新 不支持 支持
与 Kubernetes 集成 支持 不支持
与 Amazon Route 53 集成 支持 不支持
DNS 安全扩展(Domain Name System Security Extension,DNSSEC)支持 有限支持 完全支持
DNS over TLS(DoT) 支持 不支持

CoreDNS、Kubernetes和CNCF

Kubernetes 最初是由谷歌公司编写的容器编排系统,然后在 2015 年转换成了一个开源项目,如前文所述,CoreDNS 能够很好地与之集成。为了管理新开源的 Kubernetes 项目,谷歌与 Linux 基金会合作创建了 CNCF。

CNCF 已经成为构建基于云的应用程序的技术大本营,其中衍生的项目包括 Prometheus(支持收集指标和创建警报)以及 Envoy(一个服务代理)等。CNCF 管理的项目会从早期项目的沙箱(sandbox)发展到不同的成熟度级别(maturity level),再到孵化(incubating)阶段以让项目获得认可,直到最终发布(graduated),证明项目已经成熟并可以被广泛采用。

CoreDNS 于 2017 年提交给 CNCF,并于 2019 年 1 月发布。Kubernetes 从 1.13 版本(该版本于 2018 年 12 月发布)开始将 CoreDNS 作为其默认的 DNS 服务器,由此可以看出 CoreDNS 对 Kubernetes 环境的关键作用。现在几乎所有的 Kubernetes 环境都安装部署了 CoreDNS,Kubernetes 已经在容器世界中掀起了一股巨大的浪潮(容器本身似乎正在席卷全球),我们预计 CoreDNS 的部署数量将会持续地呈爆发式增长。

好啦,我们不再自卖自夸了,本文和大家讨论了 CoreDNS 基本的优点和缺点,以及它的命运是如何与 Kubernetes 绑在一起的。

推荐阅读