转自: https://help.aliyun.com/document_detail/172339.html#11

DNS最佳实践

优化域名解析请求

DNS域名解析请求是Kubernetes最高频的网络行为之一,其中很多请求是可以优化和避免的。您可以通过以下方式优化域名解析请求:

  • (推荐)使用连接池:当一个容器应用需要频繁请求另一服务时,推荐使用连接池。连接池可以将请求上游服务的链接缓存在内存中,避免每次访问时域名解析和TCP建连的开销。
  • 使用DNS缓存:
    • (推荐)当您的应用无法改造成通过连接池连接另一服务时,可以考虑在应用侧缓存DNS解析结果,具体操作,请参见使用节点DNS缓存NodeLocal DNSCache
    • 如果NodeLocal DNSCache无法适用的,可以在容器内置NSCD(Name Service Cache Daemon)缓存。关于如何使用NSCD缓存,请参见在Kubernetes集群中使用NSCD
  • 优化resolv.conf文件:由于resolv.conf文件中ndotssearch两个参数的机制作用,容器内配置域名的不同写法决定了域名解析的效率,关于ndotssearch两个参数的机制详情,请参见DNS原理和配置说明
  • 优化域名配置:当容器内应用需要访问某域名时,该域名按以下原则配置,可以最大程度减少域名解析尝试次数,继而减少域名解析耗时。
    • Pod访问同命名空间的Service,优先使用<service-name>访问,其中service-name代指Service名称。
    • Pod跨命名空间访问Service,优先使用<service-name>.<namespace-name>访问,其中namespace-name代指Service所处的命名空间。
    • Pod访问集群外部域名时,优先使用FQDN类型域名访问,这类域名通过常见域名最后加半角句号(.)的方式来指定地址,可以避免search搜索域拼接带来的多次无效搜索,例如需要访问www.aliyun.com,则优先使用FQDN类型域名www.aliyun.com.来访问。

使用合适的容器镜像

Alpine容器镜像内置的musl libc库与标准glibc的实现存在以下差异:

  • 3.3及更早版本Alpine不支持search参数,不支持搜索域,无法完成服务发现。
  • 并发请求/etc/resolv.conf中配置的多个DNS服务器,导致NodeLocal DNSCache优化失效。
  • 并发使用同一Socket请求A和AAAA记录,在旧版本内核上触发Conntrack源端口冲突导致丢包问题。

关于以上问题的更多信息,请参见musl libc

当Kubernetes集群中部署的容器采用了Alpine作为基础镜像时,可能会因为上述musl libc特性而无法正常解析域名,建议尝试更换基础镜像,如Debian、CentOS等。

避免IPVS缺陷导致的DNS概率性解析超时问题

当集群使用IPVS作为kube-proxy负载均衡模式时,您可能会在CoreDNS缩容或重启时遇到DNS概率性解析超时的问题。该问题由社区Linux内核缺陷导致,具体信息,请参见IPVS

您可以通过以下任意方式降低IPVS缺陷的影响:

使用节点DNS缓存NodeLocal DNSCache

在(aliyun)ACK集群中部署NodeLocal DNSCache可以提升服务发现的稳定性和性能,NodeLocal DNSCache通过在集群节点上作为DaemonSet运行DNS缓存代理来提高集群DNS性能。

关于更多NodeLocal DNSCache的介绍及如何在(aliyun)ACK集群中部署NodeLocal DNSCache的具体步骤,请参见使用NodeLocal DNSCache

使用合适的CoreDNS版本

CoreDNS v1.7.0以下的版本存在风险隐患,包括且不仅限于以下:

不同Kubernetes集群推荐的CoreDNS版本如下表:

Kubernetes版本推荐CoreDNS版本
v1.14.8以下(停止维护)v1.6.2
v1.14.8及以上,1.20.4以下v1.7.0.0-f59c03d-aliyun
1.20.4及以上v1.8.4.1-3a376cc-aliyun

说明 Kubernetes 1.14.8以下的版本现已停止维护,请尽快升级至更高版本后,升级CoreDNS。

监控CoreDNS运行状态

监控指标

CoreDNS通过标准的Promethues接口暴露出解析结果等健康指标,第一时间发现CoreDNS服务端甚至上游DNS服务器的异常。

阿里云应用实时监控服务ARMS Promethues监控默认内置了CoreDNS相关的指标监控和告警规则,您可以在容器服务管理控制台开启Prometheus及仪表盘功能。具体操作,请参见ARMS Prometheus监控

若您是自建Prometheus监控Kubernetes集群,可以在Prometheus观测相关指标并对以下重点指标设置告警。具体操作,请参见CoreDNS Prometheus官方文档。重点指标如下:

指标类型指标说明告警设置
coredns_dns_requests_total请求次数可针对总量进行告警,判断当前域名解析QPS是否过高。
coredns_dns_responses_total响应次数可针对不同状态码RCODE的响应次数进行告警,例如服务端异常SERVFAIL出现时,可进行告警。
coredns_panics_totalCoreDNS程序异常退出的次数大于0则说明异常发生,应进行告警。
coredns_dns_request_duration_seconds域名解析延迟延迟过高时应进行告警。

运行日志

在DNS异常发生的情况下,CoreDNS日志有助于您快速诊断异常根因。建议您开启CoreDNS域名解析日志和其SLS日志采集,具体操作,请参见分析和监控CoreDNS日志

合理调整集群CoreDNS部署状态

CoreDNS应部署于您的Kubernetes集群中,默认情况下与您的业务容器运行在同样的集群节点上,注意事项如下:

合理调整CoreDNS副本数

建议您在任何情况下设置CoreDNS副本数应至少为2,且副本数维持在一个合适的水位以承载整个集群的解析。

CoreDNS所能提供的域名解析QPS与CPU消耗成正相关,开启缓存的情况下,单个CPU可以支撑10000+ QPS的域名解析请求。不同类型的业务对域名请求的QPS需求存在较大差异,您可以观察每个CoreDNS副本的峰值CPU使用量,如果其在业务峰值期间占用CPU大于一核,建议您对CoreDNS进行副本扩容。无法确定峰值CPU使用量时,可以保守采用副本数和集群节点数1:8的比值来部署,即每扩容8个集群节点,增加一个CoreDNS副本,但副本数不应大于10。针对100节点以上的集群,推荐使用节点DNS缓存NodeLocal DNSCache。具体操作,请参见使用节点DNS缓存NodeLocal DNSCache

说明 UDP报文缺少重传机制,在CoreDNS副本停止过程中,CoreDNS任意副本缩容或重启可能会导致接收到的UDP报文丢失,触发整个集群域名解析超时或异常。当集群节点存在IPVS UDP缺陷导致的丢包风险时,CoreDNS任意副本缩容或重启可能会导致长达五分钟的整个集群域名解析超时或异常。关于IPVS缺陷导致解析异常的解决方案,请参见IPVS缺陷导致解析异常

合理分配CoreDNS副本运行的位置

建议您在部署CoreDNS副本时,应将CoreDNS副本打散在不同可用区、不同集群节点上,避免单节点、单可用区故障。CoreDNS默认配置了按节点的弱反亲和性,可能会因为节点资源不足导致部分或全部副本部署在同一节点上,如果遇到这种情况,请删除Pod重新触发其调度来调整。

CoreDNS所运行的集群节点应避免CPU、内存用满的情况,否则会影响域名解析的QPS和响应延迟。

手动扩容副本数

当集群节点数长时间较为固定时,您可以通过以下命令扩容CoreDNS副本数。

1
kubectl scale --replicas={target} deployment/coredns -n kube-system

说明 将目标副本数{target}设置成目标值。

自动扩容副本数(cluster-autoscaler)

当集群节点数不断增长时,您可以通过以下YAML部署集群水平伸缩器cluster-proportional-autoscaler动态扩容副本数量:

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
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dns-autoscaler
namespace: kube-system
labels:
k8s-app: dns-autoscaler
spec:
selector:
matchLabels:
k8s-app: dns-autoscaler
template:
metadata:
labels:
k8s-app: dns-autoscaler
spec:
serviceAccountName: admin
containers:
- name: autoscaler
image: registry.cn-hangzhou.aliyuncs.com/acs/cluster-proportional-autoscaler:1.8.4
resources:
requests:
cpu: "200m"
memory: "150Mi"
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=dns-autoscaler
- --nodelabels=type!=virtual-kubelet
- --target=Deployment/coredns
- --default-params={"linear":{"coresPerReplica":64,"nodesPerReplica":8,"min":2,"max":100,"preventSinglePointFailure":true}}
- --logtostderr=true
- --v=9

上述使用线程伸缩策略中,CoreDNS副本数的计算公式为replicas = max (ceil (cores × 1/coresPerReplica), ceil (nodes × 1/nodesPerReplica) ),且CoreDNS副本数受到maxmin限制。线程伸缩策略参数如下。

1
2
3
4
5
6
7
{
"coresPerReplica": 64,
"nodesPerReplica": 8,
"min": 2,
"max": 100,
"preventSinglePointFailure": true
}

基于CPU负载指标自动扩容副本数(HPA)

由于HPA会频繁触发CoreDNS副本缩容,建议您不要使用容器水平扩缩容(HPA),如果您的场景下必须依赖于HPA,请参考以下基于CPU负载的策略配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: coredns-hpa
namespace: kube-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: coredns
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50

说明 关于HPA使用方式的更多信息,请参见容器水平伸缩(HPA)

合理配置CoreDNS

CoreDNS的配置非常灵活,具体操作,请参见DNS原理和配置说明CoreDNS官方文档

早期版本随Kubernetes集群部署的CoreDNS默认配置可能存在一些风险,推荐您按以下方式检查和优化:

您也可以通过容器智能运维中定时巡检和故障诊断功能完成CoreDNS配置文件的检查。当容器智能运维检查结果中提示CoreDNS Configmap配置异常时,请逐个检查以上项目。

配置Ready就绪探针插件

大于1.5.0版本的CoreDNS必须配置ready插件以启用就绪探针。

  1. 执行如下命令,打开CoreDNS配置文件。

    1
    kubectl -n kube-system edit configmap coredns
  2. 检查是否包含ready一行,若无,则增加ready一行,按Esc键、输入:wq!并按Enter键,保存修改后的配置文件并退出编辑模式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    apiVersion: v1
    data:
    Corefile: |
    .:53 {
    errors
    health {
    lameduck 15s
    }
    ready #如果没有这一行,请增加本行,注意缩进与Kubernetes保持一致。
    kubernetes cluster.local in-addr.arpa ip6.arpa {
    pods verified
    fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf {
    max_concurrent 1000
    prefer_udp
    }
    cache 30
    loop
    log
    reload
    loadbalance
    }
  3. 检查CoreDNS Pod运行状态和运行日志,运行日志中出现reload字样后说明修改成功。

关闭kube-dns服务的亲和性配置

亲和性配置可能导致CoreDNS不同副本间存在较大负载差异,建议按以下步骤关闭:

    1. 在kube-system命名空间下,查看kube-dns的YAML。

      • 如果发现sessionAffinity字段为None,则无需进行以下步骤。
      • 如果发现sessionAffinityClientIP,则进行以下步骤。
    2. 删除sessionAffinity、sessionAffinityConfig及所有子键。

      1
      2
      3
      4
      5
      #删除以下所有内容。
      sessionAffinity: ClientIP
      sessionAffinityConfig:
      clientIP:
      timeoutSeconds: 10800
    3. 再次查看服务kube-dnsYAML,校验sessionAffinity字段是否为None,为None则Kube-DNS服务变更成功。

  • 命令行操作方式

    1. 执行以下命令查看kube-dns服务配置信息。

      1
      kubectl -n kube-system get svc kube-dns -o yaml
      • 如果发现sessionAffinity字段为None,则无需执行以下步骤。
      • 如果发现sessionAffinityClientIP,则执行以下步骤。
    2. 执行以下命令打开并编辑名为kube-dns的服务。

      1
      kubectl -n kube-system edit service kube-dns
    3. 删除sessionAffinity相关设置(sessionAffinity、sessionAffinityConfig及所有子键),并保存退出。

      1
      2
      3
      4
      5
      #删除以下所有内容。
      sessionAffinity: ClientIP
      sessionAffinityConfig:
      clientIP:
      timeoutSeconds: 10800
    4. 修改完成后,再次运行以下命令查看sessionAffinity字段是否为None,为None则Kube-DNS服务变更成功。

      1
      kubectl -n kube-system get svc kube-dns -o yaml

关闭Autopath插件

部分早期版本的CoreDNS开启了Autopath插件,该插件在一些极端场景下会导致解析结果出错,请确认其是否处于开启状态,并编辑配置文件将其关闭。更多信息,请参见#3765

说明 关闭Autopath插件后,客户端发起的域名解析请求QPS最高会增加3倍,解析单个域名耗时最高增加3倍,请关注CoreDNS负载和业务影响。

  1. 执行kubectl -n kube-system edit configmap coredns命令,打开CoreDNS配置文件。
  2. 删除autopath @kubernetes一行后保存退出。
  3. 检查CoreDNS Pod运行状态和运行日志,运行日志中出现reload字样后说明修改成功。

配置CoreDNS优雅退出

说明 CoreDNS刷新配置过程中,可能会占用额外内存。修改CoreDNS配置项后,请观察Pod运行状态,如果出现Pod内存不足的情况,请及时修改CoreDNS Deployment中容器内存限制,建议将内存调整至2 GB。

  • 控制台操作方式

    1. 登录容器服务管理控制台

    2. 在控制台左侧导航栏中,单击集群

    3. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情

    4. 在集群管理页左侧导航栏中,选择\配置管理\ > *配置项***

    5. 在kube-system命名空间下,单击配置项coredns右侧的YAML编辑

    6. 参考下列的YAML文件,保证health插件开启,并调整lameduck参数为15s,然后单击确定。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      .:53 {
      errors
      #health插件在不同的CoreDNS版本中可能有不同的设置情形。
      #情形一:默认未启用health插件。
      #情形二:默认启用health插件,但未设置lameduck时间。
      health
      #情形三:默认启用health插件,设置了lameduck时间为5s。
      health {
      lameduck 5s
      }
      #对于以上三种情形,应统一修改成以下,调整lameduck参数为15s。
      health {
      lameduck 15s
      }
      #其它插件不需要修改,此处省略。
      }

    如果CoreDNS Pod正常运行则说明CoreDNS优雅退出的配置更新成功。如果CoreDNS Pod出现异常,可以通过查看Pod事件及日志定位原因。

  • 命令行操作方式

    1. 执行以下命令打开CoreDNS配置文件。

      1
      kubectl -n kube-system edit configmap coredns
    2. 参考下列的YAML文件,保证

      1
      health

      插件开启,并调整lameduck参数为15s。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      .:53 {
      errors
      #health插件在不同的CoreDNS版本中可能有不同的设置情形。
      #情形一:默认未启用health插件。
      #情形二:默认启用health插件,但未设置lameduck时间。
      health
      #情形三:默认启用health插件,设置了lameduck时间为5s。
      health {
      lameduck 5s
      }
      #对于以上三种情形,应统一修改成以下,调整lameduck参数为15s。
      health {
      lameduck 15s
      }
      #其它插件不需要修改,此处省略。
      }
    3. 修改CoreDNS配置文件后保存退出。

      如果CoreDNS正常运行则说明CoreDNS优雅退出的配置更新成功。如果CoreDNS Pod出现异常,可以通过查看Pod事件及日志定位原因。

配置Forward插件与上游VPC DNS服务器的默认协议

NodeLocal DNSCache采用TCP协议与CoreDNS进行通信,CoreDNS会根据请求来源使用的协议与上游DNS服务器进行通信。因此默认情况下,来自业务容器的集群外部域名解析请求会依次经过NodeLocal DNSCache、CoreDNS,最终以TCP协议请求VPC内DNS服务器,即ECS上默认配置的100.100.2.136和100.100.2.13两个 IP。

VPC内DNS服务器对TCP协议支持有限,如果您使用了NodeLocal DNSCache,您需要修改CoreDNS配置,让其总是优先采用UDP协议与上游DNS服务器进行通信,避免解析异常。建议您使用以下方式修改CoreDNS配置文件,即修改命名空间kube-system下名为coredns的ConfigMap。具体操作,请参见创建配置项。在forward插件中指定请求上游的协议为perfer_udp,修改之后CoreDNS会优先使用UDP协议与上游通信。修改方式如下所示:

1
2
3
4
5
6
#修改前
forward . /etc/resolv.conf
#修改后
forward . /etc/resolv.conf {
prefer_udp
}

DNS解析异常问题排查

诊断流程

基本概念

  • 集群内部域名:CoreDNS会将集群中的服务暴露为集群内部域名,默认以.cluster.local结尾,这类域名的解析通过CoreDNS内部缓存完成,不会从上游DNS服务器查询。
  • 集群外部域名:除了集群内部域名以外的域名。外部域名可由CoreDNS配置文件提供解析结果,或从DNSConfig配置文件中指定的上游DNS服务器查询,默认使用阿里云VPC中的私网DNS服务地址(100.100.2.136和100.100.2.138)。您可以修改其为您自建的DNS服务器。
  • 业务Pod:您部署在Kubernetes集群中的容器Pod,不包含Kubernetes自身系统组件的容器。
  • 接入CoreDNS的业务Pod:容器内DNS服务器指向了CoreDNS的业务Pod。
  • 接入NodeLocal DNSCache的业务Pod:集群中安装了NodeLocal DNSCache插件后,通过自动或手动方式注入DNSConfig的业务Pod。这类Pod在解析域名时,会优先访问本地缓存组件。如果访问本地缓存组件不通时,会访问CoreDNS提供的kube-dns服务。

异常诊断流程

  1. 判断当前的异常原因。具体信息,请参见常见客户端报错

    • 如果异常原因是域名不存在,请参见排查思路的《按解析异常的域名类型》。
    • 如果异常原因是无法连接至域名服务器,请参见排查思路的《按解析异常出现频次》。
  2. 如果以上排查无果,请按以下步骤排查。

  3. 如果以上排查无果,请提交工单排查。

常见客户端报错

客户端报错日志可能异常
pingping: xxx.yyy.zzz: Name or service not known域名不存在或无法连接域名服务器。如果解析延迟大于5秒,一般是无法连接域名服务器。
curlcurl: (6) Could not resolve host: xxx.yyy.zzz
PHP HTTP客户端php_network_getaddresses: getaddrinfo failed: Name or service not known in xxx.php on line yyy
Golang HTTP客户端dial tcp: lookup xxx.yyy.zzz on 100.100.2.136:53: no such host域名不存在。
dig;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: xxxxx
Golang HTTP客户端dial tcp: lookup xxx.yyy.zzz on 100.100.2.139:53: read udp 192.168.0.100:42922->100.100.2.139:53: i/o timeout无法连接域名服务器。
dig;; connection timed out; no servers could be reached

排查思路

常见检查方法

检查业务Pod的DNS配置

  • 命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #查看foo容器的YAML配置,并确认DNSPolicy字段是否符合预期。
    kubectl get pod foo -o yaml

    #当DNSPolicy符合预期时,可以进一步进入Pod容器中,查看实际生效的DNS配置。

    #通过bash命令进入foo容器,若bash不存在可使用sh代替。
    kubectl exec -it foo bash

    #进入容器后,可以查看DNS配置,nameserver后面为DNS服务器地址。
    cat /etc/resolv.conf
  • DNS Policy配置说明

    DNS Policy示例如下所示。

    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
    apiVersion: v1
    kind: Pod
    metadata:
    name: <pod-name>
    namespace: <pod-namespace>
    spec:
    containers:
    - image: <container-image>
    name: <container-name>

    #默认场景下的DNS Policy。
    dnsPolicy: ClusterFirst
    #使用了NodeLocal DNSCache时的DNS Policy。
    dnsPolicy: None
    dnsConfig:
    nameservers:
    - 169.254.20.10
    - 172.21.0.10
    options:
    - name: ndots
    value: "3"
    - name: timeout
    value: "1"
    - name: attempts
    value: "2"
    searches:
    - default.svc.cluster.local
    - svc.cluster.local
    - cluster.local

    securityContext: {}
    serviceAccount: default
    serviceAccountName: default
    terminationGracePeriodSeconds: 30

    | DNSPolicy字段值 | 使用的DNS服务器 |
    | :——————————— | :—————————————————————————————- |
    | Default | 只适用于不需要访问集群内部服务的场景。Pod创建时会从ECS节点/etc/resolv.conf文件继承DNS服务器列表。 |
    | ClusterFirst | 此为DNSPolicy默认值,Pod会将CoreDNS提供的kube-dns服务IP作为DNS服务器。开启HostNetwork的Pod,如果选择ClusterFirst模式,效果等同于Default模式。 |
    | ClusterFirstWithHostNet | 开启HostNetwork的Pod,如果选择ClusterFirstWithHostNet模式,效果等同于ClusterFirst。 |
    | None | 配合DNSConfig字段,可用于自定义DNS服务器和参数。在NodeLocal DNSCache开启注入时,DNSConfig会将DNS服务器指向本地缓存IP及CoreDNS提供的kube-dns服务IP。 |

检查CoreDNS Pod运行状态

命令

  • 执行以下命令,查看容器组信息。

    1
    kubectl -n kube-system get pod -o wide -l k8s-app=kube-dns

    预期输出:

    1
    2
    NAME                      READY   STATUS    RESTARTS   AGE   IP            NODE
    coredns-xxxxxxxxx-xxxxx 1/1 Running 0 25h 172.20.6.53 cn-hangzhou.192.168.0.198
  • 执行以下命令,查看Pod的实时资源使用情况。

    1
    kubectl -n kube-system top pod -l k8s-app=kube-dns

    预期输出:

    1
    2
    NAME                      CPU(cores)   MEMORY(bytes)
    coredns-xxxxxxxxx-xxxxx 3m 18Mi
  • 如果Pod不处于Running状态,可以通过kubectl -n kube-system describe pod <CoreDNS Pod名称>命令,查询问题原因。

检查CoreDNS运行日志

命令

执行以下命令,检查CoreDNS运行日志。

1
kubectl -n kube-system logs -f --tail=500 --timestamps coredns-xxxxxxxxx-xxxxx
参数描述
f持续输出。
tail=500输出最后500行日志。
timestamps同时显示日志打印的时间。
coredns-xxxxxxxxx-xxxxxCoreDNS Pod副本的名称。

检查CoreDNS DNS查询请求日志

命令

DNS查询请求日志仅会在开启CoreDNS的Log插件后,才会打印到容器日志中。关于开启Log插件的具体操作,请参见CoreDNS配置说明

命令与检查CoreDNS运行日志相同,请参见检查CoreDNS运行日志

检查CoreDNS Pod的网络连通性

操作步骤

  1. 登录CoreDNS Pod所在集群节点。

  2. 执行ps aux | grep coredns,查询CoreDNS的进程ID。

  3. 执行nsenter -t <pid> -n bash,进入CoreDNS所在容器网络命名空间,其中pid为上一步得到的进程ID。

  4. 测试网络连通性。

    1. 运行telnet <apiserver_slb_ip> 443,测试Kubernetes API Server的连通性。

      其中apiserver_slb_ip为default命名空间下Kubernetes服务的IP地址。

    2. 运行dig <domain> @<upstream_dns_server_ip>,测试CoreDNS Pod到上游DNS服务器的连通性。

      其中domain为测试域名,upstream_dns_server_ip为上游DNS服务器地址,默认为100.100.2.136和100.100.2.138。

常见问题

现象原因处理方案
CoreDNS无法连通Kubernetes API ServerAPIServe异常、机器负载高、kube-proxy 没有正常运行等。提交工单排查。
CoreDNS无法连通上游DNS服务器机器负载高、CoreDNS配置错误、专线路由问题等。提交工单排查。

检查业务Pod到CoreDNS的网络连通性

操作步骤

  1. 选择以下任意一种方式,进入客户端Pod容器网络。

    • 方法一:使用kubectl exec命令。

    • 方法二:

      1. 登录业务Pod所在集群节点。

      2. 执行ps aux | grep <业务进程名>命令,查询业务容器的进程ID。

      3. 执行

        1
        nsenter -t <pid> -n bash

        命令,进入业务Pod所在容器网络命名空间。

        其中pid为上一步得到的进程ID。

    • 方法三:如果频繁重启,请按以下步骤操作。

      1. 登录业务Pod所在集群节点。

      2. 执行docker ps -a | grep <业务容器名>命令,查询k8s_POD_开头的沙箱容器,记录容器ID。

      3. 执行docker inspect <沙箱容器 ID> | grep netns命令,查询/var/run/docker/netns/xxxx的容器网络命名空间路径。

      4. 执行

        1
        nsenter -n<netns 路径> bash

        命令,进入容器网络命名空间。

        其中netns 路径为上一步得到的路径。

        说明 -n<netns 路径>之间不加空格。

  2. 测试网络连通性。

    1. 执行dig <domain> @<kube_dns_svc_ip>命令,测试业务Pod到CoreDNS服务kube-dns解析查询的连通性。

      其中<domain>为测试域名,<kube_dns_svc_ip>为kube-system命名空间中kube-dns的服务IP。

    2. 执行ping <coredns_pod_ip>命令,测试业务Pod到CoreDNS容器副本的连通性。

      其中<coredns_pod_ip>为kube-system命名空间中CoreDNS Pod的IP。

    3. 执行dig <domain> @<coredns_pod_ip>命令,测试业务Pod到CoreDNS容器副本解析查询的连通性。

      其中<domain>为测试域名,<coredns_pod_ip>为kube-system命名空间中CoreDNS Pod的IP。

常见问题

现象原因处理方案
业务Pod无法通过CoreDNS服务kube-dns解析机器负载高、kube-proxy没有正常运行、安全组没有放开UDP协议53端口等。检查安全组是否放开UDP 53端口,若已放开请提交工单排查。
业务Pod无法连通CoreDNS容器副本容器网络异常或安全组没有放开ICMP。运行容器网络诊断。
业务Pod无法通过CoreDNS容器副本解析机器负载高、安全组没有放开UDP协议53端口等。检查安全组是否放开UDP 53端口,若已放开请提交工单排查。

容器网络诊断

  1. 登录容器服务管理控制台

  2. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情

  3. 在控制台左侧导航栏中,单击集群

  4. 在集群管理页左侧导航栏中,选择\运维管理\ > *集群检查***

  5. 容器智能运维的左侧导航栏,选择\检查\ > *故障诊断***

  6. 故障诊断页面,单击网络诊断页签。

  7. 源地址输入业务Pod IP,在目标地址输入CoreDNS服务kube-dns IP,在端口输入53,同时选中报文跟踪,选中我已知晓并同意,单击发起诊断

  8. 在故障诊断列表,单击目标诊断项右侧操作列的诊断详情

    根据诊断结果访问全图展开所有访问路径查看网络诊断详情,诊断结果将包含异常原因。关于网络诊断的具体操作,请参见通过集群故障诊断功能定位集群问题

抓包

当无法定位问题时,需要抓包进行辅助诊断。

  1. 登录出现异常的业务Pod、CoreDNS Pod所在节点。

  2. 在ECS(非容器内)执行以下命令,可以将最近所有的53端口信息抓取到文件中。

    1
    tcpdump -i any port 53 -C 20 -W 200 -w /tmp/client_dns.pcap
  3. 结合业务日志的报错定位到精准的报错时间的报文信息。

    说明

    • 在正常情况下,抓包对业务无影响,仅会增加小部分的CPU负载和磁盘写入。
    • 以上命令会对抓取到的包进行rotate,最多可以写200个20 MB的.pcap文件。

集群外部域名自身异常

问题原因

上游服务器返回记录显示域名异常。

问题现象

业务Pod可以正常解析集群内部域名,但无法解析某些集群外部域名。

解决方案

检查CoreDNS DNS查询请求日志。

常见请求日志

CoreDNS接收到请求并回复客户端后会打印一行日志,示例如下:

1
2
# 其中包含状态码RCODE NOERROR,代表解析结果正常返回。
[INFO] 172.20.2.25:44525 - 36259 "A IN redis-master.default.svc.cluster.local. udp 56 false 512" NOERROR qr,aa,rd 110 0.000116946s

常见返回码RCODE

关于返回码RCODE定义的具体信息,请参见规范

返回码RCODE含义原因
NXDOMAIN域名不存在容器内请求域名时,会被拼接上search后缀,若拼接的结果域名不存在,则会出现该请求码。如果确认日志中请求的域名内容存在,则说明存在异常。
SERVFAIL上游服务器异常常见于无法连接上游DNS服务器等情况。
REFUSED拒绝应答常见于CoreDNS配置或集群节点/etc/resolv.conf文件指向的上游DNS服务器无法处理该域名的情况,请排查CoreDNS配置文件。

新增Headless类型域名无法解析

问题原因

1.7.0以前版本CoreDNS会在API Server抖动时异常退出,导致Headless域名停止更新。

问题现象

接入CoreDNS的业务Pod无法解析新增的Headless类型域名。

解决方案

升级CoreDNS至1.7.0以上。具体操作,请参见【组件升级】CoreDNS升级公告

StatefulSets Pod域名无法解析

问题原因

StatefulSets Pod YAML中ServiceName必须和其暴露SVC的名字一致,否则无法访问Pod域名(例如pod.headless-svc.ns.svc.cluster.local),只能访问到服务域名(例如headless-svc.ns.svc.cluster.local)。

问题现象

Headless服务无法通过Pod域名解析。

解决方案

修改StatefulSets Pod YAML中ServiceName名称。

安全组、交换机ACL配置错误

问题原因

修改了ECS或容器使用的安全组(或交换机ACL),拦截了UDP协议下53端口的通信。

问题现象

部分节点或全部节点上接入CoreDNS的业务,Pod解析域名持续性失败。

解决方案

恢复安全组、交换机ACL的配置,放开其以UDP协议对53端口的通信。

容器网络连通性异常

问题原因

由于容器网络或其它原因导致的UDP协议53端口持续性不通。

问题现象

部分节点或全部节点上接入CoreDNS的业务,Pod解析域名持续性失败。

解决方案

运行容器网络诊断。具体操作,请参见通过集群故障诊断功能定位集群问题

CoreDNS Pod负载高

问题原因

由于CoreDNS副本数不足、业务请求量高等情况导致的CoreDNS负载高。

问题现象

  • 部分节点或全部节点接入CoreDNS的业务,Pod解析域名的延迟增加、概率性或持续性失败。
  • 检查CoreDNS Pod运行状态发现各副本CPU、Memory使用量接近其资源限制。

解决方案

  • 考虑采用NodeLocal DNSCache缓存方案,提升DNS解析性能,降低CoreDNS负载。具体操作,请参见使用NodeLocal DNSCache
  • 适当扩充CoreDNS副本数,使每个Pod的峰值CPU始终低于节点空闲CPU数。

CoreDNS Pod负载不均

问题原因

由于CoreDNS副本调度不均、Service亲和性设置导致CoreDNS Pod负载不均衡。

问题现象

  • 部分接入CoreDNS的业务Pod解析域名的延迟增加、概率性或持续性失败。
  • 检查CoreDNS Pod运行状态发现各副本CPU使用量负载不均衡。
  • CoreDNS副本数少于两个,或多个CoreDNS副本位于同节点上。

解决方案

  • 扩容并打散CoreDNS副本到不同的节点上。
  • 负载不均衡时,可禁用kube-dns服务的亲和性属性。具体操作,请参见配置Kube-DNS服务

CoreDNS Pod运行状态异常

问题原因

由于CoreDNS YAML模板、配置文件等导致CoreDNS运行异常。

问题现象

  • 部分接入CoreDNS的业务Pod解析域名的延迟增加、概率性或持续性失败。
  • CoreDNS副本状态Status不处于Running状态,或重启次数RESTARTS持续增加。
  • CoreDNS运行日志中出现异常。

解决方案

检查CoreDNS Pod运行状态和运行日志。

常见异常日志及处理方案

日志中字样原因处理方案
/etc/coredns/Corefile:4 - Error during parsing: Unknown directive 'ready'配置文件和CoreDNS不兼容,Unknown directive代表当前运行的CoreDNS版本不支持ready插件。从kube-system命名空间中CoreDNS配置项中删除ready插件,其它报错同理。
pkg/mod/k8s.io/client-go@v0.18.3/tools/cache/reflector.go:125: Failed to watch *v1.Pod: Get "https://192.168.0.1:443/api/v1/": dial tcp 192.168.0.1:443: connect: connection refused日志出现时间段内,API Server中断。如果是日志出现时间和异常不吻合,可以排除该原因,否则请检查CoreDNS Pod网络连通性。具体操作,请参见检查CoreDNS Pod的网络连通性
[ERROR] plugin/errors: 2 www.aliyun.com. A: read udp 172.20.6.53:58814->100.100.2.136:53: i/o timeout日志出现时间段内,CoreDNS无法连接到上游DNS服务器。

客户端负载原因导致解析失败

问题原因

接入CoreDNS的业务Pod所在ECS负载达到100%等情况导致UDP报文丢失。

问题现象

业务高峰期间或突然偶发的解析失败,ECS监控显示机器网卡重传率、CPU负载有异常。

解决方案

Conntrack表满

问题原因

Linux内Conntrack表条目有限,无法进行新的UDP或TCP请求。

问题现象

  • 部分节点或全部节点上接入CoreDNS的业务,Pod解析域名在业务高峰时间段内出现大批量域名解析失败,高峰结束后失败消失。
  • 运行dmesg -H,滚动到问题对应时段的日志,发现出现conntrack full字样的报错信息。

解决方案

增加Conntrack表限制。具体操作,请参见如何提升Linux连接跟踪Conntrack数量限制?

AutoPath插件异常

问题原因

CoreDNS处理缺陷导致AutoPath无法正常工作。

问题现象

  • 解析集群外部域名时,概率性解析失败或解析到错误的IP地址,解析集群内部域名无异常。
  • 高频创建容器时,集群内部服务域名解析到错误的IP地址。

解决方案

按照以下步骤,关闭AutoPath插件。

  1. 执行kubectl -n kube-system edit configmap coredns命令,打开CoreDNS配置文件。
  2. 删除autopath @kubernetes一行后保存退出。
  3. 检查CoreDNS Pod运行状态和运行日志,运行日志中出现reload字样后说明修改成功。

A记录和AAAA记录并发解析异常

问题原因

并发A和AAAA的DNS请求触发Linux内核Conntrack模块缺陷,导致UDP报文丢失。

问题现象

  • 接入CoreDNS的业务Pod解析域名概率性失败。
  • 从抓包或检查CoreDNS DNS查询请求日志可以发现,A和AAAA通常在同一时间的出现,并且请求的源端口一致。

解决方案

  • 考虑采用NodeLocal DNSCache缓存方案,提升DNS解析性能,降低CoreDNS负载。具体操作,请参见使用NodeLocal DNSCache
  • CentOS、Ubuntu等基础镜像,可以通过options timeout:2 attempts:3 rotate single-request-reopen等参数优化。
  • 如果容器镜像是以Alpine制作的,建议更换基础镜像。更多信息,请参见Alpine
  • PHP类应用短连接解析问题较多,如果使用的是PHP Curl的调用,可以使用CURL_IPRESOLVE_V4参数仅发送IPv4解析。更多信息,请参见函数说明

IPVS缺陷导致解析异常

问题原因

若您集群的kube-proxy负载均衡模式为IPVS,在CentOS、Alibaba Cloud Linux 2内核版本小于4.19.91-25.1.al7.x86_64的节点上,摘除IPVS UDP类型后端后,一段时间内若新发起的UDP报文源端口冲突,该报文会被丢弃。

问题现象

当集群节点扩缩容、节点关机、CoreDNS缩容时,出现概率性解析失败,通常时长在五分钟左右。

解决方案

NodeLocal DNSCache未生效

问题原因

  • 未配置DNSConfig注入,业务Pod实际仍配置了CoreDNS kube-dns服务IP作为DNS服务器地址。
  • 业务Pod采用Alpine作为基础镜像,Alpine基础镜像会并发请求所有nameserver,包括本地缓存和CoreDNS。

问题现象

NodeLocal DNSCache没有流量进入,所有请求仍在CoreDNS上。

解决方案

  • 配置DNSConfig自动注入。具体操作,请参见使用NodeLocal DNSCache
  • 如果容器镜像是以Alpine制作的,建议更换基础镜像。更多信息,请参见Alpine

PrivateZone域名解析异常

问题原因

PrivateZone不支持TCP协议,需要使用UDP协议访问。

问题现象

对于接入NodeLocal DNSCache的业务,Pod无法解析PrivateZone上注册的域名,或无法解析包含vpc-proxy字样的阿里云云产品API域名,或解析结果不正确。

解决方案

在CoreDNS中配置prefer_udp。具体操作,请参见CoreDNS配置说明

解析外部域名很慢或超时,如何优化配置?

工作负载的容器内的resolv.conf文件,示例如下:

其中:

  • nameserver:DNS服务器的IP地址,此处为coredns的ClusterIP。
  • search:域名的搜索列表,此处为Kubernetes的常用后缀。
  • ndots:“.”的个数小于它的域名,会优先使用search进行解析。
  • timeout:超时时间。
  • single-request-reopen:发送A类型请求和AAAA类型请求使用不同的源端口。

在界面创建工作负载时,以上几项配置默认都会创建,具体参数如下:

1
2
3
4
5
6
7
dnsConfig:
options:
- name: timeout
value: '2'
- name: ndots
value: '5'
- name: single-request-reopen

以上参数可以根据业务需要进行优化或修改。

场景一:解析外部域名慢

优化方案

如果此工作负载不需要访问集群内的k8s服务,可以将dnsPolicy设置为“Default”

如果将dnsPolicy设置为“Default”,名称解析配置将从运行pod的工作节点继承(即宿主机)

但需要注意的是:这会导致 Pod 内部看到的 DNS 服务器实际上是 systemd-resolved 的本地stub监听地址,而非真正的上游 DNS 服务器。

当使用如 tcpSocket 类型的 livenessProbe,连接这个 stub 地址会检测失败导致服务无法正常启动。

如果此工作服务访问其他的k8s服务时,使用的域名中“.”的个数小于2,可以将ndots参数设置为2。

ndots默认值为5,5就是5个点号

5个点号 的意思就是说

对于一个 域名, 如果不是完全限定名(即某个域名不是以. 结尾, a.com 不是, a.com. 是)

且点号数量少于5个, 那么就按照 search 的顺序,依次拼接其再解析

如果点号大于或者等于5, 直接使用nameserver对应的dns解析

场景二:解析外部域名超时

优化方案:

  1. 通常业务内的超时时间要大于timeout * attempts的时间。
  2. 如果解析此域名通常要超过2s,可以将timeout改大。