【DNS系列-K8S排错】CoreDNS 新增 host 解析不生效

参考

  • 记一次CoreDNS排错经历.md

1 | 问题 CoreDNS 新增 host 解析不生效

正常我们只需要在 CoreDNS 的 ConfigMap 中添加 hosts 插件就可以使用了:

hosts {
  10.151.30.11 git.k8s.local
  fallthrough
}

但是在配置完成后,始终解析不了这个自定义的域名:

$ kubectl run -it --image busybox:1.28.4 test --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup git.k8s.local
Server:    169.254.20.10
Address 1: 169.254.20.10

nslookup: can't resolve 'git.k8s.local'

2 | 测试 localdns 和 coredns 的解析是否可行

启动测试容器

$ kubectl run -it --image busybox:1.28.4 test --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup git.k8s.local
Server:    169.254.20.10
Address 1: 169.254.20.10

nslookup: can't resolve 'git.k8s.local'
使用 CoreDNS 的地址来进行解析测试
/ # nslookup git.k8s.local 10.96.0.10
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      git.k8s.local
Address 1: 10.151.30.11 git.k8s.local
使用 LocalDNS 的地址来进行解析测试

发现了不能解析

/ # nslookup git.k8s.local 169.254.20.10
Server:    169.254.20.10
Address 1: 169.254.20.10

nslookup: can't resolve 'git.k8s.local'

3 | 查看日志

查看 LocalDNS 日志

下面的规则其实不难看懂

  • 10.96.0.10 为 CoreDNS 的 Service ClusterIP,169.254.20.10 为 LocalDNS 的 IP 地址
  • 10.96.207.156 是 LocalDNS 新建的一个 Service ClusterIP,该 Service 和 CoreDNS 一样都是关联以前的 CoreDNS 的 Endpoints 列表(就是此 ip 地址是和 CoreDns service 指向相同的 pod 组(即Endpoints))
  • 分块来看
    • 前三块,仔细观察可以发现 cluster.localin-addr.arpa 以及 ip6.arpa 都会通过 forward 转发到 10.96.207.156,也就是去 CoreDNS 解析
    • 其他的则是 forward . /etc/resolv.conf 通过 resolv.conf 文件去解析
$ kubectl logs -f node-local-dns-bb84m -n kube-system
......
2020/05/14 05:30:21 [INFO] Updated Corefile with 0 custom stubdomains and upstream servers /etc/resolv.conf
2020/05/14 05:30:21 [INFO] Using config file:
# 仔细观察可以发现 `cluster.local`、`in-addr.arpa` 以及 `ip6.arpa` 都会通过 `forward` 转发到 10.96.207.156,也就是去 CoreDNS 解析
cluster.local:53 {
    errors
    cache {
            success 9984 30
            denial 9984 5
    }
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    forward . 10.96.207.156 {
            force_tcp
    }
    prometheus :9253
    health 169.254.20.10:8080
    }
in-addr.arpa:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    forward . 10.96.207.156 {
            force_tcp
    }
    prometheus :9253
    }
ip6.arpa:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    forward . 10.96.207.156 {
            force_tcp
    }
    prometheus :9253
    }
# 其他的则是 forward . /etc/resolv.conf 通过 resolv.conf 文件去解析
.:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    forward . /etc/resolv.conf {
            force_tcp
    }
    prometheus :9253
    }
......
[INFO] plugin/reload: Running configuration MD5 = 3e3833f9361872f1d34bc97155f952ca
CoreDNS-1.6.7
linux/amd64, go1.11.13,

4 | 问题解决

其他是通过 resolv.conf 文件去解析,该文件的内容如下所示:

nameserver 169.254.20.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

ndots:5,表示:如果查询的域名包含的点“.”,不到5个,那么进行DNS查找,将使用非完全限定名称(或者叫绝对域名),如果你查询的域名包含点数大于等于5,那么DNS查询,默认会使用绝对域名进行查询。举例来说:

如果我们请求的域名是,a.b.c.d.e,这个域名中有4个点,那么容器中进行DNS请求时,会使用非绝对域名进行查找,使用非绝对域名,会按照 /etc/resolv.conf 中的 search 域,走一遍追加匹配:

a.b.c.d.e.default.svc.cluster.local. ->
a.b.c.d.e.svc.cluster.local. ->
a.b.c.d.e.cluster.local.

走完了search域还找不到,则使用 a.b.c.d.e. ,作为绝对域名进行DNS查找。

所以当我们解析域名 git.k8s.local 的时候需要走一遍搜索域

  • 可以看到 LocalDNS 日志前三条并不匹配
  • 因此,会走到 /etc/resolv.conf 解析,发现也解析不了

那么我们是不是自然可以想到把 hosts 插件配置在 LocalDNS 这边不就可以了吗?这种思路应该是完全正确的:

$ kubectl edit cm node-local-dns -n kube-system
......
.:53 {
    errors
    hosts {  # 添加 A 记录
      10.151.30.11 git.k8s.local
      fallthrough
    }
    cache 30
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    forward . /etc/resolv.conf {
            force_tcp
    }
    prometheus :9253
}
......

更新完成后,我们可以手动重建 NodeLocalDNS Pod,重建过后确发现 NodeLocalDNS 的 Pod 启动失败了,会出现如下所示的错误信息:

no action found for directive 'hosts' with server type 'dns'

原来压根就不支持 hosts 这个插件。那么我们就只有去 CoreDNS 解析了,所以这个时候我们需要把 forward . /etc/resolv.conf 更改成 forward . 10.96.207.156,这样就会去 CoreDNS 解析了,在 NodeLocalDNS 的 ConfigMap 中做如下的修改即可:

$ kubectl edit cm node-local-dns -n kube-system
......
.:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.10 10.96.0.10
    # 此处为 CoreDNS 地址
    # 该环境变量对应 kube-dns 的 ConfigMap 定义的 CoreDNS 地址
    forward . __PILLAR__CLUSTER__DNS__ {
            force_tcp
    }
    prometheus :9253
}
......

同样修改完成后,需要重建 NodeLocalDNS 的 Pod 才会生效。

__PILLAR__CLUSTER__DNS____PILLAR__UPSTREAM__SERVERS__ 这两个参数在镜像 1.15.6 版本以上中会自动进行配置,对应的值来源于 kube-dns 的 ConfigMap 和定制的 Upstream Server 地址。

现在我们再去测试就可以正常解析自定义的域名了:

/ # nslookup git.k8s.local
Server:    169.254.20.10
Address 1: 169.254.20.10

Name:      git.k8s.local
Address 1: 10.151.30.11 git.k8s.local

对于使用 NodeLocalDNS 的用户一定要注意这个问题,如果使用 hosts 或者 rewrite 插件失效,基本上就是这个问题造成的。排查问题通过日志去分析始终是最好的手段。

你可能感兴趣的:(Kubernetes学习笔记,k8s排错及配置,网络学习笔记,kubernetes,docker,容器)