K8S集群中Coredns域名解析故障排查思路

Posted Jiangxl~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8S集群中Coredns域名解析故障排查思路相关的知识,希望对你有一定的参考价值。

K8S集群中Coredns域名解析故障排查思路

文章目录

1.K8S域名解析故障

在使用K8S的过程中,可能会遇到域名解析失败的现象,主要有以下几种问题:

  • 在Pod中无法解析集群外部的域名,例如baidu.com,但是可以上网。
  • Pod与Pod之间服务调用,可以ping通Service资源的地址,但是无法使用服务发现地址进行通信。

在实际生产环境中,程序依赖的Tomcat、nginx都是以Pod的形式部署的,Nginx需要对Tomcat进行反向代理,若Pod无法解析域名或者是无法使用服务发现的地址通信,那么Nginx只能通过Service资源的IP进行通信,IP可能会发生变化,但是域名是肯定不会变化的。

服务发现地址是K8S内部针对每个Service资源设定的域名地址,程序之间的调用都是采用的服务发现地址,当遇到域名无法解析的时候,就会影响应用程序之间的调用。

2.无法解析集群外部的域名排查思路

k8s集群coredns无法解析外部域名

1. 问题现象

公司内部SaaS产品运行在阿里云kubernetes环境,使用阿里云[标准托管版]进行部署使用,[标准托管版] 版就是用户只需要自己运维k8s node节点,master节点由阿里云进行维护,当k8s环境部署完成之后,将公司生产业务部署后发现部分业务模块无法解析到阿里云OSS自定义的对象存储域名,导致业务出现异常;

业务模块是可以通过域名访问其他业务模块及互联网域名的,而且业务模块配置了SNAT都是可以访问互联网的

1.1. 问题分析

公司域名后缀为*.oneprocloud.com,统一方便管理,所有的资源均使用子域名

在阿里云我们采用2个4核16G的云主机作为Node节点进行部署公司生产业务,因为有部分业务模块需要访问阿里云OSS对象存储进行访问数据,OSS对象存储我们设置了自定义域名,为了方便访问,短域名地址为"downloads.oneprocloud.com",并配置了智能DNS解析,办公笔记本可以解析短域名地址,即判定自定义短域名生效,可以正常使用

在k8s业务模块内进行如下测试:

  • nslookup进行解析互联网地址,是可以正常解析的
# www.baidu.com可以正常解析
[root@jumpserver-7596dc7dcb-lcs4n ~]# nslookup www.baidu.com
Server:         10.0.0.10
Address:        10.0.0.10#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com
Address: 220.181.38.149
Name:   www.a.shifen.com
Address: 220.181.38.150
  • nslookup解析自定义阿里云OSS域名地址,发现无法进行解析
# www.baidu.com可以正常解析
[root@jumpserver-7596dc7dcb-lcs4n ~]# nslookup downloads.oneprocloud
Server:         10.0.0.10
Address:        10.0.0.10#53

Server:         10.0.0.10
Address:        10.0.0.10#53

Non-authoritative answer:
*** Can't find downloads.oneprocloud.com: No answer

经过以上测试,分析为在k8s集群内部,都是去找coredns 10.0.0.10 DNS进行解析域名,www.baidu.com 就可以解析,但是我们自定义的downloads.oneprocloud.com就无法解析,这个现象很诡异,我们接着查看coredns的配置:

查看k8s集群的coredns配置:

# 查看kube-system下的coredns configmap
[root@jumpserver-7596dc7dcb-lcs4n ~]# kubectl get configmap -n kube-system
NAME                                 DATA   AGE
ack-cluster-profile                  6      16d
acr-configuration                    5      16d
coredns                              1      16d
extension-apiserver-authentication   6      16d
kube-flannel-cfg                     2      16d
kube-proxy-worker                    2      16d
kubeadm-config                       1      16d
kubelet-config-1.11                  1      16d
kubelet-config-1.12                  1      16d
kubelet-config-1.18                  1      16d
kubernetes-dashboard-settings        1      13d

# 查看coredns的configmap的定义是如何的,其实就是看看dns的配置
[root@jumpserver-7596dc7dcb-lcs4n ~]# kubectl get configmap -n kube-system coredns -o yaml
apiVersion: v1
data:
  Corefile: |
    .:53 
        errors
        health 
           lameduck 5s
        
        ready

        kubernetes oneprocloud.com in-addr.arpa ip6.arpa   # 在Corefile配置文件我们发现dns的域配置的oneprocloud.com

          pods verified
          upstream
          fallthrough in-addr.arpa ip6.arpa
          ttl 30
        
        autopath @kubernetes
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    
kind: ConfigMap
metadata:
  annotations: # 这边的配置信息也是 oneprocloud.com域名
    kubectl.kubernetes.io/last-applied-configuration: |
      "apiVersion":"v1","data":"Corefile":".:53 \\n    errors\\n    health \\n       lameduck 5s\\n    \\n    ready\\n\\n    kubernetes oneprocloud.com in-addr.arpa ip6.arpa \\n\\n      pods verified\\n      upstream\\n      fallthrough in-addr.arpa ip6.arpa\\n      ttl 30\\n    \\n    autopath @kubernetes\\n    prometheus :9153\\n    forward . /etc/resolv.conf\\n    cache 30\\n    loop\\n    reload\\n    loadbalance\\n\\n","kind":"ConfigMap","metadata":"annotations":,"creationTimestamp":"2021-01-11T10:33:07Z","managedFields":["apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":"f:data":".":,"f:Corefile":,"f:metadata":"f:annotations":".":,"f:kubectl.kubernetes.io/last-applied-configuration":,"manager":"rc","operation":"Update","time":"2021-01-11T10:33:07Z"],"name":"coredns","namespace":"kube-system","resourceVersion":"24861979","selfLink":"/api/v1/namespaces/kube-system/configmaps/coredns","uid":"7891c2a7-bff4-4f81-abaa-d06abb0ddf35"
  creationTimestamp: "2021-01-11T10:33:07Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data: 
      f:metadata:
        f:annotations: 
    manager: rc
    operation: Update
    time: "2021-01-11T10:33:07Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        f:Corefile: 
      f:metadata:
        f:annotations:
          f:kubectl.kubernetes.io/last-applied-configuration: 
    manager: kubectl
    operation: Update
    time: "2021-01-27T10:22:30Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "145403500"
  selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
  uid: 7891c2a7-bff4-4f81-abaa-d06abb0ddf35

问题分析结果如下:

通过以上信息查看,其实oneprocloud.com是coredns的解析域,这个应该是在阿里云上部署k8s的时候设置的,这个域名会在k8s集群内部进行生效,作用是什么那,比如两个业务模块之间需要访问的话,我定义了模块的services,我就可以通过xxx.oneprocloud.com这个域名去访问其他业务模块是实现域名注册,xxx就为子域名,只能在k8s集群内部访问,其实我们定义的downloads.oneprocloud.com也是 xxx的子域名,但是并没有在k8s集群内部定义这种services,所以解析的时候,coredns认为这是同一个域内部的,然后去解析发现解析不到,但是为什么www.baidu.com域名可以访问那,是因为非oneprocloud.com后缀域,coredns正常集群外域名如果coredns解析不了,会去coredns的ecs配置的nameserver解析。所以才会出现www.baidu.com可以解析,downloads.oneprocloud.com解析不了的现象;

2. 问题处理方法

针对此问题,个人能力有限,不确定是否有更好的解决办法,例如设置tag文件,写明同一个域的其他子域名,如果coredns在内部集群解析不到的话,先去查询此tag文件,然后再进行找外部dns进行解析,只是个人想法

以上问题的发生,因为k8s环境已经部署完成,业务也已经部署了,总不能重新部署吧,那这个代价也太大了,有没有办法修改coredns配置,让其更改一个另外的解析域。

我这边大概想到2个方案:

  • 第一个方案

k8s集群内部解析域不变,变动外部自定义OSS对象域名,更换成其他的后缀域名

  • 第二个方案

改变k8s集群内部解析域,外部自定义OSS对象域名保持不变

根据以上两个方案分析,其实第二个方案还是比较合适的,因为公司内部的注册域这个肯定不可能变化的,我总不能再注册一个其他的后缀域吧,这个维护和代价成本也比较大,k8s集群内部域其实就是一个内部的,只要服务能够直接可以解析就可以了,所以第二个方案比较合适,第二个方案的处理办法继续往下

2.1. 修改k8s内部解析域名

如何按照我们的解决方案,第二个方案更改k8s集群内部coredns配置,需要如下两个操作步骤:

  1. 修改集群的coredns configmap文件
  2. 修改所有k8s集群node节点的kubelet服务的配置文件,并重启kubelet服务
  3. 重建业务pod服务

2.1.1. 修改集群coredns cm文件

  • 查看集群coredns cm配置文件并保存
[root@jumpserver-7596dc7dcb-lcs4n ~]# kubectl get configmap -n kube-system coredns -o yaml > coredns-configmap.yaml
  • 修改coredns cm配置 (以下红色标记的两处域名,修改成其他自定义)
[root@jumpserver-7596dc7dcb-lcs4n ~]# vim coredns-configmap.yaml
apiVersion: v1
data:
  Corefile: |
    .:53 
        errors
        health 
           lameduck 5s
        
        ready

        kubernetes **cluster.local** in-addr.arpa ip6.arpa 

          pods verified
          upstream
          fallthrough in-addr.arpa ip6.arpa
          ttl 30
        
        autopath @kubernetes
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      "apiVersion":"v1","data":"Corefile":".:53 \\n    errors\\n    health \\n       lameduck 5s\\n    \\n    ready\\n\\n    kubernetes **oneprocloud.com** in-addr.arpa ip6.arpa \\n\\n      pods verified\\n      upstream\\n      fallthrough in-addr.arpa ip6.arpa\\n      ttl 30\\n    \\n    autopath @kubernetes\\n    prometheus :9153\\n    forward . /etc/resolv.conf\\n    cache 30\\n    loop\\n    reload\\n    loadbalance\\n\\n","kind":"ConfigMap","metadata":"annotations":,"creationTimestamp":"2021-01-11T10:33:07Z","managedFields":["apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":"f:data":".":,"f:Corefile":,"f:metadata":"f:annotations":".":,"f:kubectl.kubernetes.io/last-applied-configuration":,"manager":"rc","operation":"Update","time":"2021-01-11T10:33:07Z"],"name":"coredns","namespace":"kube-system","resourceVersion":"24861979","selfLink":"/api/v1/namespaces/kube-system/configmaps/coredns","uid":"7891c2a7-bff4-4f81-abaa-d06abb0ddf35"
  creationTimestamp: "2021-01-11T10:33:07Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data: 
      f:metadata:
        f:annotations: 
    manager: rc
    operation: Update
    time: "2021-01-11T10:33:07Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        f:Corefile: 
      f:metadata:
        f:annotations:
          f:kubectl.kubernetes.io/last-applied-configuration: 
    manager: kubectl
    operation: Update
    time: "2021-01-27T10:22:30Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "145403500"
  selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
  uid: 7891c2a7-bff4-4f81-abaa-d06abb0ddf35
  • 重新进行应用
[root@jumpserver-7596dc7dcb-lcs4n ~]# kubectl apply -f coredns-configmap.yaml

2.1.2. 修改所有k8s集群node节点配置文件

这里需要注意是所有的节点kubelet配置文件都需要更改并重启服务,包含以后横向扩展的node节点,一定要记得也要同步修改节点配置文件,例如:当前2个node节点更改了,后续增加1个多个节点,同样也需要重复以下步骤,不然还是无法进行解析

  • 修改配置文件/etc/systemd/system/kubelet.service.d/10-kubeadm.conf

修改配置文件中标红的内容,修改成自定义的域名,要和coredns configmap修改的域名保持一致

[Service]
Environment="KUBELET_EXTRA_ARGS=--node-labels=HM-SAAS-Lable=Production"
EnvironmentFile=-/etc/kubernetes/kubelet-customized-args.conf
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_SYSTEM_PODS_ARGS=--max-pods 64 --pod-max-pids 16384 --pod-manifest-path=/etc/kubernetes/manifests"
Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin --dynamic-config-dir=/etc/kubernetes/kubelet-config --v=3"
Environment="KUBELET_DNS_ARGS=--enable-controller-attach-detach=true --cluster-dns=10.0.0.10 --pod-infra-container-image=registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.2 --enable-load-reader --cluster-domain=**cluster.local** --cloud-provider=external --hostname-override=cn-beijing.192.168.1.156 --provider-id=cn-beijing.i-2ze6kkewztaauih0izyr"
Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --authentication-token-webhook=true --anonymous-auth=false --client-ca-file=/etc/kubernetes/pki/ca.crt"
Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=systemd"
Environment="KUBELET_CERTIFICATE_ARGS=--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 --tls-cert-file=/var/lib/kubelet/pki/kubelet.crt --tls-private-key-file=/var/lib/kubelet/pki/kubelet.key --rotate-certificates=true --cert-dir=/var/lib/kubelet/pki"
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CGROUP_ARGS $KUBELET_CERTIFICATE_ARGS $KUBELET_EXTRA_ARGS $KUBELET_CUSTOMIZED_ARGS
  • 重新加载配置文件并重启kubelet服务
[root@iZ2ze6kkewztaauih0izyrZ ~]# systemctl daemon-reload
[root@iZ2ze6kkewztaauih0izyrZ ~]# systemctl restart kubelet

2.1.3. 重建业务pod服务

将所有的业务pod重建,不然无法使用最新的coredns配置进行服务注册发现

# 按照业务pod重建方式
# kubectl replace --force -f xxxx.yaml

2.1.4. 验证业务域名访问

  • 验证corends cm配置

  • 验证域名解析

通过nslookup进行解析测试,发现已经可以正常解析外部域名

3. 问题分析结论

在k8s集群内部设置了域,例如*.oneprocloud.com,那么oneprocloud.com就会被认为是集群内的域名,只向coredns进行域名解析,如果你在互联网也设置了同样后缀的DNS域名解析,在coredns内部是解析不了的,需配置配置其他外部域进行访问,正常集群外域名如果coredns解析不了,例如:*.baidu.com 那么coredns会去coredns所在ecs节点配置的nameserver进行解析。

以上是关于K8S集群中Coredns域名解析故障排查思路的主要内容,如果未能解决你的问题,请参考以下文章

k8s集群coredns无法解析外部域名

k8s集群coredns无法解析外部域名

nodelocaldns导致coredns hosts配置失效

处理coredns Pending故障

Kubernetes 0-1 K8S部署coredns

k8s中的dns应用