拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Kubernetes服务发现与CoreDNS核心机制详解

1. 从“服务发现”说起为什么Kubernetes离不开DNS如果你在Kubernetes里跑过几个Pod尝试过让一个Pod去访问另一个Pod你大概率不会去记那个又长又难记的Pod IP比如10.244.1.5。你更希望像在互联网上访问www.google.com一样用一个好记的名字比如my-frontend-service。这个“把名字变成IP地址”的过程就是服务发现而DNS域名系统是实现服务发现最自然、最通用的方式。Kubernetes将这套机制深度集成让集群内的应用可以像访问外部网站一样通过域名来访问内部服务、Pod甚至外部端点极大地简化了微服务间的通信配置。在Kubernetes的早期版本中集群DNS功能由kube-dns组件提供。但从1.11版本开始CoreDNS作为其继任者成为了默认的DNS服务器。这个转变并非偶然。CoreDNS采用Go语言编写以其模块化、灵活性和高性能著称。它不像传统的BIND那样拥有一个庞大而复杂的配置文件而是通过一个名为Corefile的简洁配置文件以插件链Plugin Chain的方式组织功能。这种设计使得CoreDNS能够轻松适应Kubernetes动态、声明式的环境高效地响应服务、Pod和节点的频繁变化。简单来说没有DNS的Kubernetes集群就像一座没有路标和门牌号的城市。服务之间只能通过原始的IP地址进行“盲找”一旦Pod重启或服务扩缩容导致IP变更整个通信链路就会断裂。CoreDNS就是这个城市里的“动态地址簿”和“智能查询中心”它持续监听Kubernetes API Server实时更新服务与IP的映射关系确保无论后端如何变化前端应用始终能用同一个稳定的域名找到它。2. CoreDNS在Kubernetes中的核心工作机制要理解CoreDNS如何工作我们需要深入到它的部署和查询流程中。当你部署一个标准的Kubernetes集群例如使用kubeadm时CoreDNS通常会以Deployment的形式运行在kube-system命名空间下背后有一个Service为其提供稳定的集群IP。2.1 默认的域名解析逻辑每个Pod在创建时其/etc/resolv.conf文件会被Kubernetes自动注入DNS配置。这个文件决定了Pod如何进行域名解析。一个典型的内容如下nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5我们来拆解这几个关键配置nameserver 10.96.0.10 这是CoreDNS Service的集群IP。Pod发出的所有DNS查询默认都会发送到这个地址。search域 这是一个域名后缀列表。当Pod尝试解析一个不完全合格域名例如只写了服务名redis时系统会依次拼接这些后缀进行查询。查询顺序是redis.default.svc.cluster.local-redis.svc.cluster.local-redis.cluster.local。这允许你在Pod内用短名称如redis访问同一命名空间的服务用service.namespace如redis.prod访问其他命名空间的服务。options ndots:5 这是一个性能优化有时也是坑点相关的选项。它规定如果一个域名中的点.数量大于等于5则会被视为绝对域名FQDN直接查询不会走search域拼接。如果点数少于5则会先尝试拼接search域查询失败后再尝试直接查询。理解这一点对排查某些解析超时问题至关重要。2.2 CoreDNS的配置核心CorefileCoreDNS的行为由一个名为Corefile的配置文件驱动。在Kubernetes中这个配置通常以一个ConfigMap的形式存在名为coredns位于kube-system命名空间。让我们看一个最简化的默认配置kubectl get configmap coredns -n kube-system -o yaml其Corefile部分可能如下.:53 { errors # 将错误日志输出到标准输出 health { # 健康检查端点默认监听8080端口 lameduck 5s } ready # 就绪检查端点用于Kubernetes的Readiness Probe kubernetes cluster.local in-addr.arpa ip6.arpa { # 核心插件处理Kubernetes域名的解析 pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 # 暴露Prometheus指标 forward . /etc/resolv.conf # 将非集群域名的查询转发到上游DNS cache 30 # 缓存 loop # 检测DNS循环查询并终止 reload # 允许自动重载配置修改ConfigMap后CoreDNS Pod会自动加载新配置 loadbalance # DNS负载均衡对同一域名的多条A记录进行轮询 }这个配置文件定义了一个监听在53端口的服务器块。其中kubernetes插件是灵魂所在。它告诉CoreDNS负责解析cluster.local及其子域如svc.cluster.local的请求。当收到一个对my-svc.default.svc.cluster.local的查询时这个插件会去查询Kubernetes API获取名为my-svc、位于default命名空间的Service的ClusterIP并返回给客户端。forward . /etc/resolv.conf这一行则指明了“非Kubernetes域名”的去向。例如Pod内查询www.baidu.com由于该域名不匹配cluster.localCoreDNS会将查询转发到Pod自身的/etc/resolv.conf中定义的上游DNS通常是宿主机的DNS或外部公共DNS从而实现内外网域名的统一解析。2.3 解析流程全景图假设一个PodPod A想要访问同一个命名空间下的服务backend整个DNS解析流程如下Pod A内的应用程序发起对backend的DNS查询。查询请求被发送到本地/etc/resolv.conf中定义的CoreDNS Service IP10.96.0.10。请求到达某个CoreDNS Pod。CoreDNS根据Corefile配置首先检查域名。backend的点数少于5ndots:5且不是FQDN因此CoreDNS会先为其拼接search域。它首先尝试查询backend.default.svc.cluster.local。这个域名匹配kubernetes插件负责的cluster.local域。kubernetes插件拦截该查询向Kubernetes API Server询问在default命名空间下是否存在一个名为backend的ServiceAPI Server返回该Service的ClusterIP例如10.103.156.88。CoreDNS将这个IP地址作为DNS响应返回给Pod A。Pod A的应用程序拿到IP发起实际的TCP/UDP连接到10.103.156.88:port由kube-proxy或CNI如果使用IPVS模式或某些服务网格完成到后端Pod的负载均衡和流量转发。这个过程对应用完全透明开发者无需关心后端Pod的具体位置和IP实现了彻底的解耦。3. 深入解析CoreDNS如何映射Kubernetes资源CoreDNS的kubernetes插件不仅仅能解析Service。通过配置它可以处理多种Kubernetes资源形成一套完整的集群内域名体系。3.1 标准域名格式Service 这是最常用的形式。格式service-name.namespace-name.svc.cluster.local解析结果对应Service的ClusterIP。如果是Headless ServiceclusterIP: None则返回该Service后端所有Pod的IP地址列表。示例backend.default.svc.cluster.local-10.103.156.88Pod 虽然不推荐直接通过Pod IP通信但CoreDNS也支持通过DNS直接定位Pod。格式pod-ip.namespace.pod.cluster.local注意这里的pod-ip需要将点.替换为横线-。例如Pod IP10.244.1.5对应的域名是10-244-1-5.default.pod.cluster.local。这主要用于一些特殊场景如StatefulSet中Pod需要有稳定的网络标识。Service端口 可以解析SRV记录获取服务的端口和协议信息。格式_port-name._protocol.service.ns.svc.cluster.local这在某些需要动态发现端口的客户端中会用到。3.2 Headless Service与StatefulSet的特别之处Headless Service无头服务是一个特例。当你创建一个clusterIP: None的Service时它不会被分配ClusterIP。此时对它进行DNS查询行为会有所不同如果该Service没有关联任何Selector则DNS查询会返回该Service配置的所有Endpoints手动指定的地址列表。如果该Service有关联Selector最常见的是与StatefulSet配合DNS查询会返回该Selector匹配的所有Pod IP地址的列表。StatefulSet与Headless Service是黄金搭档。StatefulSet创建的每个Pod都有稳定的名称statefulset-name-ordinal。当为StatefulSet创建一个同名的Headless Service后每个Pod会获得一个稳定的DNS域名格式pod-name.headless-svc-name.namespace.svc.cluster.local示例对于一个名为web的StatefulSet和一个名为nginx的Headless Service第一个Pod的域名是web-0.nginx.default.svc.cluster.local。这个域名直接解析到该Pod的IP并且在该Pod的生命周期内是稳定的即使Pod重启、重建只要名字不变域名解析就不变。这对于构建有状态应用集群如ZooKeeper, Elasticsearch至关重要集群成员可以通过这些稳定的域名互相发现。3.3 自定义上游与存根域Stub Domains在企业环境中我们经常需要让集群内的Pod能够解析内部的私有域名比如company.internal。这可以通过CoreDNS的forward插件或hosts插件来实现但更Kubernetes原生、更灵活的方式是配置存根域和上游域名服务器。你可以在CoreDNS的ConfigMap中修改Corefile添加针对特定域名的转发规则.:53 { ... kubernetes cluster.local in-addr.arpa ip6.arpa { ... } # 将 company.internal 域的所有查询转发到指定的内部DNS服务器 forward company.internal 10.100.10.1 10.100.10.2 # 将所有其他非集群域名查询转发到宿主机/etc/resolv.conf定义的上游 forward . /etc/resolv.conf ... }这样当Pod查询db.company.internal时CoreDNS会将其转发到10.100.10.1或10.100.10.2而不是公共DNS。这种配置使得混合云或需要访问企业内网服务的场景变得非常简单。4. 实战CoreDNS的配置、调优与故障排查了解了原理我们来看看如何管理和维护CoreDNS。4.1 扩缩容与资源限制默认的CoreDNS Deployment通常只有2个副本。在生产环境中这可能需要根据集群规模进行调整。你可以直接修改其Deployment的副本数kubectl scale deployment coredns --replicas3 -n kube-system同样默认的资源请求和限制可能偏低。高负载下CoreDNS可能因内存不足OOM被杀。你需要编辑其Deployment调整资源配额。一个中型集群的参考配置如下# kubectl edit deployment coredns -n kube-system resources: limits: memory: 256Mi cpu: 500m requests: memory: 128Mi cpu: 100m注意 CPU请求不宜设得过低否则在节点CPU竞争激烈时CoreDNS处理查询的延迟会显著增加表现为应用DNS解析超时。内存限制需要监控实际使用量来设定如果CoreDNS频繁OOM除了增加限制还应检查是否存在异常的高频查询或环路。4.2 性能调优缓存与负载均衡cache插件 默认配置中的cache 30表示缓存TTL为30秒。对于解析结果几乎不变的内部服务可以适当增加缓存时间如300秒以减少对API Server的查询压力。对于外部域名需谨慎因为过长的缓存可能导致IP变更不及时。你可以为不同区域配置不同的缓存策略。loadbalance插件 当Service对应多个EndpointPod IP时此插件会对返回的A记录进行轮询Round Robin。这能在DNS层面实现简单的客户端负载均衡。大多数情况下应该开启。一个调优后的Corefile片段示例.:53 { ... kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 # 可以适当增加比如300减少API查询 } cache { success 300 # 成功响应缓存5分钟 denial 30 # NXDOMAIN响应缓存30秒 } loadbalance round_robin ... }4.3 监控与日志监控 CoreDNS默认集成了prometheus插件在9153端口暴露指标。你可以通过Prometheus收集这些指标关键指标包括coredns_dns_request_count_total 总请求数按类型、区域统计。coredns_dns_request_duration_seconds 请求延迟分布。coredns_dns_response_rcode_count_total 响应码统计NOERROR, NXDOMAIN, SERVFAIL等帮助发现解析失败问题。coredns_panic_count_total CoreDNS崩溃次数。日志errors插件会将错误日志打印到标准输出。你可以通过kubectl logs查看。对于更详细的调试可以启用log插件但它会产生大量日志仅建议在排查问题时临时开启。4.4 常见故障排查场景与命令当遇到“服务无法解析”或“解析超时”问题时可以按照以下链路排查场景一Pod内无法解析任何域名检查CoreDNS Pod状态kubectl get pods -n kube-system -l k8s-appkube-dns确保所有Pod都是Running且READY为2/2一个容器是CoreDNS另一个通常是用于节点本地缓存的node-cache如果部署了的话。检查CoreDNS Servicekubectl get svc kube-dns -n kube-system确认Service存在且有ClusterIP通常是10.96.0.10。进入问题Pod检查DNS配置kubectl exec -it problem-pod -- cat /etc/resolv.conf确认nameserver指向的是正确的CoreDNS Service IP。从Pod内测试DNS查询kubectl exec -it problem-pod -- nslookup kubernetes.default # 或者使用 busybox 镜像 kubectl run -it --rm --restartNever debug --imagebusybox:1.28 -- nslookup kubernetes.default如果失败尝试直接查询CoreDNS Pod IP绕过Service# 获取一个CoreDNS Pod的IP COREDNS_POD_IP$(kubectl get pods -n kube-system -l k8s-appkube-dns -o jsonpath{.items[0].status.podIP}) kubectl exec -it problem-pod -- nslookup kubernetes.default $COREDNS_POD_IP如果直接访问Pod IP成功但通过Service IP失败问题可能出在kube-proxy或网络插件上Service网络不通。场景二可以解析外部域名但无法解析内部服务检查CoreDNS日志kubectl logs -n kube-system deployment/coredns --tail50查看是否有关于kubernetes插件的错误例如连接API Server失败。检查RBAC权限 CoreDNS需要相应的RBAC权限来访问API Server。通常这些配置在安装时已设置好但如果被误修改会导致无法查询服务信息。检查ClusterRolesystem:coredns的权限。检查Corefile配置 确认kubernetes插件配置的域cluster.local是否正确是否覆盖了你需要解析的域名。场景三DNS解析间歇性超时或延迟很高检查资源限制 如前所述检查CoreDNS Pod的CPU请求是否过低是否被其他Pod挤压。检查ndots配置 这是最常见的坑之一。假设Pod内频繁查询一个包含4个点的外部域名如my.app.prod.company.com。由于ndots:5点数45系统会先尝试拼接search域产生一系列无用的查询如my.app.prod.company.com.default.svc.cluster.local全部失败后才会发起原始查询导致显著延迟。解决方案A应用侧 在应用的连接字符串中使用完全合格域名FQDN即以点结尾如my.app.prod.company.com.。这样系统会直接查询不走search域。解决方案B集群侧 修改Pod或Namespace级别的DNS策略。可以为Pod Spec添加dnsConfig降低ndots值或减少search域。但这需要修改应用部署配置。spec: dnsConfig: options: - name: ndots value: 2 # 降低ndots值 dnsPolicy: None # 必须设置为None才能使用dnsConfig检查网络插件 某些网络插件如Calico、Cilium的配置可能会影响Pod与CoreDNS Service之间的网络连通性或性能。场景四自定义上游域名解析失败检查Corefile中的forward规则 确认IP地址和端口是否正确上游DNS服务器是否可达。从CoreDNS Pod内测试上游kubectl exec -it -n kube-system coredns-pod -- nslookup your-internal-domain upstream-dns-ip检查网络策略 如果集群启用了NetworkPolicy请确认是否有策略允许CoreDNS Pod访问上游DNS服务器的53端口。通过以上结构化的排查步骤大部分CoreDNS相关的问题都能被定位和解决。记住在Kubernetes中DNS问题常常表现为网络连通性问题掌握其工作原理和排查工具是运维人员的必备技能。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门