DNS原理讲解
Last updated
Last updated
服务发现,说白了就是服务(应用)之间相互定位的过程。
服务发现需要解决的问题:
1、服务动态性强--容器在k8s中ip变化或迁移
2、更新发布频繁--版本迭代快
3、支持自动伸缩--大促或流量高峰
我们为了解决pod地址变化的问题,我们之前部署了service资源,将pod地址通过service资源暴露的固定地址,来解决以上问题,
那么,如何解决service资源名称和service资源暴露出来的集群网络IP做自动的对应呢,从而达到服务的自动发现呢?
在k8s中,coredns就是为了解决以上问题。
当我进入到pod内部以后,我们会发现我们的dns地址是我们的coredns地址,以及搜索域:
Kubernetes 集群中运行了一组 DNS Pod,配置了对应的 Service,并由 kubelete 将 DNS Service 的 IP 地址配置到节点上的容器中以便解析 DNS names。
集群中的每一个 Service(包括 DNS 服务本身)都将被分配一个 DNS name。默认情况下,客户端 Pod 的 DNS 搜索列表包括 Pod 所在的名称空间以及集群的默认域。例如:
假设名称空间 bar
中有一个 Service 名为 foo
:
名称空间 bar
中的 Pod 可以通过 nslookup foo
查找到该 Service
名称空间 quux
中的 Pod 可以通过 nslookup foo.bar
查找到该 Service
DNS 服务器监视着创建新 Service
的 Kubernetes API,从而为每一个 Service
创建一组 DNS 记录。如果整个集群的 DNS 一直被启用,那么所有的 Pod
应该能够自动对 Service
进行名称解析
果整个集群的 DNS 一直被启用,那么所有的 Pod
应该能够自动对 Service
进行名称解析。
例如,有一个名称为 "my-service"
的 Service
,它在 Kubernetes 集群中名为 "my-ns"
的 Namespace
中,为 "my-service.my-ns"
创建了一条 DNS 记录。
在名称为 "my-ns"
的 Namespace
中的 Pod
应该能够简单地通过名称查询找到 "my-service"
。在另一个 Namespace
中的 Pod
必须限定名称为 "my-service.my-ns"
。这些名称查询的结果是 Cluster IP。
Kubernetes 也支持对端口名称的 DNS SRV(Service)记录。如果名称为 "my-service.my-ns"
的 Service
有一个名为 "http"
的 TCP
端口,可以对 "_http._tcp.my-service.my-ns"
执行 DNS SRV 查询,得到 "http"
的端口号。
Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName
类型的 Service 的方式。
Service(headless Service 除外)将被分配一个 DNS A 记录,格式为 my-svc.my-namespace.svc.cluster-domain.example
。该 DNS 记录解析到 Service 的 ClusterIP。
Headless Service(没有 ClusterIP)也将被分配一个 DNS A 记录,格式为 my-svc.my-namespace.svc.cluster-domain.example
。该 DNS 记录解析到 Service 所选中的一组 Pod 的 IP 地址的集合。调用者应该使用该 IP 地址集合,或者按照轮询(round-robin)的方式从集合中选择一个 IP 地址使用。
Service(含 headless Service)的命名端口(有 name 的端口)将被分配一个 SRV 记录,其格式为 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster-domain.example
:
对于一个普通 Service(非 headless Service),该 SRV 记录解析到其端口号和域名 my-svc.my-namespace.svc.cluster-domain.example
对于一个 Headless Service,该 SRV 记录解析到多个结果:每一个结果都对应该 Service 的一个后端 Pod,包含其端口号和 Pod 的域名 auto-generated-pod-name.my-svc.my-namespace.svc.cluster-domain.example
在每个节点上运行的 kubelet 代理会将 Pod 的 etc/resolv.conf
配置为使用 coredns
服务的 ClusterIP。如下图
Kubernetes 在创建 Pod 时,将 Pod 定义中的 metadata.name
的值作为 Pod 实例的 hostname。
Pod 定义中有一个可选字段 spec.hostname
可用来直接指定 Pod 的 hostname。例如,某 Pod 的 spec.hostname
字段被设置为 my-host
,则该 Pod 创建后 hostname 将被设为 my-host
Pod 定义中还有一个可选字段 spec.subdomain
可用来指定 Pod 的 subdomain。例如,名称空间 my-namespace
中,某 Pod 的 hostname 为 foo
,并且 subdomain 为 bar
,则该 Pod 的完整域名(FQDN)为 foo.bar.my-namespace.svc.cluster-domain.example
。
例子:
如果 Pod 所在名称空间中存在一个 headless Service,其名称与 Pod 的 subdomain 相同,则集群的 KubeDNS 服务器仍将为 Pod 的完整域名(FQDN)返回一个 A 记录。例如,假设一个 Pod 的 hostname 为 busybox-1
且其 subdomain 为 default-subdomain
,同名称空间下有一个 headless Service 的名字为 default-subdomain
,此时,该 Pod 的完整域名(FQDN)为 busybox-1.default-subdomain.my-namespace.svc.cluster-domain.example
。DNS 服务将其解析到一个 A 记录,指向 Pod 的 IP 地址。上面 yaml 文件中的 Pod busybox1
和 busybox2
都将有各自的 A 记录
备注
A 记录不是根据 Pod name 创建的,而是根据 hostname 创建的。如果一个 Pod 没有 hostname 只有 subdomain,则 Kubernetes 将只为其 headless Service 创建一个 A 记录 default-subdomain.my-namespace.svc.cluster-domain.example
,该记录指向 Pod 的 IP 地址。
Pod 必须达到就绪状态才可以拥有 A 记录,除非 Service 的字段 spec.publishNotReadyAddresses
被设置为 True
可以为每一个 Pod 设置其自己的 DNS Policy。Kubernetes 通过 Pod 定义中的 spec.dnsPolicy
字段设置 DNS Policy,可选的值有:
Default: Pod 从其所在的节点继承域名解析配置。更多细节请参考 Customizing DNS Service (opens new window)
ClusterFirst:任何与集群域名后缀(例如 www.kubernetes.io
)不匹配的 DNS 查询,都将被转发到 Pod 所在节点的上游 DNS 服务。集群管理员可能配置了额外的 stub-domain 及上游 DNS 服务,更多细节请参考 Customizing DNS Service (opens new window)
ClusterFirstWithHostNet: 对于运行在节点网络上的 Pod,其 dnsPolicy 必须指定为 ClusterFirstWithHostNet
None: 允许 Pod 忽略 Kubernetes 环境中的 DNS 设置。此时,该 Pod 的 DNS 的所有设置必须通过 spce.dnsConfig
指定。 参考 Pod 的 DNS 配置
dnsPolicy的默认值
“Default” 并非是默认的 DNS Policy。如果 spec.dnsPolicy
字段未指定,则 “ClusterFirst” 将被默认使用
卖座网都为Default 因为 kubelet将带有--cluster-dns=<dns-service-ip>
标志的DNS解析器信息传递到每个容器。
kubelet指定了--cluster-dns=10.96.0.10 --cluster-domain=cluster.local \
coredns中默认为deault
如果Pod'sdnsPolicy
设置为default
,它将从Pod运行所在的节点继承名称解析配置
如果您不希望这样做,或者想要对Pod使用其他DNS配置,则可以使用kubelet的--resolv-conf
标志。将此标志设置为“”可以防止Pod继承DNS。将其设置为有效的文件路径,以指定/etc/resolv.conf
用于DNS继承以外的文件
下面的例子中的 Pod,其 DNS Policy 必须设置为 “ClusterFirstWithHostNet”,因为它的 hostNetwork
字段为 true
Kuboard v1.0.8.3 开始,支持 Pod 的 dnsConfig 字段。配置界面在
工作负载编辑器 --> 容器组的更多设定
在 Kubernetes 中,您可以直接配置 Pod 的 DNS 设置。
Pod 定义中的 spec.dnsConfig
是可选字段,且可以与任何类型的 spec.dnsPolicy
配合使用。如果 spec.dnsPolicy
被设置为 “None”,则 spec.dnsConfig
必须被指定。
spec.dnsConfig
中有如下字段可以配置:
nameservers: Pod 的 DNS Server IP 地址列表。最多可以执行 3 个 IP 地址。当 spec.dnsPolicy
为 “None”,至少需要指定一个 IP 地址,其他情况下该字段是可选的。DNS Server 的 IP 地址列表将会与 DNS Policy 所产生的 DNS Server 地址列表合并(重复的条目被去除)。
searches:Pod 中执行域名查询时搜索域的列表。该字段是可选的。如果指定了该字段,则指定的搜索域列表将与 DNS Policy 所产生的搜索域列表合并(重复的条目被去除)。合并后的列表最多不超过 6 个域。
options:可选数组,其中每个元素由 name 字段(必填)和 value 字段(选填)组成。该列表中的内容将与 DNS Policy 所产生的 DNS 选项合并(重复的条目被去除)
上述 Pod 创建后,容器 test
的 etc/resolv.conf
文件如下所示(从 spec.dnsConfig
的配置产生),执行命令 kubectl exec -it dns-example -- cat /etc/resolv.conf
可查看该文件内容:
如果集群使用的是 IPv6,执行命令 kubectl exec -it dns-example -- cat /etc/resolv.conf
的输出结果如下所示:
Pod 定义中的 spec.dnsConfig
和 spec.dnsPolicy=None
的兼容性如下:
Kubernetes 版本号
支持情况
1.14
Stable
1.10
Beta(默认启用)
1.9
Alpha
CoreDNS是一个模块化且可插入的DNS服务器,每个插件都为CoreDNS添加了新功能。可以通过维护Corefile(即CoreDNS配置文件)进行配置。作为集群管理员,您可以修改 ConfigMap 让CoreDNS Corefile更改该群集的DNS服务发现行为。
在Kubernetes中,使用以下默认Corefile配置安装了CoreDNS:
Corefile配置包括以下CoreDNS插件:
错误:将错误记录到stdout。
健康:CoreDNS的运行状况报告给http://localhost:8080/health
。使用这种扩展语法,lameduck
将使进程运行不正常,然后等待5秒钟,然后再关闭进程。
ready:当所有能够发出信号准备就绪的插件都这样做时,端口8181上的HTTP端点将返回200 OK。
kubernetes:CoreDNS将基于Kubernetes的服务和Pod的IP答复DNS查询。您可以在CoreDNS网站上找到有关该插件的更多详细信息。ttl
允许您为响应设置自定义TTL。默认值为5秒。允许的最小TTL为0秒,最大为3600秒。将TTL设置为0将防止记录被缓存。提供
该pods insecure
选项是为了与kube-dns向后兼容。您可以使用此pods verified
选项,仅当在相同名称空间中存在具有匹配IP的容器时,该选项才返回A记录。pods disabled
如果您不使用pod记录,则可以使用该选项。
forward:任何不在Kubernetes集群域内的查询都将转发到预定义的解析器(/etc/resolv.conf)。
cache:这将启用前端缓存。
loop:检测简单的转发循环,如果发现循环,则暂停CoreDNS进程。
reload:允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟,以使更改生效。
loadbalance:这是一个轮询DNS负载均衡器,用于随机分配答案中A,AAAA和MX记录的顺序。
您可以通过修改ConfigMap来修改默认的CoreDNS行为。
普通的 Service:会生成servicename.namespace.svc.cluster.local
的域名,会解析到 Service 对应的 ClusterIP 上,在 Pod 之间的调用可以简写成 servicename.namespace
,如果处于同一个命名空间下面,甚至可以只写成 servicename 即可访问
Headless Service:无头服务,就是把 clusterIP 设置为 None 的,会被解析为指定 Pod 的 IP 列表,同样还可以通过podname.servicename.namespace.svc.cluster.local
访问到具体的某一个 Pod。
CoreDNS 实现的功能和 KubeDNS 是一致的,不过
CoreDNS
的所有功能都集成在了同一个容器中,在最新版的1.11.0版本中官方已经推荐使用 CoreDNS了
官方文档 https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
kuboard https://kuboard.cn/learning/k8s-intermediate/service/dns.html#pod-%E7%9A%84-dns-%E9%85%8D%E7%BD%AE
dns讲解:https://kubernetes.io/zh/docs/tasks/administer-cluster/dns-custom-nameservers/
明阳的博客:https://www.qikqiak.com/post/service-found-dns/
coredns原理:https://draveness.me/dns-coredns/