DAY 04 —— DNS 与服务发现
================================================================
DAY 04 —— DNS 与服务发现
================================================================
【学习目标】
1. 说清 CoreDNS 在集群里的位置和作用
2. 读懂 Pod 里的 /etc/resolv.conf 三个关键字段
3. 会拼各种域名格式,能自己排查解析失败
4. 理解 ndots:5 带来的解析放大问题
5. 会改 CoreDNS 配置(自定义 hosts、转发、缓存)
----------------------------------------------------------------
一、为什么需要集群 DNS
----------------------------------------------------------------
Service 有 ClusterIP,但 IP 也不适合写死在配置里(重建集群就变)。
所以要有稳定的名字:web.default.svc.cluster.local
Pod 创建时,kubelet 会把 nameserver 指向 CoreDNS 的 ClusterIP,
于是容器内直接 curl http://web 就能通。
全链路:
Pod 内 getaddrinfo → /etc/resolv.conf 里的 nameserver(CoreDNS ClusterIP)
→ CoreDNS 查 Service 记录 → 返回 ClusterIP → 容器连 ClusterIP
→ kube-proxy 规则 DNAT 到某个 Pod IP
----------------------------------------------------------------
二、CoreDNS 是什么、跑在哪
----------------------------------------------------------------
- 以 Deployment 形式跑在 kube-system,通常 2 副本
- 前面挂一个名为 kube-dns 的 Service(ClusterIP,历史名字沿用)
- 配置来自 ConfigMap coredns(Corefile)
- 插件化:kubernetes、forward、cache、hosts、rewrite、loop…
查看:
kubectl -n kube-system get deploy,pod,svc | grep -E 'coredns|kube-dns'
kubectl -n kube-system get cm coredns -o yaml
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
----------------------------------------------------------------
三、Pod 里的 resolv.conf
----------------------------------------------------------------
kubectl exec -it <pod> -- cat /etc/resolv.conf
典型内容:
nameserver 10.96.0.10 # CoreDNS 的 ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
三个字段的含义:
1) nameserver:DNS 服务器地址,就是 kube-dns Service 的 ClusterIP
2) search:域名后缀列表,短名字会依次拼接这些后缀去试
3) ndots:5:如果查询的名字里"."的数量 >= 5,先当绝对域名查;
否则先拼 search 后缀逐个试,最后才查原名
实际效果:容器内 curl web
先查 web.default.svc.cluster.local → 命中,返回 ClusterIP
(如果 Pod 在别的命名空间则查不到,再往下试 web.svc.cluster.local 等)
【重要】这就是为什么"跨命名空间必须写全名":
web.default.svc.cluster.local 或至少 web.default
----------------------------------------------------------------
四、域名格式速查
----------------------------------------------------------------
<service>.<namespace>.svc.cluster.local 正常 Service(A 记录 → ClusterIP)
<service>.<namespace>.svc 同上,短一点
<service> 仅同命名空间可用
<pod-ip-dashed>.<namespace>.pod.cluster.local Pod 记录(如 10-244-1-5.default.pod...)
<hostname>.<service>.<namespace>.svc.cluster.local Headless + StatefulSet 的稳定名
StatefulSet 的 Pod 名就是 hostname(redis-0/redis-1),
所以 redis-0.redis.default.svc.cluster.local 永远指向同一个 Pod。
SRV 记录(拿端口号用):
_<port-name>._<protocol>.<service>.<ns>.svc.cluster.local
例:_http._tcp.web.default.svc.cluster.local
----------------------------------------------------------------
五、ndots:5 的解析放大问题
----------------------------------------------------------------
场景:访问外部域名 api.example.com(2 个点 < 5)
容器会依次查:
api.example.com.default.svc.cluster.local ✗
api.example.com.svc.cluster.local ✗
api.example.com.cluster.local ✗
api.example.com. ✓
一次业务请求产生 4 次 DNS 查询。QPS 高时 CoreDNS 压力巨大,
表现为"偶发 DNS 超时 5s"。
解决:
方案 A(推荐):应用里写带结尾点的绝对域名 api.example.com.
方案 B:调低 ndots
spec:
dnsConfig:
options:
- name: ndots
value: "2"
方案 C:CoreDNS 加 autopath 插件(已不推荐,有坑)
方案 D:NodeLocal DNSCache(每节点一个缓存,官方推荐的大规模方案)
【核心结论】应用配置里访问外部域名一律加结尾点,成本最低。
----------------------------------------------------------------
六、自定义 DNS 配置
----------------------------------------------------------------
6.1 Pod 级别改 DNS
spec:
dnsPolicy: None
dnsConfig:
nameservers: ["10.96.0.10", "223.5.5.5"]
searches: ["default.svc.cluster.local", "svc.cluster.local"]
options:
- name: ndots
value: "2"
dnsPolicy 四种:
- ClusterFirst(默认):先集群 DNS,外部域名转发上游
- Default:继承节点 /etc/resolv.conf
- ClusterFirstWithHostNet:hostNetwork=true 的 Pod 要用这个
- None:完全自定义,必须配 dnsConfig
6.2 CoreDNS 加自定义 hosts(替代改镜像 /etc/hosts)
kubectl -n kube-system edit cm coredns
在 Corefile 里加一段:
hosts {
10.0.0.100 db.internal
10.0.0.101 cache.internal
fallthrough
}
然后滚动重启:
kubectl -n kube-system rollout restart deploy coredns
kubectl -n kube-system rollout status deploy coredns
6.3 转发特定域名到内部 DNS
example.corp:53 {
forward . 10.10.0.2
cache 30
}
6.4 上游 DNS 设置
Corefile 里的 forward . /etc/resolv.conf 表示用节点 DNS。
如果节点 DNS 不稳定(常见于国内环境),改成显式地址:
forward . 223.5.5.5 119.29.29.29 {
max_concurrent 1000
}
----------------------------------------------------------------
七、验证与排障
----------------------------------------------------------------
【验证工具 Pod】
kubectl run dnsutils --rm -it --image=registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 \
--restart=Never -- bash
# 容器内:
nslookup kubernetes.default
nslookup web.default.svc.cluster.local
dig +short web.default.svc.cluster.local
dig @10.96.0.10 web.default.svc.cluster.local
busybox 的 nslookup 功能弱,正式排查用 dnsutils 或 netshoot:
kubectl run net --rm -it --image=nicolaka/netshoot --restart=Never -- bash
【逐层排查】
1) CoreDNS 活着吗
kubectl -n kube-system get pod -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100
# 常见报错:plugin/loop 检测到循环、上游超时、i/o timeout
2) kube-dns Service 有端点吗
kubectl -n kube-system get svc kube-dns
kubectl -n kube-system get endpointslice -l kubernetes.io/service-name=kube-dns
3) Pod 的 resolv.conf 对吗
kubectl exec -it <pod> -- cat /etc/resolv.conf
# nameserver 不是 10.96.0.10 说明 kubelet 配置有问题(clusterDNS)
4) 能直连 CoreDNS 吗
kubectl exec -it <pod> -- sh -c 'nc -zvu 10.96.0.10 53; nc -zv 10.96.0.10 53'
# 不通 → NetworkPolicy 拦了 UDP/TCP 53
5) 解析具体域名
kubectl exec -it <pod> -- nslookup web.default.svc.cluster.local 10.96.0.10
【典型现象对照】
- "server misbehaving":CoreDNS 后端上游不可达
- "i/o timeout":UDP 53 被拦 / CoreDNS 挂了 / conntrack 表满
- "no such host":名字拼错 / 跨命名空间没写全 / Service 不存在
- 间歇性 5s 超时:ndots 放大 + CoreDNS 压力 / conntrack 竞争
- 只有部分节点解析失败:那台的 kube-proxy 或 CNI 异常
【conntrack 表满】
现象:随机 DNS 超时,node 上 dmesg 有 "nf_conntrack: table full"
处理:
sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
持久化写 /etc/sysctl.d/99-k8s.conf
----------------------------------------------------------------
八、扩容与高可用
----------------------------------------------------------------
# CoreDNS 副本数(节点多时按 1:8 左右配,至少 2)
kubectl -n kube-system scale deploy coredns --replicas=3
# 反亲和,避免全挤一台
kubectl -n kube-system edit deploy coredns
# affinity:
# podAntiAffinity:
# preferredDuringSchedulingIgnoredDuringExecution:
# - weight: 100
# podAffinityTerm:
# topologyKey: kubernetes.io/hostname
# labelSelector:
# matchLabels: {k8s-app: kube-dns}
# 资源限制别设太小,DNS 是 CPU 敏感型
resources:
requests: {cpu: 100m, memory: 70Mi}
limits: {memory: 170Mi}
大规模集群(>1000 节点)建议上 NodeLocal DNSCache:
每个节点跑一个 DaemonSet 缓存,Pod 的 nameserver 指向 169.254.20.10,
减少跨节点 DNS 流量并规避 conntrack 问题。
----------------------------------------------------------------
九、Day 04 自检清单
----------------------------------------------------------------
[ ] 能画出 Pod → CoreDNS → kube-proxy 的解析与访问链路
[ ] 能解释 search 和 ndots:5 的作用
[ ] 能说出为什么跨命名空间要写全名
[ ] 会用 nslookup/dig 在临时 Pod 里验证解析
[ ] 知道 ndots 放大的成因和四种解法
[ ] 亲手在 CoreDNS ConfigMap 里加一条 hosts 记录并验证
[ ] 遇到 "no such host" 能按五步法定位
常见坑:
- 改了 coredns ConfigMap 没重启 Pod(不会自动生效)
- Corefile 缩进错,CoreDNS 起不来 → 全集群解析挂掉,务必先备份
- hostNetwork 的 Pod 用默认 dnsPolicy 会解析不到集群域名,要改 ClusterFirstWithHostNet
- CoreDNS 只给 100m CPU 又被限流,高 QPS 下大量超时
- 对外域名不加结尾点,QPS 高时把自己 DNS 打挂
- 点赞
- 收藏
- 关注作者
评论(0)