部署好k8s 集群后,calico 和coredns 都是Running 状态,但是测试ping www.baidu.com
的时候,就老是报错
/ # ping www.baidu.com
ping: bad address 'www.baidu.com'
但是在/etc/resolve.conf 文件后增加了 nameserver 223.5.5.5 之后,他好像就可以解析了,但是k8s 内部的仍然不能解析:
curl -ik https://kubernetes
为了探针是否为DNS问题,需要提前部署用于测试DNS问题的dnsutils镜像,该镜像中包含了用于测试DNS问题的工具包,非常利于我们分析与发现问题
[root@k8s01 ~]# cat ndsutils.yaml
apiVersion: v1
kind: Pod
metadata:
name: dnsutils
spec:
containers:
- name: dnsutils
image: mydlqclub/dnsutils:1.3
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
[root@k8s01 ~]# kubectl create -f ndsutils.yaml -n kube-system
上面DNS工具已经部署完成,可也通过Kubectl工具进入Pod命令行,然后使用里面的一些工具进行问题分析
exec:让指定 Pod 容器执行某些命令
-i:将控制台内容传入到容器
-t:进入容器的 tty 使用 bash 命令行
-n:指定上面部署 DNS Pod 所在的 Namespace
[root@k8s01 ~]# kubectl exec -it dnsutils /bin/sh -n kube-system
使用 ping 命令来分别探测观察是否能够 ping 通集群内部和集群外部的地址,观察到的:
#Ping 集群外部,例如这里 ping 一下百度
/ # ping www.baidu.com
ping: bad address 'www.baidu.com'
#Ping集群内部kube-apiserver的Service地址
/ # ping kubernetes.default
ping: bad address 'kubernetes.default'
#使用nslookup命令查询域名信息
/ # nslookup kubernetes.default
;; connection timed out; no servers could be reached
#直接Ping集群内部kube-apiserver的IP地址
/ # ping 10.96.0.1
PING 10.96.0.1 (10.96.0.1): 56 data bytes
64 bytes from 10.96.0.1: seq=0 ttl=64 time=0.096 ms
64 bytes from 10.96.0.1: seq=1 ttl=64 time=0.050 ms
64 bytes from 10.96.0.1: seq=2 ttl=64 time=0.068 ms
#退出dnsutils Pod命令行
/ # exit
观察到两次ping域名都不能 ping 通,且使用nsloopup分析域名信息时超时。使用ping kube-apiserver的IP地址"10.96.0.1"则可以正常通信,排除网络插件(flannel、calico 等)的问题,初步判断很可能是CoreDNS组件的错误引起的某些问题,所以接下来测试 CoreDNS是否正常
检查 CoreDNS Pod 是否正在运行,如果READY 0,则显示CoreDNS组件有问题
[root@k8s01 ~]# kubectl get pods -l k8s-app=kube-dns -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-669f77d7cc-8pkpw 1/1 Running 2 6h5m
coredns-669f77d7cc-jk9wk 1/1 Running 2 6h5m
看到CoreDNS两个Pod均正常启动,再查看两个Pod中的日志信息,看看有无错误日志
[root@k8s01 ~]# for p in $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name); \
do kubectl logs --namespace=kube-system $p; done
.:53
[INFO] plugin/reload: Running configuration MD5 = 4e235fcc3696966e76816bcd9034ebc7
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
.:53
[INFO] plugin/reload: Running configuration MD5 = 4e235fcc3696966e76816bcd9034ebc7
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
通过上面信息可以观察到,日志中信息也是正常启动没有问题,查看下CoreDNS的入口 Service “kube-dns” 是否存在
[root@k8s01 ~]# kubectl get service -n kube-system | grep kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kube-dns ClusterIP 10.96.0.2 <none> 53/UDP,53/TCP,9153/TCP
kube-dns的IP 为 10.96.0.2,集群内的 Pod 都是通过该IP与DNS组件进行交互,查询 DNS信息 上面显示 Service “kube-dns” 也存在,但是 Service 是通过 endpoints 和 Pod 进行绑定的,所以看看这个CoreDNS的endpoints 是否存在及信息是否正确
[root@k8s01 ~]# kubectl get endpoints kube-dns -n kube-system
NAME ENDPOINTS AGE
kube-dns 10.244.230.193:53,10.244.247.65:53,10.244.230.193:53 + 3 more... 26h
可以看到 endpoints 配置也是正常的,正确的与两个 CporeDNS Pod 进行了关联
修改存储于Kubernetes ConfigMap中的CoreDNS配置参数信息,添加log参数,让 CoreDNS日志中显示域名解析信息 CoreDNS 配置参数说明:
#编辑 coredns 配置
[root@k8s01 ~]# kubectl edit configmap coredns -n kube-system
apiVersion: v1
data:
Corefile: |
.:53 {
log #添加log
errors
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
}
保存更改后CoreDNS会自动重新加载配置信息,不过可能需要等上一两分钟才能将这些更改传播到CoreDNS Pod,等一段时间后再次查看CoreDNS日志
[root@k8s01 ~]# for p in $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name); \
do kubectl logs --namespace=kube-system $p; done
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] 127.0.0.1:47278 - 55171 "HINFO IN 4940754309314083739.5160468069505858354. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.040844011s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
[INFO] 127.0.0.1:32896 - 49064 "HINFO IN 1027842207973621585.7098421666386159336. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.044098742s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
可以看到CoreDNS已经重新加载了配置,再次进入dnsuitls Pod中执行ping命令
#进入 DNSutils Pod 命令行
[root@k8s01 ~]# kubectl exec -it dnsutils /bin/sh -n kube-system
#执行 ping 命令
/ # ping www.baidu.com
#退出 dnsutils Pod 命令行
/ # exit
再次查看CoreDNS 的日志信息
[root@k8s01 ~]# for p in $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name); \
do kubectl logs --namespace=kube-system $p; done
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] 127.0.0.1:47278 - 55171 "HINFO IN 4940754309314083739.5160468069505858354. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.040844011s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
[INFO] 127.0.0.1:32896 - 49064 "HINFO IN 1027842207973621585.7098421666386159336. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.044098742s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
发现和之前没有执行 ping 命令时候一样,没有 DNS 域名解析的日志信息,说明Pod执行域名解析时,请求并没有进入CoreDNS中。接下来在查看Pod中DNS配置信息进而分析问题
Pod中的DNS策略默认为ClusterFirst,该参数起到的作用是,优先从Kubernetes DNS插件地址读取DNS配置,所以正常创建的Pod中,DNS配置DNS服务器地址应该指定为 Kubernetes集群的DNS插件Service提供的虚拟IP地址 其中DNS策略(dnsPolicy)支持四种类型:
Default: 从 DNS 所在节点继承 DNS 配置,即该 Pod 的 DNS 配置与宿主机完全一致
ClusterFirst:预先 Kubenetes的DNS插件中进行DNS解析,如果解析不成功,才会使用宿主机的DNS进行解析
ClusterFirstWithHostNet:Pod是用HOST模式启动的(hostnetwork),用 HOST模式表示Pod中的所有容器,都使用宿主机的 /etc/resolv.conf 配置进行 DNS解析,但如果使用了HOST模式,还继续使用Kubernetes的DNS服务,那就将dnsPolicy设置为ClusterFirstWithHostNet
None:完全忽略kubernetes系统提供的DNS,以Pod Spec中dnsConfig配置为主
进入dnsutils Pod中,查看Pod中DNS配置文件/etc/resolv.conf配置参数是否正确 resolv.conf 配置参数说明:
search: 指明域名查询顺序
nameserver: 指定 DNS 服务器的 IP 地址,可以配置多个 nameserver
#进入 dnsutils Pod 内部 sh 命令行
[root@k8s01 ~]# kubectl exec -it dnsutils /bin/sh -n kube-system
## 查看 resolv.conf 配置文件
/ # cat /etc/resolv.conf
nameserver 10.96.0.2
search kube-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
#退出 DNSutils Pod 命令行
/ # exit
可以看到Pod内部的resolv.conf 内容,其中nameserver指定DNS解析服务器IP为 “10.96.0.2” ,这个IP地址正是Kubernetes集群CoreDNS的Service “kube-dns” 的 cluterIP,说明当Pod内部进行域名解析时,确实是将查询请求发送到Service “kube-dns” 提供的虚拟IP进行域名解析 既然Pod 中 DNS配置文件没问题,且CoreDNS也没问题,会不会是Pod本身域名解析不正常呢?或者Service “kube-dns” 是否能够正常转发域名解析请求到CoreDNS Pod中
怀疑是Pod本身解析域名有问题,不能正常解析域名。或者Pod没问题,但是请求域名解析时将请求发送到Service “kube-dns” 后不能正常转发请求到CoreDNS Pod,为了验证这两点,可以修改Pod中的 /etc/resolv.conf 配置来进行测试验证 修改 resolv.conf 中DNS解析请求地址为阿里云DNS服务器地址,然后执 ping命令验证是否为Pod解析域名是否有问题
##进入dnsutils Pod内部sh命令行
[root@k8s01 ~]# kubectl exec -it dnsutils /bin/sh -n kube-system
#编辑/etc/resolv.conf 文件,修改 nameserver 参数为阿里云提供的 DNS 服务器地址
/ # vi /etc/resolv.conf
nameserver 223.5.5.5
#nameserver 10.96.0.10
search kube-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
#修改完后再进行 ping 命令测试,看看是否能够解析baidu.com网址
/ # ping baidu.com
PING baidu.com (220.181.38.148): 56 data bytes
64 bytes from 220.181.38.148: seq=0 ttl=48 time=31.029 ms
64 bytes from 220.181.38.148: seq=1 ttl=48 time=31.102 ms
64 bytes from 220.181.38.148: seq=2 ttl=48 time=31.097 ms
64 bytes from 220.181.38.148: seq=3 ttl=48 time=30.999 ms
#退出 DNSutils Pod 命令行
/ # exit
观察到Pod中更换DNS服务器地址后,域名解析正常,说明Pod本身域名解析是没有问题的 接下来再修改resolv.conf 中DNS解析请求地址为CoreDNS Pod的IP地址,这样让Pod直接连接CoreDNS Pod的IP,而不通过Service进行转发,再进行ping命令测试,进而判断 Service kube-dns是否能够正常转发请求到CoreDNS Pod的问题:
#查看CoreDNS Pod的IP地址
[root@k8s01 ~]# kubectl get pods -n kube-system -o wide | grep coredns
coredns-669f77d7cc-rss5f 1/1 Running 0 10.244.2.155 k8s-node-1
coredns-669f77d7cc-rt8l6 1/1 Running 0 10.244.1.163 k8s-node-2
#进入dnsutils Pod内部sh命令行
/ # kubectl exec -it dnsutils /bin/sh -n kube-system
#编辑 /etc/resolv.conf文件,修改nameserver参数为阿里云提供的DNS服务器地址
/ # vi /etc/resolv.conf
nameserver 10.244.2.155
nameserver 10.244.1.163
#nameserver 10.96.0.10
search kube-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
## 修改完后再进行 ping 命令测试,看看是否能够解析 www.mydlq.club 网址
/ # ping baidu.com
PING baidu.com (220.181.38.148): 56 data bytes
64 bytes from 220.181.38.148: seq=0 ttl=48 time=31.029 ms
64 bytes from 220.181.38.148: seq=1 ttl=48 time=31.102 ms
64 bytes from 220.181.38.148: seq=2 ttl=48 time=31.097 ms
64 bytes from 220.181.38.148: seq=3 ttl=48 time=30.999 ms
#退出 DNSutils Pod命令行
/ # exit
#观察CoreDNS日志信息,查看有无域名解析相关日志
[root@k8s01 ~]# for p in $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name); \
do kubectl logs --namespace=kube-system $p; done
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] 127.0.0.1:47278 - 55171 "HINFO IN 4940754309314083739.5160468069505858354. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.040844011s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
[INFO] 10.244.1.162:40261 - 21083 "AAAA IN www.baidu.com.kube-system.svc.cluster.local. udp 62 false 512" NXDOMAIN qr,aa,rd 155 0.000398875s
[INFO] 10.244.1.162:40261 - 20812 "A IN www.baidu.com.kube-system.svc.cluster.local. udp 62 false 512" NXDOMAIN qr,aa,rd 155 0.000505793s
[INFO] 10.244.1.162:55066 - 53460 "AAAA IN www.baidu.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000215384s
[INFO] 10.244.1.162:55066 - 53239 "A IN www.baidu.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000267642s
.:53
[INFO] plugin/reload: Running configuration MD5 = 6434d0912b39645ed0707a3569fd69dc
CoreDNS-1.6.7
linux/amd64, go1.13.6, da7f65b
[INFO] Reloading
[INFO] plugin/health: Going into lameduck mode for 5s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
[INFO] 127.0.0.1:32896 - 49064 "HINFO IN 1027842207973621585.7098421666386159336. udp 57 false 512" NXDOMAIN qr,rd,ra 57 0.044098742s
[INFO] plugin/reload: Running configuration MD5 = a4809ab99f6713c362194263016e6fac
[INFO] Reloading complete
[INFO] 10.244.1.162:40261 - 21083 "AAAA IN www.baidu.com.kube-system.svc.cluster.local. udp 62 false 512" NXDOMAIN qr,aa,rd 155 0.000217299s
[INFO] 10.244.1.162:40261 - 20812 "A IN www.baidu.com.kube-system.svc.cluster.local. udp 62 false 512" NXDOMAIN qr,aa,rd 155 0.000264552s
[INFO] 10.244.1.162:55066 - 53460 "AAAA IN www.baidu.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000144795s
[INFO] 10.244.1.162:55066 - 53239 "A IN www.baidu.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.00
经过上面两个测试,已经可以得知如果 Pod DNS配置中直接修改DNS服务器地址为 CoreDNS Pod的IP地址,DNS解析确实没有问题,能够正常解析。不过正常的情况下 Pod中DNS配置的服务器地址一般是CoreDNS的Service地址,不直接绑定Pod IP(因为 Pod 每次重启IP都会发生变化), 所以问题找到了,正是在Pod向CoreDNS的Service “kube-dns” 进行域名解析请求转发时出现了问题,一般Service的问题都跟Kube-proxy组件有关,接下来观察该组件是否存在问题
观察kube-proxy的日志,查看是否存在问题
#查看kube-proxy Pod列表
[root@k8s01 ~]# kubectl get pods -n kube-system | grep kube-proxy
kube-proxy-6kdj2 1/1 Running 3 9h
kube-proxy-lw2q6 1/1 Running 3 9h
kube-proxy-mftlt 1/1 Running 3 9h
#选择一个kube-proxy Pod,查看最后5条日志内容
[root@k8s01 ~]# kubectl logs kube-proxy-6kdj2 --tail=5 -n kube-system
E0326 15:20:23.159364 1 proxier.go:1950] Failed to list IPVS destinations, error: parseIP Error ip=[10 96 0 10 0 0 0 0 0 0 0 0 0 0 0 0]
E0326 15:20:23.159388 1 proxier.go:1192] Failed to sync endpoint for service: 10.8.0.10:53/UPD, err: parseIP Error ip=[10 96 0 16 0 0 0 0 0 0 0 0 0 0 0 0]
E0326 15:20:23.159479 1 proxier.go:1950] Failed to list IPVS destinations, error: parseIP Error ip=[10 96 0 10 0 0 0 0 0 0 0 0 0 0 0 0]
E0326 15:20:23.159501 1 proxier.go:1192] Failed to sync endpoint for service: 10.8.0.10:53/TCP, err: parseIP Error ip=[10 96 0 16 0 0 0 0 0 0 0 0 0 0 0 0]
E0326 15:20:23.159595 1 proxier.go:1950] Failed to list IPVS destinations, error: parseIP Error ip=[10 96 0 10 0 0 0 0 0
通过 kube-proxy Pod的日志可以看到,里面有很多Error 级别的日志信息,根据关键字 IPVS、parseIP Error 可知可能是由于IPVS模块对IP进行格式化导致出现问题,因为这个问题是升级到kubernetes 1.18版本才出现的,所以去Kubernetes Github查看相关issues,发现有人在升级Kubernetes版本到1.18后,也遇见了相同的问题,经过issue 中Kubernetes维护人员讨论,分析出原因可能为新版Kubernetes使用的IPVS模块是比较新的,需要系统内核版本支持,这里使用的是CentOS系统,内核版本为3.10,里面的 IPVS模块比较老旧,缺少新版Kubernetes IPVS所需的依赖,根据该 issue 讨论结果,解决该问题的办法是,更新内核为新的版本 issues地址:
https://github.com/kubernetes/kubernetes/issues/89520
升级Kubernetes集群各个节点的CentOS系统内核版本
#载入公钥
[root@k8s01 ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
#安装 ELRepo 最新版本
[root@k8s01 ~]# yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
#列出可以使用的 kernel 包版本
$ yum list available --disablerepo=* --enablerepo=elrepo-kernel
#安装指定的 kernel 版本:
[root@k8s01 ~]# yum install -y kernel-lt-4.4.218-1.el7.elrepo --enablerepo=elrepo-kernel
#查看系统可用内核
[root@k8s01 ~]# cat /boot/grub2/grub.cfg | grep menuentry
menuentry 'CentOS Linux (3.10.0-1062.el7.x86_64) 7 (Core)' --class centos (略)
menuentry 'CentOS Linux (4.4.218-1.el7.elrepo.x86_64) 7 (Core)' --class centos ...(略)
#设置开机从新内核启动
[root@k8s01 ~]# grub2-set-default "CentOS Linux (4.4.218-1.el7.elrepo.x86_64) 7 (Core)"
#查看内核启动项
[root@k8s01 ~]# grub2-editenv list
saved_entry=CentOS Linux (4.4.218-1.el7.elrepo.x86_64) 7 (Core)
重启系统使内核生效
[root@k8s01 ~]# reboot
启动完成查看内核版本是否更新
[root@k8s01 ~]# uname -r
4.4.218-1.el7.elrepo.x86_64
进入Pod内部使用ping命令测试DNS是否能正常解析
#进入 dnsutils Pod 内部 sh 命令行
[root@k8s01 ~]# kubectl exec -it dnsutils /bin/sh -n kube-system
## Ping集群外部,例如这里ping一下百度
/ # ping www.baidu.com
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=1 ttl=127 time=7.20 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=2 ttl=127 time=6.60 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=3 ttl=127 time=6.38 ms
#Ping集群内部kube-api的Service地址
/ # ping kubernetes.default
64 bytes from kubernetes.default.svc.cluster.local (10.96.0.1): icmp_seq=1 ttl=64 time=0.051 ms
64 bytes from kubernetes.default.svc.cluster.local (10.96.0.1): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from kubernetes.default.svc.cluster.local (10.96.0.1): icmp_seq=3 ttl=64 time=0.064 ms
可以看到Pod中的域名解析已经恢复正常