跳到正文
复制成功
请遵守本站许可
报告
章节_文章 // 现场报告

文章编号: RL-SERVICE与

2026.09.16

Service 与 DNS 服务发现

Chavy
Chavy
#Kubernetes#Service#DNS#CoreDNS
档案

摘要:理解 Service、EndpointSlice 与 CoreDNS 如何提供稳定访问和名称解析,掌握端口映射、DNS 搜索域、Headless Service 及服务发现排查。

1. 为什么需要 Service?#

假设你部署了三个后端 Pod:

flowchart TB
    N0["前端 Pod<br/>需要调用后端 API"]
    N1["backend Service<br/>稳定的虚拟 IP 和服务名称"]
    N2["Pod A<br/>10.244.1.10"]
    N3["Pod B<br/>10.244.1.11"]
    N4["Pod C<br/>10.244.2.15"]
    N0 --> N1
    N1 --> N2
    N1 --> N3
    N1 --> N4

如果前端直接访问 Pod A 的 IP,一旦 Pod A 被删除并创建新实例,原来的 IP 就可能失效。

Service 解决了这个问题:

  • 提供相对稳定的服务访问入口。
  • 根据标签选择后端 Pod。
  • 将请求转发给符合条件的后端端点。
  • 配合 DNS,让客户端通过服务名称访问。

前端可以直接请求:

PRTCL // BASH
Terminal window
curl http://backend:8080

而不需要知道后端 Pod 的具体 IP。

2. Service 的工作原理#

Service 通常通过标签选择器找到后端 Pod,并由控制平面维护相应的 EndpointSlice。

flowchart TB
    N0["客户端 Pod<br/>请求 backend:8080"]
    N1["CoreDNS<br/>将 backend 解析为 Service 的 ClusterIP"]
    N2["Service ClusterIP:8080<br/>通过数据面规则转发流量"]
    N3["EndpointSlice"]
    N4["Pod A"]
    N5["Pod B"]
    N6["Pod C"]
    N0 -->|"DNS 查询"| N1
    N1 -->|"返回 ClusterIP"| N0
    N0 -->|"访问 Service"| N2
    N3 -.->|"端点信息"| N2
    N2 -->|"转发流量"| N4
    N2 -->|"转发流量"| N5
    N2 -->|"转发流量"| N6

这里有一个重要区别:

  • CoreDNS:负责名称解析。
  • Service:提供稳定的服务抽象。
  • EndpointSlice:记录服务关联的网络端点。
  • kube-proxy 或其他兼容的数据面:负责实际的流量转发。

DNS 解析成功,并不代表后端一定可用;Service 也不是一个必须运行独立进程的代理服务器。

3. Service 配置与端口映射#

PRTCL // YAML
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
selector:
app: backend
ports:
- name: http
port: 8080
targetPort: 80
protocol: TCP

此时,Service 的 port 是 8080,而后端容器监听的 targetPort 是 80。

所以请求路径是:

flowchart TB
    N0["客户端"]
    N1["Service :8080"]
    N2["Nginx Pod :80"]
    N0 -->|"backend:8080"| N1
    N1 -->|"转发到后端 :80"| N2

注意: ClusterIP 默认用于集群内部访问,外部电脑通常不能直接访问这个地址。

4. Service 的四种常见类型#

类型用途典型访问方式
ClusterIP集群内部服务通信Service 虚拟 IP 或 DNS
NodePort通过节点端口暴露服务节点 IP:NodePort
LoadBalancer通过负载均衡器对外暴露外部负载均衡器地址
ExternalName将 Service DNS 名称映射到外部 DNS 名称CNAME 解析

1. ClusterIP#

最常见的类型,适合前端调用后端、应用访问数据库等集群内部通信。

PRTCL // YAML
spec:
type: ClusterIP

不指定 type 时,默认就是 ClusterIP。

2. NodePort#

NodePort 会在符合条件的节点上开放一个端口,默认端口范围通常为 30000–32767,但可以通过集群配置调整。

PRTCL // YAML
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080

访问方式:

PRTCL // TEXT
http:// 节点 IP:30080

实际可达性还取决于节点防火墙、网络路由及集群数据面配置。

3. LoadBalancer#

在支持 LoadBalancer 的云环境或已安装相应负载均衡实现的自建集群中,可以使用:

PRTCL // YAML
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80

Kubernetes 会通过相应的实现申请或配置负载均衡入口。在裸机集群中,仅创建 LoadBalancer Service 不一定就能自动获得外部 IP,还需要配套的负载均衡实现。

4. ExternalName#

例如,你希望在集群中通过 external-db 这个服务名称访问外部数据库域名:

PRTCL // YAML
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.com

这种类型主要提供 DNS 名称映射,不会像普通 ClusterIP Service 一样创建代理转发规则。

5. Service 如何发现后端 Pod?#

主要依靠 selector。

例如:

PRTCL // YAML
selector:
app: backend

这表示 Service 会匹配带有 app=backend 标签的 Pod。

假设有以下三个 Pod:

Pod标签是否匹配
Pod Aapp=backend是
Pod Bapp=backend是
Pod Capp=frontend否

那么 Service 只会把符合条件且可用于服务流量的端点纳入转发范围。

你可以查看:

PRTCL // BASH
Terminal window
kubectl get pods --show-labels
kubectl get endpointslices
kubectl describe svc backend

如果 Service 存在,但没有可用后端,优先检查:

  1. Service 的 selector 是否正确。
  2. Pod 是否已经创建。
  3. Pod 标签是否匹配。
  4. readinessProbe 是否通过。
  5. Service 的 targetPort 是否正确。

EndpointSlice 是现代 Kubernetes 管理服务端点的主要 API 资源;旧的 Endpoints 资源仍可能出现在排障资料中,但不应把它当作所有场景下的首选。

6. Kubernetes Service 的 DNS 命名规则#

Kubernetes 中最常见的 Service 完整域名格式是:

PRTCL // TEXT
<service-name>.<namespace>.svc.<cluster-domain>

假设:

  • Service 名称:backend
  • Namespace:default
  • 集群域名:cluster.local

那么完整域名就是:

PRTCL // TEXT
backend.default.svc.cluster.local

常见的访问方式有以下几种:

访问名称适用场景
backend通常用于同一个 Namespace
backend.default明确指定 Namespace
backend.default.svc指定 Service 域名层级
backend.default.svc.cluster.local使用完整域名

这里的 cluster.local 是常见默认值,不是固定要求,实际集群可能使用其他域名。

1. 为什么不同 Namespace 可以有同名 Service?#

例如:

flowchart TB
    N0["Namespace: dev"]
    N1["backend"]
    N2["Namespace: prod"]
    N3["backend"]
    N0 --> N1
    N2 --> N3

两个 Service 可以同名,因为 Namespace 提供了命名空间隔离。

在 dev Namespace 中,直接访问 backend 通常会解析到 dev 中的 Service;如果要访问生产环境的服务,可以写:

PRTCL // BASH
Terminal window
curl http://backend.prod.svc.cluster.local:8080

这也是 Kubernetes 服务发现的重要基础。

7. CoreDNS 是什么?#

CoreDNS 是 Kubernetes 中常用的集群 DNS 服务。它通常以 Deployment 的形式运行在集群中,并由对应的 Service 提供访问入口。

它主要负责:

  1. 解析 Kubernetes 集群内部的 Service 名称。
  2. 根据集群资源信息生成 DNS 响应。
  3. 按配置将外部域名查询转发给上游 DNS 服务器。
  4. 根据配置提供缓存等 DNS 功能。

查看 CoreDNS:

PRTCL // BASH
Terminal window
kubectl get pods -n kube-system
kubectl get svc -n kube-system
kubectl get deployment -n kube-system

通常可以看到类似以下资源:

flowchart TB
    N0["kube-system"]
    N1["coredns-xxxxx"]
    N2["coredns-yyyyy"]
    N3["kube-dns"]
    N0 --> N1
    N0 --> N2
    N0 --> N3

这里有一个容易混淆的名称:

即使实际 DNS 程序是 CoreDNS,Kubernetes 中对应的 Service 仍经常叫 kube-dns。

这是历史命名沿用,并不代表集群还在运行旧版 kube-dns 程序。

1. CoreDNS 的工作流程#

flowchart TB
    N0["Pod 发起 DNS 查询<br/>例如查询 backend.default"]
    N1["Pod 的 DNS 配置<br/>nameserver 指向集群 DNS 服务地址"]
    N2["CoreDNS<br/>匹配集群域名规则,查询 Kubernetes 服务信息"]
    N3["返回集群资源对应的记录"]
    N4["按配置转发或处理"]
    N0 --> N1
    N1 --> N2
    N2 -->|"集群内部域名"| N3
    N2 -->|"外部域名"| N4

CoreDNS 的具体处理流程由 Corefile 配置决定。例如,kubernetes 插件负责 Kubernetes 域名,forward 插件可以把外部查询转发给上游 DNS。

8. /etc/resolv.conf:Pod 如何知道 DNS 在哪里?#

进入一个 Pod,执行:

PRTCL // BASH
Terminal window
cat /etc/resolv.conf

典型内容可能类似:

PRTCL // TEXT
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

这些字段非常重要。

字段含义
search配置 DNS 查询时尝试使用的搜索域
nameserver指定 DNS 服务器地址
ndots控制何时优先尝试绝对域名查询

实际输出取决于 Pod 的 dnsPolicy、集群配置以及 DNS 域名设置。

1. Search:为什么只写 backend 也能访问?#

假设 /etc/resolv.conf 中有:

PRTCL // TEXT
search default.svc.cluster.local svc.cluster.local cluster.local

当程序查询 backend 时,系统的名称解析机制可能依次尝试类似以下名称:

PRTCL // TEXT
backend.default.svc.cluster.local
backend.svc.cluster.local
backend.cluster.local
backend

具体顺序和尝试方式会受到解析器实现、ndots 和域名写法影响。

因此,你在同一个 Namespace 中通常可以直接执行:

PRTCL // BASH
Terminal window
curl http://backend:8080

而不必手动写完整域名。

2. ndots:5 是什么意思?#

ndots:5 表示:域名中至少有 5 个点时,解析器才会把它视为优先尝试绝对查询的名称;点数不足时,通常先尝试搜索域扩展。

例如:

PRTCL // TEXT
backend

只有 0 个点,解析器通常会先尝试搜索域。

而:

PRTCL // TEXT
backend.default.svc.cluster.local

包含 4 个点,在常见的 ndots:5 配置下,仍可能先尝试附加搜索域,再尝试绝对名称。

这可能导致额外的 DNS 查询,特别是在应用频繁访问外部域名时。

不过,ndots 的行为属于操作系统解析器的机制,不是 CoreDNS 自己决定的所有查询顺序。

9. Headless Service:DNS 直接返回 Pod 地址#

普通 ClusterIP Service 通常通过 DNS 返回 Service 的虚拟 IP。

Headless Service 则不分配普通 ClusterIP,而是通过 DNS 暴露符合条件的后端地址。

创建方式:

PRTCL // YAML
apiVersion: v1
kind: Service
metadata:
name: backend-headless
spec:
clusterIP: None
selector:
app: backend
ports:
- port: 8080
targetPort: 80

普通 Service 和 Headless Service 的区别:

对比普通 ClusterIPHeadless Service
是否有 ClusterIP有没有普通 ClusterIP
DNS 常见结果Service 虚拟 IP符合条件的后端 Pod 地址
流量转发通过 Service 数据面客户端通常直接连接解析到的端点
常见用途普通微服务StatefulSet、需要发现各实例的应用

Headless Service 特别适合 StatefulSet,因为每个实例可以拥有可预测的网络身份。

但需要注意:DNS 返回 Pod 地址并不保证 Pod 一定健康,也不保证客户端能够直接访问这些地址。

10. Service 与 DNS 故障排查#

1. Service 请求失败#

建议按照从上到下的顺序:

PRTCL // BASH
Terminal window
# 1. 检查 Pod
kubectl get pods -o wide
# 2. 检查 Service
kubectl get svc backend
kubectl describe svc backend
# 3. 检查后端端点
kubectl get endpointslices \
-l kubernetes.io/service-name=backend
# 4. 检查 DNS
kubectl exec < 客户端 Pod> -- \
nslookup backend
# 5. 检查应用端口与日志
kubectl logs < 后端 Pod>
kubectl describe pod < 后端 Pod>

常见故障:

现象优先检查
DNS 解析失败CoreDNS、Pod DNS 配置、服务名称
Service 没有后端selector、Pod 标签、就绪状态
DNS 正常但连接超时网络策略、路由、数据面、防火墙
连接被拒绝应用是否监听、targetPort 是否正确
只有部分请求失败后端实例健康状况、端口和应用日志

2. DNS 专项排查#

这是 K8s 网络中的经典问题。

假设:

PRTCL // BASH
Terminal window
curl http://10.96.120.30:8080

可以访问,但:

PRTCL // BASH
Terminal window
curl http://backend:8080

失败。

这时应该先区分是 DNS 解析失败,还是解析成功后的网络连接失败。

1. 第一步:检查 DNS 配置#

PRTCL // BASH
Terminal window
kubectl exec <pod-name> -- cat /etc/resolv.conf

确认 nameserver 是否指向正确的集群 DNS 地址,以及 search 域是否符合预期。

2. 第二步:检查 DNS 查询#

如果容器中有 nslookup:

PRTCL // BASH
Terminal window
kubectl exec <pod-name> -- nslookup backend

或者查询完整域名:

PRTCL // BASH
Terminal window
kubectl exec <pod-name> -- nslookup \
backend.default.svc.cluster.local

3. 第三步:检查 Service 和端点#

PRTCL // BASH
Terminal window
kubectl get svc backend
kubectl get endpointslices \
-l kubernetes.io/service-name=backend

确认 Service 存在,并且后端端点符合预期。

4. 第四步:检查 CoreDNS#

PRTCL // BASH
Terminal window
kubectl get pods -n kube-system
kubectl logs -n kube-system \
-l k8s-app=kube-dns

如果日志选择器不匹配实际标签,可以先执行:

PRTCL // BASH
Terminal window
kubectl get pods -n kube-system --show-labels

再选择正确的标签查看日志。

5. 第五步:检查 DNS 网络连通性#

如果查询超时,需要继续检查:

  • Pod 是否能访问 DNS Service。
  • CoreDNS Pod 是否正常运行。
  • UDP/TCP 53 端口是否可达。
  • NetworkPolicy 是否阻断 DNS。
  • CNI、路由或节点防火墙是否影响 DNS 流量。

不要因为 DNS 解析失败就直接重启 CoreDNS。先通过查询结果和事件确定故障范围。

11. 知识检查清单#

本节最重要的知识点:

  1. CoreDNS 负责集群 DNS 服务。
  2. Service DNS 名称 让应用不必依赖变化的 Pod IP。
  3. /etc/resolv.conf 决定 DNS 服务器、搜索域和部分查询行为。
  4. Headless Service 可以让客户端发现具体的后端 Pod 地址。
  5. DNS 解析成功不代表应用一定可达,仍需检查 Service、端点和网络链路。
归档于 2026.09.16
// 档案结束
Classified
章节_06
协议编号: CC-BY-NC-SA-4.0

Service 与 DNS 服务发现

作者:Chavy发布日期:2026.09.16

基于 CC BY-NC-SA 4.0

© 2026 Chavy
Powered by Astro