kubernetes dns 解析超时问题排查
Posted chen2ha
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes dns 解析超时问题排查相关的知识,希望对你有一定的参考价值。
文章目录
事故发起方
- 在客户内网机器环境内部署的 grafana 一直获取不到 prometheus 的数据,导致页面一直展示 no data
- 通过 grafana 页面测试 prometheus 数据源验证了这个问题,grafana 一直链接不上 prometheus 数据源
事故处理流程
grafana 容器访问 prometheus 的 svc
配置 curl-format 获取接口访问时间
time_namelookup
:DNS 解析时间
time_connect
:连接时间,从请求开始到 DNS 解析完毕所用时间。单纯的连接时间 = time_connect - time_namelookup
time_appconnect
:建立完成时间,例如 SSL/SSH 等建立连接或者完成三次握手的时间
time_redirect
:重定向时间,包括最后一次传输前的几次重定向的 DNS 解析、连接、预传输、传输时间
time_pretransfer
:从开始到准备传输的时间
time_starttransfer
:开始传输时间。在 client 发出请求后,服务端返回数据的第一个字节所用的时间
cat <<EOF> curl-format.txt
time_namelookup: %time_namelookup\\\\n
time_connect: %time_connect\\\\n
time_appconnect: %time_appconnect\\\\n
time_redirect: %time_redirect\\\\n
time_pretransfer: %time_pretransfer\\\\n
time_starttransfer: %time_starttransfer\\\\n
----------\\\\n
time_total: %time_total\\\\n
EOF
使用 clusterip 获取请求时间
获取 prometheus 的 svc 信息(这里理解逻辑就好,namespace 和 svc 的名字大家自己替换成自己的就好)
kubectl get svc -n tool | grep prometheus
返回结果类似下面的样子
prometheus-svc ClusterIP 10.102.38.55 <none> 9090/TCP 41d
/dev/null
表示空设备,即丢弃一切写入的数据,但显示写入操作成功-s
表示静默输出
curl -s -w "@curl-format.txt" \\
-o /dev/null \\
-l "http://10.102.38.55"
返回的结果如下,耗时非常的短
time_namelookup: 0.000
time_connect: 0.000
time_appconnect: 0.000
time_redirect: 0.000
time_pretransfer: 0.000
time_starttransfer: 0.001
----------
time_total: 0.001
使用 svc 域名获取请求时间
curl -s -w "@curl-format.txt" \\
-o /dev/null \\
-l "http://prometheus-svc.tool.svc.cluster.local"
返回结果如下,耗时 15秒之久
time_namelookup: 15.522
time_connect: 15.522
time_appconnect: 0.000
time_redirect: 0.000
time_pretransfer: 15.522
time_starttransfer: 15.523
----------
time_total: 15.523
容器内安装 bind-utils 工具
bind-utils 工具内有一个 host 命令,可以查看域名解析过程
host -v prometheus-svc.tool.svc.cluster.local
可以看到,总共尝试了五个域名,解析五次才达到我们需要使用的域名
Trying "prometheus-svc.tool.svc.cluster.local.tool.svc.cluster.local"
Trying "prometheus-svc.tool.svc.cluster.local.svc.cluster.local"
Trying "prometheus-svc.tool.svc.cluster.local.cluster.local"
Trying "prometheus-svc.tool.svc.cluster.local.openstacklocal"
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59444
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN A
;; ANSWER SECTION:
prometheus-svc.tool.svc.cluster.local. 5 IN A 10.102.38.55
Received 108 bytes from 10.96.0.10#53 in 0 ms
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26804
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN AAAA
;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1679994755 7200 1800 86400 30
Received 148 bytes from 10.96.0.10#53 in 0 ms
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2668
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN MX
;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1679994764 7200 1800 86400 30
Received 148 bytes from 10.96.0.10#53 in 0 ms
翻看一系列文档
k8s 官方文档中,看到一句话:
DNS 查询可以使用 Pod 中的
/etc/resolv.conf展开。 Kubelet 为每个 Pod 配置此文件。 例如,对
data的查询可能被展开为
data.test.svc.cluster.local。
search选项的取值会被用来展开查询。要进一步了解 DNS 查询,可参阅 resolv.conf 手册页面
在 resolv.conf 手册中,看到一个参数:
ndots:n
Sets a threshold for the number of dots which must appear in a name given to res_query(3) (see resolver(3)) before an initial absolute query will be made.
The default for n is 1, meaning that if there are any dots in a name, the name will be tried first as an absolute name before any search list elements are appended to it.
The value for this option is silently capped to 15.
- 意思就是,在进行绝对查询前,必须要为出现的点数设置一个阈值
- 这个阈值默认为1,意味着优先当前域名先做解析,也就是绝对查询
- 这个选项的值,默认上限为 15
分析 kubernetes svc 的域名结构
kubernetes 默认的 svc 域名结构为:
<svc-name>.<namespace>.svc.cluster.local
<pod-name>.<svc-name>.<namespace>.svc.cluster.local
可以看到,不带 pod 名称时,域名中有四个点,带 pod 名称时,域名中有五个点
在容器内,通过查看
/etc/resolv.conf
文件可以看到当前的ndots
设定的值
nameserver 10.96.0.10
search tool.svc.cluster.local svc.cluster.local cluster.local openstacklocal
options ndots:5
在容器内尝试访问来验证
host -v prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local
- 当域名内出现的点数和
ndots
设定的值一致时,走的绝对查询- 当域名内出现的点数小于
ndots
设定的值,就会走/etc/resolv.conf
文件内search
指定的 dns 服务器,并且逐一拼接到域名后面,最后才会进行绝对查询
Trying "prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local"
Received 175 bytes from 10.96.0.10#53 in 0 ms
Trying "prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local.tool.svc.cluster.local"
Trying "prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local.svc.cluster.local"
Trying "prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local.cluster.local"
Trying "prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local.openstacklocal"
Host prometheus-f9dd6964b-wzbk4.prometheus-svc.tool.svc.cluster.local.openstacklocal not found: 2(SERVFAIL)
Received 97 bytes from 10.96.0.10#53 in 2 ms
配置 pod 的 dnsConfig
既然问题出在
ndots
参数上,那就尝试修改 pod 的 yaml 文件,通过 kubernetes 官网可以看到 dns 相关的策略
- Pod 的 DNS 策略 [ 这些策略可以在 Pod 规约中的
dnsPolicy
字段设置 ]
Default
: Pod 从运行所在的节点继承名称解析配置ClusterFirst
: 与配置的集群域后缀不匹配的任何 DNS 查询(例如"www.kubernetes.io") 都会由 DNS 服务器转发到上游名称服务器。
- 集群管理员可能配置了额外的存根域和上游 DNS 服务器
ClusterFirstWithHostNet
: 对于以 hostNetwork 方式运行的 Pod,应将其 DNS 策略显式设置为ClusterFirstWithHostNet
- 否则,以 hostNetwork 方式和
ClusterFirst
策略运行的 Pod 将会做出回退至 “Default” 策略的行为- 注意:这在 Windows 上不支持
None
: 此设置允许 Pod 忽略 Kubernetes 环境中的 DNS 设置
- Pod 会使用其 dnsConfig 字段所提供的 DNS 设置
- Pod 的 DNS 配置 [
dnsConfig
字段是可选的,它可以与任何dnsPolicy
设置一起使用。 但是,当 Pod 的dnsPolicy
设置为 “None
” 时,必须指定dnsConfig
字段 ]
nameservers
:将用作于 Pod 的 DNS 服务器的 IP 地址列表。
- 最多可以指定 3 个 IP 地址
- 当 Pod 的
dnsPolicy
设置为 “None
” 时, 列表必须至少包含一个 IP 地址,否则此属性是可选的。- 所列出的服务器将合并到从指定的 DNS 策略生成的基本名称服务器,并删除重复的地址
searches
:用于在 Pod 中查找主机名的 DNS 搜索域的列表。
- 此属性是可选的
- 指定此属性时,所提供的列表将合并到根据所选 DNS 策略生成的基本搜索域名中
- 重复的域名将被删除
- Kubernetes 最多允许 6 个搜索域
options
:可选的对象列表,其中每个对象可能具有name
属性(必需)和value
属性(可选)
- 此属性中的内容将合并到从指定的 DNS 策略生成的选项
- 重复的条目将被删除
- 通过 dnsConfig 来控制 ndots 的值,可以先设定到 4 来验证
dnsConfig:
options:
- name: ndots
value: "4"
重启完容器后,再次进入容器查看
/etc/resolv.conf
文件的内容,可以看到 ndots 的值被修改成 4 了
nameserver 10.96.0.10
search tool.svc.cluster.local svc.cluster.local cluster.local openstacklocal
options ndots:4
继续用 host 命令查看域名解析过程
host -v prometheus-svc.tool.svc.cluster.local
可以看到,直接就走了绝对查询
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45608
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN A
;; ANSWER SECTION:
prometheus-svc.tool.svc.cluster.local. 30 IN A 10.102.38.55
Received 108 bytes from 10.96.0.10#53 in 0 ms
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10840
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN AAAA
;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1680002970 7200 1800 86400 30
Received 148 bytes from 10.96.0.10#53 in 0 ms
Trying "prometheus-svc.tool.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48585
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;prometheus-svc.tool.svc.cluster.local. IN MX
;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1680002961 7200 1800 86400 30
Received 148 bytes from 10.96.0.10#53 in 0 ms
用 curl 查看请求时间 [ 容器重启后,之前配置的 curl-format 记得重新生成一次 ]
curl -s -w "@curl-format.txt" \\
-o /dev/null \\
-l "http://prometheus-svc.tool.svc.cluster.local"
这个时候就跟吃了德福一样丝滑了
time_namelookup: 0.004
time_connect: 0.004
time_appconnect: 0.000
time_redirect: 0.000
time_pretransfer: 0.005
time_starttransfer: 0.006
----------
time_total: 0.006
这个时候,再去 grafana 去测试 prometheus 的数据源就不会报错了
09-kubernetes中的域名解析流程
参考技术A从Kubernetes 1.11版本开始,Kubernetes集群的DNS服务由CoreDNS提供。CoreDNS是CNCF基金会的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端。CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains设置,等等。
CoreDNS支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS。
CoreDNS没有使用多个容器的架构,只用一个容器便实现了KubeDNS内3个容器的全部功能。
从kubernetes官方提供的 coredns.yml 文件中,不难看出coredns服务配置至少需要一个ConfigMap、一个Deployment和一个Service共3个资源对象。ConfigMap coredns 主要配置文件Corefile的内容:
其中主要有二个地方来解析配置
1、这段配置的意思是cluster.local后缀的域名都是kubernetes内部域名,coredns会监控service的变化来修改域名的记录
2、如果coredns没有找到dns记录,则去找 /etc/resolv.conf 中的 nameserver 解析
接下来使用一个带有nslookup工具的Pod来验证DNS服务能否正常工作:
通过nslookup进行测试。
查找defaul命名空间存在的ng-deploy-80服务
如果某个Service属于不同的命名空间,那么在进行Service查找时,需要补充Namespace的名称,组合成完整的域名。下面以查找kubernetes-dashboard服务为例,
众所周知, DNS 服务器用于将域名转换为 IP (具体为啥要转换建议复习下 7 层网络模型). Linux 服务器中 DNS 解析配置位于 /etc/resolv.conf , 在 Pod 中也不例外,
DNS 策略可以逐个 Pod 来设定。当前kubernetes支持这4中DNS 策略
如果我们不填dnsPolicy, 默认策略就是 ClusterFirst 。
kubelet 在起 pause 容器的时候,会将其 DNS 解析配置初始化成集群内的配置。配置: 它的 nameserver 就是指向 coredns 的
k8s里面有4种DNS策略, 而coredns使用的DNS策略就是Default, 这个策略的意思就是继承宿主机上的/etc/resolve.conf, 所以coredns Pod 里面的/etc/resolve.conf 的内容就是宿主机上的内容。
在集群中 pod 之间互相用 svc name 访问的时候,会根据 resolv.conf 文件的 DNS 配置来解析域名,下面来分析具体的过程。
pod 的 resolv.conf 文件主要有三个部分,分别为 nameserver、search 和 option。而这三个部分可以由 K8s 指定,也可以通过 pod.spec.dnsConfig 字段自定义。
nameserver
resolv.conf 文件的第一行 nameserver 指定的是 DNS 服务的 IP,这里就是 coreDNS 的
clusterIP:
也就是说所有域名的解析,都要经过coreDNS的虚拟IP 10.100.0.2 进行解析, 不论是内部域还是外部域名。
search 域
resolv.conf 文件的第二行指定的是 DNS search 域。解析域名的时候,将要访问的域名依次带入 search 域,进行 DNS 查询。
比如我要在刚才那个 pod 中访问一个域名为 ng-deploy-80的服务,其进行的 DNS 域名查询的顺序是:
options
resolv.conf 文件的第三行指定的是其他项,最常见的是 dnots。dnots 指的是如果查询的域名包含的点 “.” 小于 5,则先走 search 域,再用绝对域名;如果查询的域名包含点数大于或等于 5,则先用绝对域名,再走 search 域。K8s 中默认的配置是 5。
也就是说,如果我访问的是 a.b.c.e.f.g ,那么域名查找的顺序如下:
通过 svc 访问
在 K8s 中,Pod 之间通过 svc 访问的时候,会经过 DNS 域名解析,再拿到 ip 通信。而 K8s 的域名全称为 "<service-name>.<namespace>.svc.cluster.local",而我们通常只需将 svc name 当成域名就能访问到 pod,这一点通过上面的域名解析过程并不难理解。
参考
(1)K8S落地实践 之 服务发现(CoreDNS)
https://blog.51cto.com/u_12965094/2641238
(2)自定义 DNS 服务
https://kubernetes.io/zh/docs/tasks/administer-cluster/dns-custom-nameservers/
(3)Kubernetes 服务发现之 coreDNS
https://juejin.cn/post/6844903965520297991
(4)Kubernetes 集群 DNS 服务发现原理
https://developer.aliyun.com/article/779121
(5)Kubernetes之服务发现和域名解析过程分析
https://www.jianshu.com/p/80ad7ff37744
以上是关于kubernetes dns 解析超时问题排查的主要内容,如果未能解决你的问题,请参考以下文章