参看此篇章前可先查看记录一次k3s网络DNS问题排查

参考:

https://v1-24.docs.kubernetes.io/zh-cn/docs/tasks/administer-cluster/nodelocaldns/

https://www.suse.com/support/kb/doc/?id=000020174

https://stackoverflow.com/questions/70913822/kubernetes-k3s-pod-gets-enotfound-after-5-20-hours-of-airing-time

https://icode.best/i/10017745505921

https://hub.docker.com/r/dyrnq/k8s-dns-node-cache/tags

https://github.com/coredns/deployment/blob/master/kubernetes/Scaling_CoreDNS.md

https://lework.github.io/2020/11/09/node-local-dns/

简介

NodeLocal DNSCache 通过在集群节点上运行一个 DaemonSet 来提高 clusterDNS 性能和可靠性。处于 ClusterFirst 的 DNS 模式下的 Pod 可以连接到 kube-dns 的 serviceIP 进行 DNS 查询。通过 kube-proxy 组件添加的 iptables 规则将其转换为 CoreDNS 端点。

通过在每个集群节点上运行 DNS 缓存,NodeLocal DNSCache 可以缩短 DNS 查找的延迟时间、使 DNS 查找时间更加一致,以及减少发送到 kube-dns 的 DNS 查询次数。

在集群中运行 NodeLocal DNSCache 有如下几个好处:

  • 如果本地没有 CoreDNS 实例,则具有最高 DNS QPS 的 Pod 可能必须到另一个节点进行解析,使用 NodeLocal DNSCache 后,拥有本地缓存将有助于改善延迟
  • 跳过 iptables DNAT 和连接跟踪将有助于减少 conntrack 竞争并避免 UDP DNS 条目填满 conntrack 表(常见的5s超时问题就是这个原因造成的)
  • 从本地缓存代理到 kube-dns 服务的连接可以升级到 TCP,TCP conntrack 条目将在连接关闭时被删除,而 UDP 条目必须超时(默认 nf_conntrack_udp_timeout 是 30 秒)
  • 将 DNS 查询从 UDP 升级到 TCP 将减少归因于丢弃的 UDP 数据包和 DNS 超时的尾部等待时间,通常长达 30 秒(3 次重试+ 10 秒超时)

要安装 NodeLocal DNSCache 也非常简单,直接获取官方的资源清单即可:

1
$ wget https://github.com/kubernetes/kubernetes/raw/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml

该资源清单文件中包含几个变量,其中:

  • __PILLAR__DNS__SERVER__ :表示 kube-dns 这个 Service 的 ClusterIP,可以通过命令 kubectl get service --namespace kube-system kube-dns -o jsonpath='{.spec.clusterIP}' 获取
  • __PILLAR__LOCAL__DNS__:表示 DNSCache 本地的 IP,默认为 169.254.20.10,该地址可以是任何地址,只要该地址不和你的集群里现有的 IP 地址发生冲突。 推荐使用本地范围内的地址,例如 IPv4 链路本地区段 169.254.0.0/16 内的地址(默认一般取 169.254.20.10 即可
  • __PILLAR__DNS__DOMAIN__:表示集群域,默认就是 cluster.local

部署

kube-proxy为iptables模式

另外还有两个参数 __PILLAR__CLUSTER__DNS____PILLAR__UPSTREAM__SERVERS__,镜像 1.15.6 版本以上这两个参数会自动进行配置,对应的值来源于 kube-dns 的 ConfigMap 和定制的 Upstream Server 配置。直接执行如下所示的命令即可安装:

registry.k8s.io墙内可能下载不下来, 所以可以选择将其替换成docker源dyrnq

地址: https://hub.docker.com/r/dyrnq/k8s-dns-node-cache/tags

1
2
3
4
5
6
cat nodelocaldns.yaml \
| sed -e "s/registry.k8s.io\/dns/dyrnq/g" \
| sed -e "s/__PILLAR__DNS__DOMAIN__/cluster.local/g" \
| sed -e "s/__PILLAR__DNS__SERVER__/$(kubectl get service --namespace kube-system kube-dns -o jsonpath='{.spec.clusterIP}')/g" \
| sed -e "s/__PILLAR__LOCAL__DNS__/169.254.20.10/g" \
| kubectl apply -f -

可以通过如下命令来查看对应的 Pod 是否已经启动成功:

1
2
3
4
5
6
7
$ kubectl get pods -n kube-system | grep node-local-dns
node-local-dns-8zm2f 1/1 Running 0 9m54s
node-local-dns-dd4xg 1/1 Running 0 9m54s
node-local-dns-hs8qq 1/1 Running 0 9m54s
node-local-dns-pxfxn 1/1 Running 0 9m54s
node-local-dns-stjm9 1/1 Running 0 9m54s
node-local-dns-wjxvz 1/1 Running 0 9m54s

iptables 模式下 Pod 还是向原来的集群 DNS 请求,节点上有这个 IP 监听,会被本机拦截,再请求集群上游 DNS,所以不需要更改 --cluster-dns 参数。

需要注意的是这里使用 DaemonSet 部署 node-local-dns 使用了 hostNetwork=true,会占用宿主机的 8080 端口,所以需要保证该端口未被占用。

kube-proxy为ipvs模式

当kube-proxy为ipvs模式, 则需要进行如下调整

1
2
3
4
5
6
cat nodelocaldns.yaml \
| sed -e "s/registry.k8s.io\/dns/dyrnq/g" \
| sed -e "s/,__PILLAR__DNS__SERVER__//g" \
| sed -e "s/__PILLAR__DNS__SERVER__/$(kubectl get service --namespace kube-system kube-dns -o jsonpath='{.spec.clusterIP}')/g" \
| sed -e "s/__PILLAR__LOCAL__DNS__/169.254.20.10/g" \
| kubectl apply -f -

在此模式下,node-local-dns Pods 只会侦听 <node-local-address>的地址。 node-local-dns 接口不能绑定 kube-dns 的集群 IP 地址,因为 IPVS 负载均衡 使用的接口已经占用了该地址。 node-local-dns Pods 会设置 __PILLAR__UPSTREAM__SERVERS__

我们还需要修改 kubelet 的 --cluster-dns 参数,将其指向 169.254.20.10Daemonset 会在每个节点创建一个网卡来绑这个 IP,Pod 向本节点这个 IP 发 DNS 请求,缓存没有命中的时候才会再代理到上游集群 DNS 进行查询。

**关于 iptables 模式为什么不需要修改--cluster-dns**:Daemonset 会在每个节点创建一个网卡来绑这个 IP,Pod 向本节点这个 IP 发 DNS 请求,缓存没有命中的时候才会再代理到上游集群 DNS 进行查询。 iptables 模式下 Pod 还是向原来的集群 DNS 请求,节点上有这个 IP 监听,会被本机拦截,再请求集群上游 DNS,所以不需要更改 --cluster-dns 参数。

使用

如果希望使用上node-local-dns的解析,有两种设置方式:

  1. 单独配置 Pod 的 dnsconfig
  2. 配置 kubelet的 cluster-dns

单独配置 Pod 的 dnsconfig

使用此方法,仅针对某个pod设置,不影响其他组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Pod
metadata:
name: test-node-local-dns
spec:
containers:
- name: local-dns
image: busybox:glibc
command: ["/bin/sh", "-c", "sleep 60m"]
dnsPolicy: "None"
dnsConfig:
nameservers:
- 169.254.20.10
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "2"

配置 kubelet 的 cluster-dns

使用此方法,生效的对象则是kubelet所管理的所有pod,但需要重启 kubelet

如果使用的是 kubeadm 安装的 1.16 版本的集群,只需要替换节点上 /var/lib/kubelet/config.yaml 文件中的 clusterDNS 这个参数值,然后重启即可,我们也可以完全在官方的 DaemonSet 资源对象中添加一个 initContainer 来完成这个工作:

替换10.96.0.10$(kubectl get service --namespace kube-system kube-dns -o jsonpath='{.spec.clusterIP}')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
initContainers:  # ipvs模式下需要修改dns配置,重启kubelet
- name: setup
image: alpine
tty: true
stdin: true
securityContext:
privileged: true
command:
- nsenter
- --target
- "1"
- --mount
- --uts
- --ipc
- --net
- --pid
- --
- bash
- -c
- |
# 确保 kubelet --cluster-dns 被设置为 169.254.20.10
echo "Configuring kubelet --cluster-dns=169.254.20.10"
sed -i 's/10.96.0.10/169.254.20.10/g' /var/lib/kubelet/config.yaml
systemctl daemon-reload && systemctl restart kubelet

但是需要注意的是对于线上环境还是不推荐用上面的方式,因为它会优先将 kubelet 的 cluster-dns 参数进行修改,然后再去安装 NodeLocal,这中间毕竟有一段真空期,我们完全可以手动去一个节点一个节点验证:

1
2
$ sed -i 's/10.96.0.10/169.254.20.10/g' /var/lib/kubelet/config.yaml
$ systemctl daemon-reload && systemctl restart kubelet

验证

Iptables OUTPUT 链

iptables 有一个 OUTPUT 链,用于将发往我们的 CoreDNS 集群服务 IP 的 DNS 请求路由到分配给 localdns 变量的 IP

使用如下命令进行查看iptables -nL OUTPUT

1
2
3
4
5
6
7
8
9
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
KUBE-ROUTER-OUTPUT all -- 0.0.0.0/0 0.0.0.0/0 /* kube-router netpol - VEAAIY32XVBHCSCY */
KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes service portals */
KUBE-FIREWALL all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT udp -- 10.43.0.10 0.0.0.0/0 udp spt:53
ACCEPT tcp -- 10.43.0.10 0.0.0.0/0 tcp spt:53
ACCEPT udp -- 169.254.20.10 0.0.0.0/0 udp spt:53
ACCEPT tcp -- 169.254.20.10 0.0.0.0/0 tcp spt:53

查询本地缓存实例:

$dig +short @169.254.20.10 prefetch.net

1
67.205.141.207

$dig +short @169.254.20.10 prefetch.net

1
67.205.141.207

以上会得到相同的结果。但是检查日志,第一个请求会到达本地缓存服务器,然后被转发到主 CoreDNS 服务 IP。当第二个查询进来时,缓存的条目将返回给请求者,从而减少主 CoreDNS 服务器的负载。如果 pod 配置为指向上游 CoreDNS 服务器,iptables 将确保查询命中本地 DNS 缓存。

创建pod并测试解析

创建测试pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-node-local-dns
spec:
containers:
- name: local-dns
image: busybox:glibc
command: ["/bin/sh", "-c", "sleep 60m"]
dnsPolicy: "None"
dnsConfig:
nameservers:
- 169.254.20.10
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "2"
EOF

注意: busybox 的 新版本 uclibc 中的nslookup 有问题,请使用 glibc 。

待 pod 启动后,查看 /etc/resolv.conf

1
2
3
4
# kubectl exec test-node-local-dns -- cat /etc/resolv.conf      
nameserver 169.254.20.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:2

在 pod 的节点上,监听 53 端口

我这里是 k8s-worker-node2 节点,可以通过kubectl get pods test-node-local-dns -o jsonpath='{$.spec.nodeName}' 获取

1
2
3
# yum install tcpdump -y
# tcpdump -i any src host 169.254.20.10 and port 53 -vv
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes

在 pod 中查询 外部域名 A 记录

1
2
3
4
5
6
7
8
9
10
11
12
13
# kubectl exec test-node-local-dns -- nslookup www.baidu.com
Server: 169.254.20.10
Address: 169.254.20.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

正常返回,没有问题。

在 pod 的节点上,观察 tcpdump 接收到的信息

1
2
3
4
5
6
7
k8s-worker-node2.domain > 10.244.4.24.38514: [bad udp cksum 0xcd77 -> 0x112f!] 41730 q: AAAA? www.baidu.com. 1/0/0 www.baidu.com. CNAME www.a.shifen.com. (74)
8:03.164521 IP (tos 0x0, ttl 64, id 33106, offset 0, flags [DF], proto UDP (17), length 102)
k8s-worker-node2.domain > 10.244.4.24.38514: [bad udp cksum 0xcd77 -> 0x112f!] 41730 q: AAAA? www.baidu.com. 1/0/0 www.baidu.com. CNAME www.a.shifen.com. (74)
8:03.164646 IP (tos 0x0, ttl 64, id 33107, offset 0, flags [DF], proto UDP (17), length 166)
k8s-worker-node2.domain > 10.244.4.24.38514: [bad udp cksum 0xcdb7 -> 0x60ed!] 33472 q: A? www.baidu.com. 3/0/0 www.baidu.com. CNAME www.a.shifen.com., www.a.shifen.com. A 180.101.49.12, www.a.shifen.com. A 180.101.49.11 (138)
8:03.164649 IP (tos 0x0, ttl 64, id 33107, offset 0, flags [DF], proto UDP (17), length 166)
k8s-worker-node2.domain > 10.244.4.24.38514: [bad udp cksum 0xcdb7 -> 0x60ed!] 33472 q: A? www.baidu.com. 3/0/0 www.baidu.com. CNAME www.a.shifen.com., www.a.shifen.com. A 180.101.49.12, www.a.shifen.com. A 180.101.49.11 (138)

到这里就说明NodeLocal DNSCache 组件部署成功了,但是域名解析我们还是要多测试测试。

测试 service 域名解析

1
2
3
4
5
6
7
8
9
10
11
12
# kubectl exec test-node-local-dns -- nslookup -type=a kubernetes
Server: 169.254.20.10
Address: 169.254.20.10:53

** server can't find kubernetes.cluster.local: NXDOMAIN

** server can't find kubernetes.svc.cluster.local: NXDOMAIN

Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1

command terminated with exit code 1
因为使用了相对域名,使用搜索域,进行了所有域的查询操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# fqdn
# kubectl exec test-node-local-dns -- nslookup -type=a kubernetes.
Server: 169.254.20.10
Address: 169.254.20.10:53

** server can't find kubernetes.: SERVFAIL

command terminated with exit code 1
# dot 2
[root@k8s-master-node1 ~]# kubectl exec test-node-local-dns -- nslookup -type=a kubernetes.default
Server: 169.254.20.10
Address: 169.254.20.10:53

** server can't find kubernetes.default: NXDOMAIN

command terminated with exit code 1
# domain
[root@k8s-master-node1 ~]# kubectl exec test-node-local-dns -- nslookup -type=a kubernetes.default.svc.cluster.local
Server: 169.254.20.10
Address: 169.254.20.10:53

Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
  • 使用**FQDN(完全限定域名)**时,只会查询一次。

    • FQDN的组成:
  • 域名中的.数目等于或大于设置的值时,也会只查询一次。

ExternalName Service 解析

ExternalName Service 是 Service 的一个特例,没有选择器,可以用于给外部服务取一个内部别名。

创建 ExternalName Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: baidu
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com
EOF

# kubectl describe svc baidu
Name: baidu
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ExternalName
IP:
External Name: www.baidu.com
Session Affinity: None
Events: <none>

测试解析内部服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# kubectl exec test-node-local-dns -- nslookup baidu
Server: 169.254.20.10
Address: 169.254.20.10:53

** server can't find baidu.cluster.local: NXDOMAIN

baidu.default.svc.cluster.local canonical name = www.baidu.com
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

baidu.default.svc.cluster.local canonical name = www.baidu.com
www.baidu.com canonical name = www.a.shifen.com

** server can't find baidu.svc.cluster.local: NXDOMAIN

** server can't find baidu.svc.cluster.local: NXDOMAIN

** server can't find baidu.cluster.local: NXDOMAIN

command terminated with exit code 1

baidu.default.svc.cluster.local 将会被映射到 www.baidu.com , 这是通过 DNS 的 CNAME 记录实现的。

压测

使用 dnsperf 项目进行 dns 查询压力测试

创建pod

1
2
3
4
5
6
7
8
9
10
11
12
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: perf-node-dns
spec:
containers:
- name: perf-node-dns
image: guessi/dnsperf:alpine
command: ["/bin/sh", "-c", "sleep 60m"]
dnsPolicy: "None"
EOF

测试coredns的性能

coredns 在集群中默认是2个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# kubectl exec -ti perf-node-local-dns -- sh
cat <<EOF >records.txt
baidu.com A
www.baidu.com A
mail.baidu.com A
github.com A
www.yahoo.com A
www.microsoft.com A
www.aliyun.com A
developer.aliyun.com A
kubernetes.io A
kubernetes A
kubernetes.default.svc.cluster.local A
kube-dns.kube-system.svc.cluster.local A
EOF

/ # dnsperf -l 60 -s 10.96.0.10 -Q 100000 -d records.txt
DNS Performance Testing Tool
Version 2.2.1

[Status] Command line: dnsperf -l 60 -s 10.96.0.10 -Q 100000 -d records.txt
[Status] Sending queries (to 10.96.0.10)
[Status] Started at: Tue Nov 10 05:00:35 2020
[Status] Stopping after 60.000000 seconds
[Status] Testing complete (time limit)

Statistics:

Queries sent: 835613
Queries completed: 835613 (100.00%)
Queries lost: 0 (0.00%)

Response codes: NOERROR 765979 (91.67%), SERVFAIL 69634 (8.33%)
Average packet size: request 35, response 163
Run time (s): 60.005840
Queries per second: 13925.527915

Average Latency (s): 0.005713 (min 0.000170, max 0.067250)
Latency StdDev (s): 0.003657

dnsperf 参数

  • -l 60 : 测试 60s
  • -s 10.96.0.10 : dns 服务器
  • -Q 100000: 最高qps
  • -d records.txt: 查询的列表

在 Statistics 区域中,我们可以看到发送查询835613,查询完成度**100%**,qps 为 13925.527915。 返回码有SERVFAIL 是因为 kubernetes 域名查询的错误。

测试使用NodeLocal DNSCache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/ # dnsperf -l 60 -s 169.254.20.10 -Q 100000 -d  records.txt
DNS Performance Testing Tool
Version 2.2.1

[Status] Command line: dnsperf -l 60 -s 169.254.20.10 -Q 100000 -d records.txt
[Status] Sending queries (to 169.254.20.10)
[Status] Started at: Tue Nov 10 05:08:16 2020
[Status] Stopping after 60.000000 seconds
[Status] Testing complete (time limit)

Statistics:

Queries sent: 1515112
Queries completed: 1515112 (100.00%)
Queries lost: 0 (0.00%)

Response codes: NOERROR 1388853 (91.67%), SERVFAIL 126259 (8.33%)
Average packet size: request 35, response 163
Run time (s): 60.010329
Queries per second: 25247.520306

Average Latency (s): 0.003299 (min 0.000035, max 0.052578)
Latency StdDev (s): 0.002136

在 Statistics 区域中,我们可以看到发送查询1515112,查询完成度**100%**,qps 为 25247.520306。 其性能比使用coredns提升了55% 左右。

高可用

NodeLocal DNS Cache 并没有高可用性的特征,但是我们通过设置DaemonSet的属性,可以提高本地 dns缓存服务的稳定性。

在常规的pod终止过程中,pod会删除dummy interface & iptables规则。这样就会将流量从自身切换到集群中运行的常规 kube-dns pod上。但是如果我们强行杀死 pod,将不会去除 iptable 规则,这样就会破坏该节点的所有DNS流量,因为nodelocaldns接口上没有任何应用在监听。

为了避免这个不必要的麻烦,默认的 DaemonSet 没有设置内存/CPU限制。我建议你保持这种方式,以避免内存终止或任何CPU节流。另外pods被标记为 system-node-critical 优先级,这使得nodelocaldns几乎可以保证在节点资源耗尽的情况下,首先被调度,不太可能被驱逐。

如果你想安全起见,建议把DaemonSet更新策略改为OnDelete,并通过排空Kubernetes节点来进行维护/升级,排空成功后逐一删除Node Local DNS pods。

在pod中,增加一个备用nameserver,也就是我们的 kube-dns的 cluster ip,从而在 node-local-dns 不可用的情况下,能使用集群中的dns服务解析域名,保障服务不中断业务。

故障演练

模拟 node-local-dns pod 意外宕机

进入测试pod容器中

1
2
3
4
5
6
# kubectl exec -ti test-node-local-dns -- sh
/ # cat /etc/resolv.conf
nameserver 169.254.20.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:2
/ #

定时查询解析

1
/ # while true; do date; nslookup -type=a www.baidu.com; sleep 0.5; done

在测试pod节点上kill掉node-local-dns pod

1
2
# docker kill $(docker ps | grep node-cache_node-local-dns  | awk '{print $1}')
939d90728c43

在测试pod容器中,查看解析情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Wed Nov 11 03:43:55 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.11
Name: www.a.shifen.com
Address: 180.101.49.12

......

Wed Nov 11 03:43:58 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.11
Name: www.a.shifen.com
Address: 180.101.49.12

Wed Nov 11 03:43:59 UTC 2020
nslookup: read: Connection refused
nslookup: read: Connection refused
;; connection timed out; no servers could be reached

......

Wed Nov 11 03:46:39 UTC 2020
nslookup: read: Connection refused
nslookup: read: Connection refused
;; connection timed out; no servers could be reached

Wed Nov 11 03:46:44 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.11
Name: www.a.shifen.com
Address: 180.101.49.12

Wed Nov 11 03:46:45 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.11
Name: www.a.shifen.com
Address: 180.101.49.12

解析日志做了缩减处理。

从上列日志中可以看到,在Wed Nov 11 03:43:59 UTC 2020Wed Nov 11 03:46:44 UTC 2020 时间内,解析域名是不成功的,也就意味着近4分钟内应用是无法连接外网的。node-local-dns pod 在此时间内完成了重建,后续解析才能够成功。

对于这种情况,我们可以增加一个备用nameserver,也就是我们的 kube-dns的 cluster,从而在 node-local-dns 不可用的情况下,能使用集群中的dns服务。

添加备用 nameserver

1
2
3
4
5
6
/ # cat  /etc/resolv.conf 
nameserver 169.254.20.10
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:2
options timeout:2

定时查询解析

1
/ # while true; do date; nslookup -type=a www.baidu.com; sleep 0.5; done

在测试pod节点上kill掉 node-local-dns pod

1
2
# docker kill $(docker ps | grep node-cache_node-local-dns  | awk '{print $1}')
eaf8e75858e0

在测试pod容器中,查看解析情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Wed Nov 11 04:36:58 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

......

Wed Nov 11 04:36:59 UTC 2020
nslookup: read: Connection refused
nslookup: read: Connection refused
Server: 10.96.0.10
Address: 10.96.0.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

......

Wed Nov 11 04:37:10 UTC 2020
nslookup: read: Connection refused
nslookup: read: Connection refused
Server: 10.96.0.10
Address: 10.96.0.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

Wed Nov 11 04:37:16 UTC 2020
Server: 169.254.20.10
Address: 169.254.20.10:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11

解析日志做了缩减处理。

从上列日志中可以看到,在Wed Nov 11 04:36:59 UTC 2020Wed Nov 11 04:37:16 UTC 2020 时间内,169.254.20.10 本地dns 解析域名是不成功的,经过重试 10.96.0.10 集群dns获得了域名A记录。这样就能保障在本地dns出现故障时,可以使用集群dns接替解析任务,从而使业务不中断。