当前位置: 首页 > news >正文

15. CoreDNS

CoreDns

什么需要服务发现?

在 Kubernetes 中,Pod 是有生命周期的,IP 会变化,因此不能直接使用 Pod IP。

Kubernetes 通过 Service 暴露一组 Pod,并提供稳定的 ClusterIP。

但是,其他应用怎么知道 Service 的 IP?

这就需要“服务发现”

服务发现方式 1:环境变量(旧方案)

原理

Pod 启动时,kubelet 将当前所有 Service 的信息(IP/端口等)注入为环境变量,例如:

NGINX_SERVICE_SERVICE_HOST=10.111.22.33
NGINX_SERVICE_SERVICE_PORT=5000

容器内即可通过环境变量访问服务。

缺点(致命)

依赖服务必须在 Pod 启动前存在
否则环境变量不会被注入。

这就导致:

先启动应用 Pod,再创建 Service → Pod 无法获取环境变量

必须保证启动顺序(使用 initContainer 或其他手段)→ 增加复杂性

因此环境变量被判定为 不适合动态微服务系统。

服务发现方式 2:DNS(推荐)

DNS 是互联网使用的 IP 发现标准方式,Kubernetes 中也采用 DNS 来解决服务发现问题。

DNS 解析流程(互联网版)

DNS 递归解析过程包含以下角色:

  • 递归解析器(Resolver)
  • 根域名服务器(.)
  • 顶级域名服务器(TLD,例如 .com)
  • 权威 DNS 服务器

解析步骤概述:

  1. 浏览器向递归解析器查询
  2. 解析器问根服务器
  3. 根服务器返回 TLD 服务器地址
  4. 解析器问 TLD
  5. TLD 返回权威服务器地址
  6. 解析器问权威服务器
  7. 返回该域名的 IP

K8s 的 DNS 服务:CoreDNS

Kubernetes 通过 CoreDNS 提供集群内部的 DNS 解析,用于:

  • Service 名称 → ClusterIP
  • Headless Service → Pod IP 列表
  • Pod 名称 → Pod IP

CoreDNS 由 Deployment + Service(ClusterIP)构成,一般地址为:
10.96.0.10

由 kubelet 配置给每个 Pod:

clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local

K8s 中 Service 的域名规则

  1. 普通 Service

生成 DNS 域名:

servicename.namespace.svc.cluster.local

在 Pod 内部简写方式:

写法 说明
servicename 同 namespace
servicename.namespace 不同 namespace
servicename.namespace.svc.cluster.local 完整 FQDN

示例

访问 nginx-service(端口 5000):

curl nginx-service:5000
curl nginx-service.default.svc
curl nginx-service.default.svc.cluster.local
  1. Headless Service(clusterIP: None)

返回 Pod IP 列表:

A 记录:pod1_IP  
A 记录:pod2_IP

可用于负载均衡或自定义服务发现机制(如 gRPC、StatefulSet)。

也可通过以下方式访问具体 Pod:

podname.servicename.namespace.svc.cluster.local

CoreDNS 默认配置(解释重要插件)

插件 作用
kubernetes Service/Pod DNS 解析核心插件
forward 非集群域名转发到宿主机 DNS
cache DNS 缓存
log 输出解析日志
reload 动态加载配置
health / ready 健康检查
loadbalance 返回记录时随机排序

常用 CoreDNS 扩展方式

1. 启用日志功能

log

2. 特定域名使用自定义 DNS 服务器

example.com:53 {forward . 10.10.0.10
}

自定义 hosts 映射

hosts {127.0.0.1 www.example.comfallthrough
}

内外统一域名 rewrite

将 foo.example.com → foo.default.svc.cluster.local

rewrite stop {name regex foo.example.com foo.default.svc.cluster.localanswer name foo.default.svc.cluster.local foo.example.com
}

禁止 AAAA(IPv6)解析加速 DNS 查询

template IN AAAA .

验证 CoreDNS 是否正常工作

创建测试 Pod:

image: cnych/jessie-dnsutils
command: ["sleep", "infinity"]

查看 DNS 配置:

cat /etc/resolv.confnameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
# 注意 search 域决定了 DNS 查询顺序。

DNS 查询效率问题:curl s 与 curl s.default

curl s
# DNS 会依次尝试:
# s.default.svc.cluster.local
# s.svc.cluster.local
# s.cluster.local
curl s.default
# DNS 会先查询: s.default.<search-domain>
# 因为 curl s.default 比 curl s 多一次失败查询,因此效率稍低。

ndots / DNS 查找行为(要点)

ndots 是 resolv.conf 的一个选项,控制“是否把一个查询名视为可能的绝对(FQDN)”的阈值。

规则(常见 resolver 行为):

  • 若查询名中 . 的数量 ≥ ndots,则 先把该名字当作绝对(带 . 结尾的 FQDN)进行解析(即直接查询 name.)。
  • 如果绝对解析失败,才会尝试使用 search 列表逐项追加后缀再次解析。
  • 若查询名中 . 的数量 < ndots,则先用 search 一项项追加后缀去解析(例如 name.ns.svc.cluster.local),全部失败后才以绝对名再试一次(name.)。

Kubernetes 集群默认:ndots:5,目的是优先匹配集群内较长的服务名(例如 a.b.c.d.e 属于内部名字,应优先走集群 DNS),从而避免不必要地把内部名发到上游公网解析器。

举例:

假设 search 为 default.svc.cluster.local svc.cluster.local cluster.local。

  1. ndots:5,查询 a.b.c.d.e(有 4 个 .)
  • 4 < 5 → 先走 search:
  • a.b.c.d.e.default.svc.cluster.local → 若失败再试 a.b.c.d.e.svc.cluster.local → … → 最后再试 a.b.c.d.e.(绝对名)。
  1. ndots:5,查询 a.b.c.d.e.f(有 5 个 .)
  • 5 ≥ 5 → 先试 a.b.c.d.e.f.(绝对名)。如果失败,再按 search 列表尝试追加后缀(实现依赖解析库,但多数实现会在绝对名失败后继续尝试 search)。
  1. 如果你在名字末尾加 .,例如 youdianzhishi.com. —— 解析器直接按绝对名处理,跳过 search 列表(节省查询和延迟)。

如何查看 Pod 的 ndots / resolv.conf

kubectl exec -it <pod> -- cat /etc/resolv.conf
# 会看到类似:
# search default.svc.cluster.local svc.cluster.local cluster.local
# nameserver 10.96.0.10
# options ndots:5

你也可以在 Pod spec 中通过 dnsConfig.options 设置/覆盖 ndots:

dnsPolicy: "None"           # 或者其它策略,dnsConfig 可与任意策略一起使用(dnsPolicy: None 时必须指定 dnsConfig)
dnsConfig:options:- name: ndotsvalue: "1"

调试与抓包(常用技巧)

  • 在 Pod 内运行 nslookup / dig 来观察 resolver 行为(是否走 search、是否为绝对名、返回的 nameserver)。

  • 为观察 CoreDNS 日志,可在 CoreDNS 配置里启用 log 插件,观察解析请求与来源。

  • 做抓包(tcpdump):

    • 若容器内无 tcpdump,可切到宿主机,进入目标容器的网络 namespace(用 crictl / docker 或者 kubectl debug)并在 namespace 内执行 tcpdump。

    • 或用 kubectl-debug / ephemeral containers 插入调试容器来抓包。

性能与可靠性建议

  • 保留默认 ndots:5:对于大多数 k8s 集群这是合理的,因为它降低了内部长域名被外部 DNS 误解析的概率。

  • 对外网密集型服务可以调整为 ndots:1/2:如果应用大量访问外部短域名(如 api.example.com)且对解析延迟敏感,可为该 Pod 单独设置 ndots:1,减少 search 尝试,直接用绝对查询。

  • 最好使用 FQDN(并在需要时加 .):应用里尽量使用 service.namespace.svc.cluster.local(或在代码里配置),或在需要规避 search 的地方在域名末尾加 .,可避免额外的 search 查询。

  • 减少 search 列表长度:Kubernetes 最多允许 6 个搜索域,过多的 search 域会导致更多尝试和额外延迟。尽量使 search 列表精简。

  • 对 stateful/依赖 pod IP 的服务,使用 headless service:避免通过 DNS 轮询引入不确定性。

  • 监控 CoreDNS 延迟与查询失败率:若看到大量超时或转发到上游的查询(尤其是 IPv6 AAAA 导致的额外延迟),考虑使用 template IN AAAA . 或优化 forward 配置。

性能优化

DNS 5s问题

核心问题:客户端(glibc/musl)并行发 A/AAAA 请求导致相同五元组的 UDP 报文在内核 conntrack 插入时竞争或被丢弃,表现为 随机 5s DNS 超时(重试等待)。 Linux 内核问题。

使用TCP发送DNS请求[不推荐]

# 在 Pod 或主机的 /etc/resolv.conf 中加入:
options use-vc

Pod 中的 resolv.conf 是由 Kubelet 生成的,不允许你直接写文件,只能用 dnsConfig 注入 options。

apiVersion: v1
kind: Pod
metadata:name: test-vc
spec:containers:- name: busyboximage: busyboxcommand: ["sleep", "3600"]dnsPolicy: ClusterFirstdnsConfig:options:- name: use-vc

说明:

  • 使用 TCP 查询 DNS
  • 不走 UDP → 不会触发 UDP conntrack 问题
  • CoreDNS 端要求支持 TCP(默认支持)

缺点:

  • TCP 开销较大,性能比 UDP 差

避免相同五元组DNS请求的并发[不推荐]

single-request-reopen发送A类型请求和AAAA类型请求使用不同的源端口(Socket)。这样两个请求在conntrack表中不占用同一个表项,从而避免冲突。

single-request避免并发,改为串行发送A类型和AAAA类型请求。没有了并发,从而也避免了冲突。

options single-request-reopen

K8s中

apiVersion: v1
kind: Pod
metadata:name: test-srr
spec:containers:- name: busyboximage: busyboxcommand: ["sleep", "3600"]dnsPolicy: ClusterFirstdnsConfig:options:- name: single-request-reopen

没什么必要 NodeLocal DNSCache 方案比这个好很多。

NodeLocalDNS

NodeLocal DNSCache(nodelocaldns)通过:

  • 在 每个节点运行一个本地 DNS 缓存
  • Pod 的解析直接访问 NodeLocalDNS(本地 169.254.20.10)
  • 缓存不存在时再代理到 kube-dns,并强制使用 TCP

1. 获取Yaml

wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml

2. 修改 YAML 中的几个关键变量

占位符 说明
__PILLAR__DNS__SERVER__ kube-dns ClusterIP
__PILLAR__LOCAL__DNS__ NodeLocalDNS 在本机监听的 IP(一般 169.254.20.10)
__PILLAR__DNS__DOMAIN__ 集群域名(一般 cluster.local)
__PILLAR__UPSTREAM__SERVERS__ 外部 DNS(8.8.8.8 / 114.114.114.114 等)
# 获取 kube-dns ClusterIP
ubuntu@ubuntu:~$ kubectl get svc -n kube-system kube-dns
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   77d
# NodeLocalDNS 可以是任何地址,只要该地址不和你的集群里现有的 IP 地址发生冲突即可
# 集群域名 一般 cluster.local 除非安装时指定 
# 可以执行下方去查询
ubuntu@ubuntu:~$ kubectl get cm -n kube-system kubeadm-config -o yaml

替换 YAML 内容

ubuntu@ubuntu:~$ sed \-e 's/__PILLAR__DNS__SERVER__/10.96.0.10/g' \-e 's/__PILLAR__LOCAL__DNS__/169.254.20.10/g' \-e 's/__PILLAR__DNS__DOMAIN__/cluster.local/g' \nodelocaldns.yaml | kubectl apply -f -
serviceaccount/node-local-dns created
service/kube-dns-upstream created
configmap/node-local-dns created
daemonset.apps/node-local-dns created
service/node-local-dns created
# 查看是否成功
ubuntu@ubuntu:~$ kubectl get pods -n kube-system -l k8s-app=node-local-dns -o wide
NAME                   READY   STATUS    RESTARTS   AGE    IP                NODE     NOMINATED NODE   READINESS GATES
node-local-dns-c9ktr   1/1     Running   0          104s   192.168.236.103   node2    <none>           <none>
node-local-dns-lqf85   1/1     Running   0          104s   192.168.236.101   master   <none>           <none>
node-local-dns-t5lnl   1/1     Running   0          104s   192.168.236.102   node1    <none>           <none>

开启 NodeLocalDNS(关键部分)

NodeLocalDNS 部署好之后,Pod 并不会自动使用它

你必须让 kubelet 或 Pod 的 resolv.conf 指向它。

# 查看配置
kubectl -n kube-system get configmap kube-proxy -o yaml
# 看model是啥, 空为iptables

修改默认clusterDns配置

# 修改配置 每个节点都执行
ubuntu@ubuntu:~/example/dns$ sudo sed -i 's/10.96.0.10/169.254.20.10/g' /var/lib/kubelet/config.yaml
ubuntu@ubuntu:~/example/dns$ sudo systemctl daemon-reload
ubuntu@ubuntu:~/example/dns$ sudo systemctl restart kubelet

注意: 这个先去测试执行,再去生产执行。保险的话不修改默认的,手动指定 dnsnamespace。

验证 NodeLocalDNS 是否生效

创建Pod

# dns-test.yaml
apiVersion: v1
kind: Pod
metadata:name: dns-test
spec:containers:- name: testimage: busyboxargs: ["sleep", "3600"]

验证:

# 查看dns
ubuntu@ubuntu:~/example/dns$ kubectl exec -it dns-test -- /bin/sh
/ # cat /etc/resolv.conf 
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 169.254.20.10
options ndots:5
# 追踪解析
/ # nslookup www.baidu.com
Server:		169.254.20.10
Address:	169.254.20.10:53Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 183.2.172.17
Name:	www.a.shifen.com
Address: 183.2.172.177Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 240e:ff:e020:99b:0:ff:b099:cff1
Name:	www.a.shifen.com
Address: 240e:ff:e020:98c:0:ff:b061:c306
/ # 

旧POD不会一起更新配置,请采用滚动更新的办法重启

http://www.jsqmd.com/news/45443/

相关文章:

  • 山西忻州一对一辅导机构口碑之选:2025年备受好评的补习机构
  • 2025口碑好的配电房动环网关机公司推荐排行榜哪家强——南京品尼科自动化有限公司
  • 2025年11月国内候车亭/公交站牌厂家权威推荐TOP10
  • 缓存穿透、缓存击穿和缓存雪崩,傻傻分不清楚?
  • 【完整源码+数据集+部署教程】【零售和消费品&存货】超市购物车商品检测系统源码&素材集全套:改进yolo11-DySnakeConv
  • 2025 最新工业开关厂家推荐排行榜:电感式 / 电容式 / 光电开关等优质国产企业权威甄选环形接近开关/磁感应式接近开关/限位开关/红外开关/接近开关/磁性开关/光电开关公司推荐
  • TradingAgents-CN:面向中文用户的多智能体与大模型股票分析学习平台。
  • AI无人机助力生态智慧农田倒伏检测与防控,基于嵌入式端超轻量级模型LeYOLO全系列【n/s/m/l】参数模型创建构建无人机航拍智慧生态农田场景下稻田作物倒伏智能化检测预警系统
  • iOS代码架构
  • 在Ubuntu下,通过Docker安装 Pgsql 18
  • 2025年酸化水生成器优质厂家权威推荐榜单:酸水设备/酸化水机器/酸化水设备企业精选
  • 2025年度合肥电销外呼行业商家推荐榜单
  • P19_神经网络-非线性激活
  • 2025年系统门窗隔热条/国标隔热条/隔热条厂家实力前十排行榜
  • 基于全变差的压缩感知视频图像重构算法
  • 数据说话,节能落地:MyEMS 开源系统,让能源消耗可视化、优化可执行
  • 解码标杆营销逻辑,纷享管理服务实战课圆满落幕
  • 2025年国内烘干设备实力厂家口碑推荐排行榜:四川蜀冷冷暖设备领跑
  • 2025企业级ITSM产品推荐:年度IT服务管理升级指南
  • 2025年11月网架/钢结构/光伏支架钢管厂家TOP10:江苏华力钢管登顶
  • 2025年评价高的高承重静音阻尼轨道厂家推荐及选购指南
  • 2025年国内烘干设备厂家排行榜:四川蜀冷冷暖设备领跑行业
  • 2025 年 11 月宣传片拍摄团队最新推荐榜:北京通州宣传片拍摄、宣传片剪辑、宣传片制作、产品宣传片、企业宣传片拍摄团队推荐
  • MyEMS:开源基因 能源智慧,为各类场景定制高效节能管理方案
  • 性能压测 并发用户数 与 吞吐量、错误率之间的关系 - BKY007
  • 2025年11月烘干房工厂推荐榜单
  • 2025年房屋安全检测公司推荐排名:内蒙古鑫质检测有限公司领跑行业
  • 第三代半导体半桥上管电压电流测试方案
  • 2025年口碑好的铜套加工厂家最新推荐排行榜
  • [Vue]性能优化:动态首行与动态列的匹配,表格数据格式处理性能优化