CoreDNS 中如何处理查询

以及它如何应用于群集域内的kubernetes自定义 DNS 条目。

上一篇文章中,介绍了三个在kubernetes中自定义 DNS 条目的不同用例

在该文章中,我们介绍了前两种用例。在本篇文章中,我们将展示如何使用kubernetes插件的fallthrough选项,以满足第三种用例。

要了解其工作原理,我们首先需要了解 CoreDNS 如何处理请求。这在之前的查询路由 一文中有所介绍,但在这里我们将更加深入地进行讨论。

我们都知道 CoreDNS 会链接插件。但这到底是什么意思呢?为了了解其含义,我们将会剖析一个 Corefile 以及了解如何将其转换成 CoreDNS 内部元素,然后我们将讨论查询是如何通过这些内部元素进行路由的。

考虑一下这个 Corefile

coredns.io:5300 {
  file /etc/coredns/zones/coredns.io.db
}

example.io:53 {
  errors
  log
  file /etc/coredns/zones/example.io.db
}

example.net:53 {
  file /etc/coredns/zones/example.net.db
}

.:53 {
  errors
  log
  health
  rewrite name foo.example.com foo.default.svc.cluster.local
  kubernetes cluster.local 10.0.0.0/24
  file /etc/coredns/example.db example.org
  forward . /etc/resolv.conf
  cache 30
}

请注意,此文件中有两个不同的端口:5300 和 53。在内部,每个端口都会产生一个dnsserver.Server。尽管有四个服务器块(节),但我们只获得两个实际的服务器。CoreDNS 将收集与同一端口相关的所有服务器块并将它们合并到同一dnsserver.Server 中。服务器将多路复用端口上的查询,并根据区域将它们传递到不同的插件链中。它会为该区域选择最具体的匹配服务器块。如果没有匹配的服务器块,则返回SERVFAIL。这在下图中以可视化的方式进行了展示。

Query Processing

因此,任何特定的查询都会经过一个插件链。插件的顺序在在构建时plugin.cfg文件决定,尽管有一些讨论关于在运行时修改该顺序。这就是为什么即使cache出现在服务器块的末尾,它也不是插件链的结尾。

请注意,在 .:53 服务器块中,我们定义了 health 插件,但它不会出现在图表中。这是由于有一些不同类型的插件。“常规”插件执行请求处理,并出现在插件链中。不过,有一些插件只修改服务器或服务器块的配置。由于它们不包含任何请求时逻辑,因此不会插入到插件链中。工作原理类似于此类插件的一些插件包括:healthtlsstartupshutdownroot 插件。

您可以将执行请求时处理的插件分为两组:以某种方式操作请求的插件以及后端插件。后端插件提供了区域和记录数据的不同来源。etcdfilekubernetes 插件都是后端的范例。

操作请求但不是后端的插件(即,它们不是区域数据的来源)通常会在执行逻辑后将查询传递至下一个插件。例如,rewrite 插件对请求进行更改,然后将其传递出去。在从后续插件返回结果时,它将问题部分还原为原来的样子(以便客户端不会抱怨),但会保留响应并将其传递回客户端。

给定的任何后端通常都是其区域的最后依托对象 - 它会返回结果或为查询返回 NXDOMAIN。不过,有时候这不是期望的行为,因此一些插件支持 fallthrough 选项。当启用 fallthrough 时,如果未找到记录,插件不会返回 NXDOMAIN,而是会将请求向下传递到该链中。接下来在该链中的后端有机会处理该请求。

返回我们最初对 Kubernetes 中这三个用例的讨论,我们现在可以了解我们如何使用 fallthrough 达到第三个用例。记起这篇博文中的初始 Corefile

.:53 {
    errors
    log
    health
    kubernetes cluster.local 10.0.0.0/24
    forward . /etc/resolv.conf
    cache 30
}

这涉及处理群集中 DNS 服务发现的标准。第三个用例是向现有集群域添加任意条目。为此,我们要定义另一个用于处理 cluster.local 区域的后端,并在 kubernetes 插件中配置 fallthrough 选项。对于非常动态的条目,我们可用到 etcd 插件。但为了演示目的,使用 file 插件更简单一些,因此我们这么做了。

由于在 plugin.cfgkubernetes 位于 file 之前,在 kubernetes 中使用 fallthrough 会导致 file 处理 kubernetes 无法处理的任何查询。这意味着我们需要像之前在博客中处理第二个用例一样拥有一个区域文件作为我们的 ConfigMap 的一部分。不过,在这种情况下,不像配置不同的区域(在另一篇博客中为 example.org),file 插件被配置为使用 cluster.local

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        log
        health
        kubernetes cluster.local 10.0.0.0/24 {
          fallthrough
        }
        file /etc/coredns/cluster.db cluster.local
        forward . /etc/resolv.conf
        cache 30
    }    
  cluster.db: |
    cluster.local.               IN      SOA     ns.dns.cluster.local. hostmaster.cluster.local. 2015082541 7200 3600 1209600 3600
    something.cluster.local.     IN      A       10.0.0.1
    otherthing.cluster.local.    IN      CNAME   google.com.    

记住将 cluster.db 文件添加到容器模板的 config-volume

      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
            - key: cluster.db
              path: cluster.db

最后,发信号给 CoreDNS 让它优雅地重新加载(每个正在运行的容器)

$ kubectl -n kube-system exec coredns-461002909-7mp96 -- kill -SIGUSR1 1

现在让我们尝试一下新的 DNS 记录。

$ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
If you don't see a command prompt, try pressing enter.
/ # host kubernetes
kubernetes.default.svc.cluster.local has address 10.0.0.1
/ # host something
something.cluster.local has address 10.0.0.1
/ # host otherthign
Host otherthign not found: 3(NXDOMAIN)
/ # host otherthing
otherthing.cluster.local is an alias for google.com.
google.com has IPv6 address 2607:f8b0:4005:805::200e
google.com mail is handled by 30 alt2.aspmx.l.google.com.
google.com mail is handled by 50 alt4.aspmx.l.google.com.
google.com mail is handled by 40 alt3.aspmx.l.google.com.
google.com mail is handled by 20 alt1.aspmx.l.google.com.
google.com mail is handled by 10 aspmx.l.google.com.
/ #

我们可以看到如果输入了错误的名称,我们仍然像期望的那样接收 NXDOMAIN。但是,正确的名称会解析为区域文件中的记录。因此,我们现在拥有了一种在集群域中创建自定义条目的方法。

在标准 CoreDNS 版本中,kubernetes 插件位于 fileetcd 之前。这意味着它获取处理查询的优先权。如果你愿意,可以重新构建 CoreDNS 以更改该顺序 - 如果想查看如何执行该操作,可以看看 Miek 在 如何将插件添加到 CoreDNS 中的文章。

John Belamaric
发布于:,标有 自定义发现DNS文档Kube-DNSKubernetes插件服务 标签,并使用了 1143 个字。