k3s的Pod无法解析内网域名
问题
jetson tx2开发板上安装了docker
和k3s
,部署了一个pod,发现日志报错
1 |
|
其中esmp-cloud-sync.dev.ennew.com
是内网域名,说明pod无法解析该域名。
但是宿主机上能ping通该域名。
环境
- os : ubuntu18.04
- k3s: v1.18.9+k3s1
- cpu arch : arm64
- coreDNS: 1.6.9
排查过程
首先检查宿主机的域名服务器设置。 如果不正常,则需要设置正确的域名服务器。并重启k3s服务和pod。 如果正常,则进一步检查k3s的DNS设置。而k3s的网络域名解析是由coreDNS控制的。
查看宿主机的DNS设置
宿主机的DNS设置,查看/etc/resolv.conf
$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.
nameserver 127.0.0.53
search addom.xinaogroup.com
运行”systemd-resolve –status”查看实际的nameservers。
$ systemd-resolve --status
...
DNS Servers: 10.36.8.40
10.36.8.41
127.0.0.1
DNS Domain: ~.
addom.xinaogroup.com
...
可以看到实际的域名服务器。pod里无法ping通的域名esmp-cloud-sync.dev.ennew.com
,在宿主机环境是可以的。
查看pod的DNS设置
pod的DNS设置是由CoreDNS
控制的。但是进入CoreDNS的pod,使用kubectl exec
是不行的。需要使用边车模式,
先查看运行CoreDNS的容器的ID,然后用docker再启动一个容器。(因为k3s server是基于dockerd运行的,所以
可以用docker ps查看CoreDNS pod里的容器)
docker ps | grep coredns
ID=8afb33b91c9f
docker run -it --net=container:$ID --pid=container:$ID --volumes-from=$ID alpine sh
然后就可以查看CoreDNS的corefile配置文件
# cat /etc/coredns/Corefile
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
hosts /etc/coredns/NodeHosts {
reload 1s
fallthrough
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
从forward . /etc/resolv.conf
可以看出,由/etc/resolv.conf
文件接管DNS设置。进一步查看该文件,
# cat /etc/resolv.conf
nameserver 8.8.8.8
可以发现这里设置的nameserver
是8.8.8.8
,而不是10.36.8.40
。因此在pod里虽然可以ping通公网域名
,例如www.baidu.com
,但是无法ping通内网域名esmp-cloud-sync.dev.ennew.com
另外查看CoreDNS的pod日志也可以看到无法解析内网域名esmp-cloud-sync.dev.ennew.com
的错误。
分析问题
从排查结果可以看到,主要问题在于CoreDNS的DSN设置与宿主机的DNS设置不同,导致解析内网域名解析失败。这一点比较奇怪,通常k3s默认 会继承宿主机的DNS设置。
也就是pod里的/etc/resolv.conf
,没有与宿主机的/etc/resolv.conf
的内容一致。
再回头看看我们要解决的问题——pod里解析内网域名,那么最直接的方案就是修改CoreDNS的Corefile,
修改forward . /etc/resolv.conf
为forward . 10.36.8.40
但是这种方法的缺点是显而易见的,写死了。 我们还是希望找到一个方法能够令/etc/resolv.conf
与宿主机的/etc/resolv.conf
的内容一致
解决方法
宿主机的/etc/resolv.conf
文件是一个指向 /run/systemd/resolve/resolv.conf
的软链接,查看该文件的内容
$ cat /run/systemd/resolve/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 10.36.8.40
nameserver 10.36.8.41
nameserver 127.0.0.1
search addom.xinaogroup.com
可以看到含有正确的nameservers。
另外 k3s 有启动参数--resolv-conf
,可以指定默认的resolv.conf
。
修改/etc/systemd/system/k3s.service
,增加启动参数--resolv-conf /run/systemd/resolve/resolv.conf
...
ExecStart=/usr/local/bin/k3s \
server \
'--docker' \
'--write-kubeconfig' \
'/home/tx2/.kube/config' \
'--write-kubeconfig-mode' \
'666' \
'--resolv-conf' \
'/run/systemd/resolve/resolv.conf'
然后重新启动k3s,并且删除CoreDNS的pod(kubectl delete pod -n kube-system coredns-xxxx
),令其自动创建一个新的pod。
这时候再查看CoreDNS pod里的/etc/resolv.conf, 内容一致了,
/ # cat /etc/resolv.conf
nameserver 10.36.8.40
nameserver 10.36.8.41
nameserver 127.0.0.1
search addom.xinaogroup.com
问题解决了。