DAY 04 —— DNS 与服务发现

举报
yd_268505900 发表于 2026/11/10 10:32:16 2026/11/10
【摘要】 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 打挂

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。