在kubernetes集群里优雅的不影响应用的更换节点的dns服务器ip

dns服务器作为基础设施,一般很少变更。如果dns服务器ip发生变化了,怎么更换kubernetes节点的dns配置?

更换节点步骤,直接替换/etc/resolv.conf文件里的dns服务器ip。

上面只更新了节点的/etc/resolv.conf文件,node local dns和coredns的pod里面的/etc/resolv.conf并没有更新。

重启生效

1
2
kubectl rollout restart deployment -n kube-system coredns
kubectl rollout restart daemonset -n kube-system node-local-dns

本文使用coredns版本为1.8.7, node local dns为1.21.1

上面的方法简单粗暴,重启过程中pod里的程序无法解析域名。

在只部署coredns集群,按照上面方式重启coredns pod,在linux内核版本5.9以下且kube-proxy ipvs模式下,会有概率pod无法解析域名。相关issue https://github.com/kubernetes/kubernetes/issues/93297

在部署了coredns和node local dns集群中,按照上面方式重启node local dns的pod。pod重启期间,节点上dns模式为ClusterFirst(且网络模式不为hostnetwork)的pod无法解析域名。

下面介绍,不中断服务情况下变更节点dns服务器ip。

先替换/etc/resolv.conf文件里的dns服务器ip,然后再替换node local dns和coredns的pod的/etc/resolv.conf文件

修改pod的dns配置文件/etc/resolv.conf内容里介绍了无需重启pod更改pod的/etc/resolv.conf文件方法。这里使用相同的方法替换node local dns和coredns的pod的/etc/resolv.conf,将pod的/etc/resolve.conf文件内容改成节点的/etc/resolve.conf内容。

containerd为运行时

1
cat /etc/resolv.conf >  $(crictl inspect -o go-template  --template='{{- range $mount := .info.runtimeSpec.mounts -}} {{- if eq $mount.destination "/etc/resolv.conf" -}} {{- $mount.source -}}   {{- end -}} {{- end -}} '  $(crictl ps |grep node-local-dns |awk '{print $1}'))

dockershim为运行时

1
cat /etc/resolv.conf > $(docker inspect $(docker ps |grep k8s_node-cache_node-local-dns | awk '{print $1}') --format '{{ .ResolvConfPath }}')

在coredns pod节点运行命令

containerd为运行时

1
crictl inspect -o go-template  --template='{{- range $mount := .info.runtimeSpec.mounts -}} {{- if eq $mount.destination "/etc/resolv.conf" -}} {{- $mount.source -}}   {{- end -}} {{- end -}} '  $(crictl ps |grep coredns- |awk '{print $1}') | xargs -i  bash -c "cat /etc/resolv.conf > {}"

dockershim为运行时

1
docker inspect $(docker ps |grep k8s_coredns_coredns | awk '{print $1}') --format '{{ .ResolvConfPath }}' | xargs -i  bash -c "cat /etc/resolv.conf > {}"

上面只是文件替换了,但是进行是否重新读取/etc/resolv.conf,依赖程序的实现。

不幸的是coredns和node local dns只在启动时候读取/etc/resolv.conf文件,同时reload插件只是监听配置文件的变化,并不会捕获/etc/resolv.conf文件变化。

Yes - the forward plugin only reads the file (e.g. /etc/resolv.conf) when CoreDNS starts/restarts. The reload plugin only checks for changes in the Corefile, not other files referenced by plugins (e.g. the zone file by the file plugin, and resolv.conf by the forward plugin ).

Whether not we periodically check/re-read plugin referenced files is currently left to the plugins themselves. For example, the file plugin periodically reloads its zone file, which makes sense, since a zone file is inherently dynamic. Currently, the forward plugin does not periodically check/reload its resolv.conf file - probably because its contents are generally static.

https://github.com/coredns/coredns/issues/3928#issuecomment-640586182

所以要让coredns和node local dns进行reload才能重新读取/etc/resolv.conf

configmap添加换行–神奇的魔法

当配置文件变化时,reload插件触发reload。即只要修改coredns和node local dns的configmap,就能触发reload。这里的魔法–只需要在configmap内容中添加换行,这个换行位置必须和reload在同一大括号内。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.:53 {
这里添加了换行
 errors
 cache 30
 reload
 loop
 bind 169.254.20.10 
 forward . __PILLAR__UPSTREAM__SERVERS__ {
 force_tcp
 }

过一会日志中出现Reloading complete,说明重新读取/etc/resolv.conf成功。

1
2
3
[INFO] Reloading
....
[INFO] Reloading complete

pod的dns模式为Default,或网络模式是HostNetwork且dns模式为ClusterFirst,由于使用是节点的/etc/resolv.conf文件,所以也需要进行替换。

至于程序是否重新读取/etc/resolv.conf文件,要看各个程序的实现。

优雅变更节点的dns服务器ip步骤

  1. 直接替换/etc/resolv.conf文件里的dns服务器ip
  2. 使用修改节点上挂载文件方式,修改coredns和node local dns里的/etc/resolv.conf文件。
  3. 在configmap内容里添加一个换行,让coredns和node local dns进行reload,从而重新读取/etc/resolv.conf文件。
  4. 使用修改节点上挂载文件方式,修改其他pod(dns模式为Default,或网络模式是HostNetwork且dns模式)的/etc/resolv.conf文件
  5. 让这些pod重新读取/etc/resolv.conf文件

https://gist.github.com/wu0407/946354660972f81613417ce5a5904a4d

相关内容