你所不了解的 coreDNS

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
云解析 DNS,旗舰版 1个月
简介: CoreDNS 是一个 DNS 服务器。基于 Go 语言开发。由于其灵活性,可以在多种不同的环境中使用。CoreDNS 已在 Apache 2 许可证版本获得许可,并且完全开源。其已成为 Kubernetes 1.13+ 以后版本的默认 DNS 服务。如今,当我们使用托管 Kubernetes 集群或为应用程序工作负载自行管理集群时,通常只需要关注应用程序本身,而无须过多关注 Kubernetes 提供的服务或如何利用它们。DNS 解析是任何应用程序的基本要求,因此我们需要确保它正常工作。

    CoreDNS 是一个 DNS 服务器。基于 Go 语言开发。由于其灵活性,可以在多种不同的环境中使用。CoreDNS 已在 Apache 2 许可证版本获得许可,并且完全开源。其已成为 Kubernetes 1.13+ 以后版本的默认 DNS 服务。如今,当我们使用托管 Kubernetes 集群或为应用程序工作负载自行管理集群时,通常只需要关注应用程序本身,而无须过多关注 Kubernetes 提供的服务或如何利用它们。DNS 解析是任何应用程序的基本要求,因此我们需要确保它正常工作。

    本文的将不深入探讨 coreDNS,而是解释 DNS 如何在 Kubernetes 中工作,coreDNS 包含什么以及 Corefile 如何使用插件。

    在讨论 coreDNS 之前,我们先来看一下 Kubernetes 是如何在集群中实现 DNS 交互的。假设有一个 Pod,即 Service A 想要与另一个 Pod Service B 进行通信。通常情况下,我们可以通过在 /etc/hosts 文件中将对方的地址信息更新上去来实现这一点,如下图所示。

    但在实际的业务场景中,我们所面临的并不是少量的服务交互。如果我们处理的是每分钟都在创建和销毁的数百个甚至上万个 Pod ,并且 Pod 之间也不停止的互访,那该怎么办?

    在这种情况下,我们不在 /etc/hosts 中创建条目(这不是合适的解决方案),而是将这些条目移动到集中式 DNS 服务器,即 10.10.0.10,如下图所示。现在,我们需要在 Pod 中的某个位置将这个 IP 指定为 nameserver,该位置恰好位于 /etc/resolv.conf 文件中。

    每次创建新 Pod 时,K8s 都会在 DNS 服务器 中更新新加入的 Pod 地址信息,并在新 Pod 的 /etc/resolv.conf 文件中更新相应的条目,当然,这些清单列表指向 DNS 服务器的 IP 地址,如下图所示:

    正如我上面所说,我们将 /etc/hosts 的条目更改为集中式 DNS 服务器。嗯,这是正确的,但有一部分是正确的。DNS 不会像我们在 Pods 中编辑 /etc/hosts 文件那样输入Pods(格式:<pod\u name><IP>)。相反,它通过将 Pod 的 IP 地址中的点替换为破折号来创建新的主机名,如主机名 “10-10-10-1(其格式为:<hostname><IP>)”。详情如下图所示:

    基于上述的解析,我们对 Pod 之间的交互有了简单的认知。然而,在实际的业务场景中,Pod 通过 K8s 集群中的服务进行通信,coreDNS 为这些服务设置记录(默认情况下,Pod 条目被禁用,但我们可以在 coreDNS 的 Ccorefile 中启用它们)。

    虽然 CoreDNS 和 Kube DNS 最终执行相同的任务,但在实现中存在一些影响资源消耗和性能的关键差异。我们可以在 coreDNS 官方文档中详细了解这一点。

    CoreDNS 自 1.9 版开始在 Kubernetes 中可用。它是一个快速灵活的 DNS 服务器。因此,意味着大家可以自由使用 DNS 数据,可以使用一系列插件来使用这些数据。如果某些功能不是现成的,我们可以通过编写插件来实现,毕竟,它是基于 Go 语言写的。

    我们将 CoreDNS 部署为集群中 Kube 系统命名空间中的一个部署对象,该集群中有一个名为 “kube dns” 的服务。它需要一个配置文件,我们将位于 /etc/coredns/corefile 的文件称之为 Corefile。

    其实,从本质上来讲,Corefile 由多种不同的插件组成,其往往主要用于错误处理、报告运行状况、监控指标、缓存等等。

    使 coreDNS 与 Kubernetes 协同工作的插件是 Kubernetes 插件。在 Kubernetes 插件中,设置了 Kubernetes 集群的顶级域(cluster.local)。此外,默认情况下,它会监视新服务。对于 Pod,我们需要通过在集群中创建 “pods Pod Mode” 条目,在 Kubernetes 插件下的 Corefile 中启用 “Pod Mode”。如果创建了一个新对象,它会在 coreDNS 服务器中添加服务记录或 Pod。

    Pods 的下一步是通过在 resolv.conf 文件中指定 nameserver来 指向用于 DNS 解析的 coreDNS IP 地址。但是,应该是什么地址呢?

    其实,我们不需要关心这个,因为 DNS 条目已经由 Kubelet 组件处理。

    当我们在集群中安装 coreDNS 时,我们将其作为服务公开,因此 Kubelet 将该服务的 IP 地址配置为 Pods 中的名称服务器。

    现在我们的问题是 Kubelet 是如何知道这一点的?

    当然,我们可以在 Kubelet 配置文件中看到 coreDNS 服务器的条目,如上图所示。

除此之外,我们还可以配置 Kubelet 并作为服务运行,并在该服务文件中传递 ClusterDns IP 信息。

    我们基于 Minikube 工具,来进行简要的阐述,其相关操作如下:


[administrator@JavaLangOutOfMemory ~] % minikube ssh
[administrator@JavaLangOutOfMemory ~] % cat /var/lib/kubelet/config.yaml

    我们来看一下完整的 config.yaml 文件信息,具体如下所示:


[administrator@JavaLangOutOfMemory ~] % cat /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 0S
    enabled: true
  x509:
    clientCAFile: /var/lib/minikube/certs/ca.crt
authorization:
  mode: Webhook
  webhook:
    cacheAuthorizedTTL: 0S
    cacheUnAuthorizedTTL: 0S
clusterDNS:
- 10.10.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimunGCAge: 0s
kind: KubeletConfiguration
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: ture
runtimeRequestTimeout: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

    然而,在我们实际的项目中,很多企业仍未使用托管 Kubernetes 服务,因此,在此我将讨论自建的 Kubernetes 集群,我们可以通过对任何 K8s 节点执行 ssh 来检查 Kubelet 服务中的 clusterDns 条目。下面是我们在 K8s 集群中使用的服务文件,如下所示:


[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/bin/kubelet \
  --allow-privileged=true \
  --cloud-provider= \
  --cluster-dns=10.10.0.10  \
  --cluster-domain=cluster.local \
  --container-runtime=docker \
  --docker-endpoint=unix:///var/run/docker.sock \
  --network-plugin=cni \
  --cni-bin-dir=/opt/cni/bin \
  --cni-conf-dir=/etc/cni/net.d \
  --kubeconfig=/var/lib/kubelet/kubeconfig \
  --serialize-image-pulls=true \
  --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \
  --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \
  --system-reserved=memory=19227Mi \
  --fail-swap-on=true \
  --runtime-cgroups=/systemd/system.slice \
  --kubelet-cgroups=/systemd/system.slice \
  --pod-infra-container-image=<dockerregistry/imagename:tag \
  --log-dir=/var/log/kubernetes \
  --logtostderr=false \
  --v=2
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

    接下来,我们再来看一下 Kubernetes DNS 记录的相关内容情况,具体如下所示。基于其格式规范:

    对于服务:svcname.namespace.type.rootDomain

    对于 Pod:hostname.namespace.type.rootDomain

    这里,我们举个简单的例子,如下所示:

    对于服务:test-service.default.svc.cluster.local

    对于 Pod:  10-10-10-1.default.pod.cluster.local

    在 Corefile 中,我们在集群中将 Corefile 作为配置映射传递,以便它与 coreDNS 的部署对象保持解耦我们可以在 “https://coredns.io/plugins/kubernetes/” 获得插件链列表。


.:53 {
        errors
        log
        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
        cache 30
        loop
        reload
        loadbalance
    }

    让我们再来看下 Kubernetes 插件,基于 Kubernetes 插件,CoreDNS 将会从 Kubernetes 集群中读取区域数据。它实现了为 Kubernetes 基于 DNS 的服务发现定义的规范。其格式为以下:


Kubernetes ZONE {
pods POD-MODE
           fallthrough ZONE
           ttl time_in_sec

    Kubernetes Plugin 块示例,具体可参考如下所示:


kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30

    在 Kubernetes 插件中,我们可以在 https://coredns.io/plugins/kubernetes/查看更多的选项以供选择。

    让我们再简要解析一下在上面的 Corefile 文件中核心参数含义及使用规范,具体如下所示:

    pods POD-MODE:设置处理基于 IP 的 Pod A 记录的模式,例如10-10-10-1.default.POD.cluster.local。在 A 10.10.10.1中,提供此选项是为了在直接连接到 Pod 时方便使用 SSL 证书。

    insecure:我们所使用的 Pod 模式的值,其往往会返回一个 Pod 记录。

    fallthrough[ZONES…]:如果插件授权的区域中的查询返回结果,或者返回查询的NXDOMAIN。当 DNS 没有所请求域的列表时,将创建 NXDOMAIN 响应。如果启用了 fallthrough,则插件不会在未找到记录时返回 NXDOMAIN ,而是将请求向下传递到插件链,该插件链可以包含另一个插件来处理查询。

    ttl:允许我们为响应设置自定义 ttl 。默认值为 5 秒。允许的最小 TTL 为 0 秒,最大 TTL 为 3600 秒。将 TTL 设置为 0 将阻止缓存记录。

    综上所述,我们阐述了 DNS 是如何在 Kubernetes 中发挥重要作用的。coreDNS 通过利用 Kubernetes 插件与 Kubernetes 进行协作。基于各种插件组合,我们可以根据自己的实际业务场景进行定制。基于上述所述,使得大家能够尽可能去接触到 coreDNS 世界奥妙,以助于大家在云原生生态中能够稳健翱翔。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
Kubernetes Linux Docker
Kubernetes v1.22.1部署报错3:.com/google_containers/coredns:v1.8.4...
Kubernetes v1.22.1部署报错3:.com/google_containers/coredns:v1.8.4...
248 0
|
6月前
|
Kubernetes 调度 Docker
Kubernetes高可用集群二进制部署(五)kubelet、kube-proxy、Calico、CoreDNS
Kubernetes高可用集群二进制部署(五)kubelet、kube-proxy、Calico、CoreDNS
Kubernetes高可用集群二进制部署(五)kubelet、kube-proxy、Calico、CoreDNS
|
3月前
|
Prometheus Kubernetes 网络协议
k8s学习笔记之CoreDNS
k8s学习笔记之CoreDNS
|
3月前
|
Kubernetes 监控 API
在K8S中,什么是 Minikube、Kubectl、Kubelet?
在K8S中,什么是 Minikube、Kubectl、Kubelet?
|
3月前
|
Kubernetes 监控 API
在K8S中,Minikube、Kubectl、Kubelet是什么?
在K8S中,Minikube、Kubectl、Kubelet是什么?
|
3月前
|
存储
coredns使用etcd
coredns使用etcd
|
Prometheus Kubernetes Cloud Native
k8s安装kube-promethues(超详细)
k8s安装kube-promethues(超详细)
1238 0
|
6月前
|
JSON Kubernetes 数据安全/隐私保护
Kubectl
Kubectl 是一个命令行工具,用于管理 Kubernetes 集群。它可以用来创建、删除、更新和查询 Kubernetes 资源,例如部署、服务、副本集等。Kubectl 提供了丰富的命令和选项,可以满足各种管理需求。
76 3
|
弹性计算 Perl 容器
ReplicaSet 、DaemonSet new
ReplicaSet 、DaemonSet new
71 0
ReplicaSet 、DaemonSet new