首页 / Kubernetes (k8s) 入门教程 / 服务发现与 CoreDNS

Kubernetes (k8s) 入门教程

服务发现与 CoreDNS

本教程共 65 篇 · 第 27 篇 · 更新于 2026-08-14 · 约 13 分钟阅读

KubernetesCoreDNS服务发现DNS集群域名命名空间

本节目标:理解集群内为什么要用 DNS 做服务发现,CoreDNS 怎么为每个 Service 和 Pod 生成记录,以及跨命名空间访问时 DNS 名字怎么写。

前面两章讲了 Service 用虚拟 IP 兜住一组 Pod。但还有个问题:前端怎么知道这个 Service 的 IP 是多少?总不能写死在代码里吧。

Kubernetes 给的答案很干脆:用 DNS 名字,别用 IP

27-1 服务发现的两种老办法

在 Kubernetes 里,集群内的客户端发现 Service 主要有两条路:环境变量和 DNS。

环境变量是早期方案。当 Pod 被调度到节点上时,kubelet 会往 Pod 里塞一组环境变量,比如有个叫 redis-primary 的服务,Pod 里就能看到:

REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379

但环境变量有个硬伤:必须先创建 Service,客户端 Pod 才读得到。客户端后于 Service 启动才管用,顺序反了就什么都没有。

DNS 就没这问题。Service 一创建,DNS 记录就生成,什么时候查都行。所以现在几乎都走 DNS。

Tip

新应用一律用 DNS 做服务发现,别依赖环境变量。环境变量的顺序依赖坑过不少人。

27-2 CoreDNS 在背后干了啥

CoreDNS 是 Kubernetes 集群默认的 DNS 服务(插件形式安装)。它干的事很单纯:盯着 API 服务器里新增、变更的 Service 和 Pod,然后给每个对象生成对应的 DNS 记录。

只要集群开了 DNS(现在基本都开),所有 Pod 天生就能用名字解析 Service。你不用操心 CoreDNS 怎么配,它和 kubelet 配合,把 Pod 的 /etc/resolv.conf 写好。

一个典型 Pod 里的 DNS 配置长这样:

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

10.32.0.10 就是 CoreDNS 自己的集群 IP。search 那行决定了你只写短名字时,系统会帮你在哪些域里补全查找。

27-3 Service 的 DNS 名字怎么拼

普通(非无头)Service 会被分配一条 A 记录(或 AAAA 记录,对应 IPv6),名字格式是:

my-svc.my-namespace.svc.cluster-domain.example

它解析到的就是 Service 的集群 IP。

举个具体例子。你在 my-ns 命名空间里有个 my-service,那它的完整域名就是 my-service.my-ns.svc.cluster.local

27-4 在同命名空间 vs 跨命名空间

DNS 查询的结果,取决于发起查询的 Pod 在哪个命名空间。默认情况下,不写命名空间的话,查询被限制在 Pod 自己所在的命名空间。

假设 test 命名空间有个 Pod,想访问 prod 命名空间里的 data 服务:

  • 只查 data → 查的是 test 命名空间,找不到,返回空。
  • data.prod → 指定了命名空间,能找到。

所以跨命名空间访问,要把命名空间带上。同命名空间内可以偷懒只写服务名,因为 search 列表会帮你补成 data.test.svc.cluster.local

Note

默认集群域名是 cluster.local,所以标准后缀是 svc.cluster.local。有些发行版会改这个域,看到不一样的别慌。

27-5 无头服务的 DNS 不一样

前面提过无头服务(clusterIP: None)没有虚拟 IP。它的 DNS A 记录不解析到单个 IP,而是解析到所有后端 Pod 的 IP 集合

客户端拿到这一组 IP,自己挑一个连(或者按标准轮询)。这给有状态集这类需要直连特定 Pod 的场景开了口子。

27-6 Pod 自己也有 DNS 名字

不光 Service,Pod 也能有 DNS 名字。默认情况下,Pod 的 FQDN 形如:

<pod-ip-with-dashes>.<namespace>.pod.cluster.local

比如 IP 是 172.17.0.3、在 default 命名空间,名字就是 172-17-0-3.default.pod.cluster.local

你也可以给 Pod 指定 hostnamesubdomain 字段,让它拥有更好认的主机名。比如一个 Pod 的 hostnamebusybox-1subdomainbusybox-subdomain,再加一个同名的无头服务,它就有了一个体面的名字:

busybox-1.busybox-subdomain.my-namespace.svc.cluster.local

27-7 命名端口还有 SRV 记录

Service 里给端口起了名字(比如 http),CoreDNS 还会生成 SRV 记录。你可以用 DNS SRV 查询 _http._tcp.my-service.my-ns,一次性拿到端口号和 IP。

这对服务想”自报家门”说”我监听哪个端口”很有用,调用方不用硬编码端口号。

27-8 每个 Pod 的 DNS 策略

Pod 的 DNS 行为由 dnsPolicy 字段控制,支持四种:

  • Default:从所在节点继承 DNS 配置(注意,它不是默认值)。
  • ClusterFirst:集群域名之外的查询转发给上游 DNS。这是默认策略。
  • ClusterFirstWithHostNet:用 hostNetwork 跑的 Pod 必须设这个,否则会回退成 Default。
  • None:完全忽略集群预设,DNS 全靠你写的 dnsConfig 提供。
Warning

没显式写 dnsPolicy 时,走的是 ClusterFirst 而不是 Default。别望文生义,这俩名字容易误导。

27-9 自定义 DNS 配置

dnsPolicy: None 时,你必须在 dnsConfig 里把 DNS 服务器、搜索域、选项配齐。就算不是 None,也可以叠加自定义:

apiVersion: v1
kind: Pod
metadata:
  name: dns-example
spec:
  dnsPolicy: None
  dnsConfig:
    nameservers:
      - 192.0.2.1
    searches:
      - ns1.svc.cluster.local
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"
      - name: edns0
  containers:
    - name: test
      image: nginx

Kubernetes 本身对 DNS 配置的限制是:搜索域最多 32 个、总长度不超过 2048 字符。超出会出问题。

小结

服务发现的核心是:别记 IP,记名字。CoreDNS 在后台监听 Service 变化,自动维护 DNS 记录。同命名空间用短名字,跨命名空间带上命名空间前缀。

无头服务把 DNS 指向一组 Pod IP,给有状态场景留了门。Pod 自身也能有 DNS 名字,命名端口还有 SRV 记录可用。

下章进入七层路由:用 Ingress 把集群外的 HTTP/HTTPS 流量,按域名和路径精准分发到内部 Service。