Kubernetes 服务发现与外部访问全解析:从 DNS 解析到 Ingress 暴露
在 Kubernetes 集群中,服务间的通信与外部访问是核心功能,而这一切都依赖于 DNS 解析机制和合理的服务暴露策略。本文将系统讲解 Kubernetes 内部服务域名的构成、Pod 的 DNS 配置原理,以及如何通过 Ingress 或 Nginx 将内部服务安全、高效地暴露给外部访问。
一、Kubernetes 内部服务域名:服务发现的基石
Kubernetes 为每个 Service 自动生成固定的内部域名,实现了 Pod 动态 IP 与固定访问入口的解耦。理解域名的构成规则是掌握服务发现的关键。
1. 服务域名的组成与含义
以 openapi.test.svc.cluster.local
为例,这个域名由四部分组成,遵循严格的命名规则:
openapi
:Service 资源的名称(对应metadata.name
字段);test
:Service 所在的命名空间(metadata.namespace
);svc
:固定标识,表明这是一个 Kubernetes Service 资源;cluster.local
:集群域名后缀(默认值,可在集群初始化时通过--cluster-domain
自定义)。
完整含义:该域名指向 test
命名空间下的 openapi
服务,是集群内部 Pod 间通信的固定地址。
2. 服务域名的核心作用
Service 域名的最大价值在于屏蔽 Pod IP 的动态变化。由于 Pod 重启、扩缩容等操作会导致 IP 改变,直接使用 Pod IP 通信极不稳定。而 Service 域名一旦创建便固定不变,无论后端 Pod 如何变化,都能通过域名稳定访问服务。
例如,在集群内任意 Pod 中,可直接通过以下命令访问目标服务:
curl http://openapi.test.svc.cluster.local:9090
二、Pod 的 DNS 配置:如何解析内部域名?
Pod 之所以能通过 Service 域名通信,依赖于其内部的 DNS 配置。Kubernetes 通过 resolv.conf
文件、dnsPolicy
策略和 dnsConfig
自定义配置,构建了一套灵活的域名解析体系。
1. 解析 Pod 中的 /etc/resolv.conf
在任意运行中的 Pod 内执行 cat /etc/resolv.conf
,会看到类似以下的配置:
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
这三行配置分别控制了域名解析的核心逻辑:
(1)search
:自动补全域名后缀
search
字段定义了 DNS 搜索路径,作用是为短域名自动补充后缀,简化集群内访问。例如,当 Pod 中查询 nginx
时,系统会按以下顺序尝试解析:
nginx.default.svc.cluster.local
(当前命名空间 + 服务后缀)nginx.svc.cluster.local
(集群通用服务后缀)nginx.cluster.local
(集群域名后缀)
这解释了为什么同命名空间的 Service 可直接通过名称访问(如 curl nginx
)—— 搜索路径会自动补全完整域名。
搜索路径的生成规则:
- 以 Pod 所在命名空间为起点(如
default
); - 依次拼接固定前缀
svc
和集群域名后缀(如cluster.local
); - 最终形成
[namespace].svc.[cluster-domain]
、svc.[cluster-domain]
、[cluster-domain]
的层级结构。
(2)nameserver
:指定 DNS 服务器
nameserver 10.96.0.10
明确了 Pod 中 DNS 请求的目标服务器,这个 IP 通常是 CoreDNS 服务的 ClusterIP(Kubernetes 内置的 DNS 服务)。
验证这一点可查看 kube-system
命名空间下的 kube-dns
服务:
kubectl -n kube-system get svc 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 5d
CoreDNS 通过监听 Kubernetes API 中的 Service、Endpoint 等资源变化,实时更新本地缓存,确保域名解析的准确性。
(3)options ndots:5
:控制解析策略
ndots:5
是 DNS 解析的关键参数,规则是:当查询的域名中点的数量少于 5 时,优先使用 search
路径补全后缀;否则直接解析原域名。
例如:
- 查询
nginx
(0 个点):触发search
补全; - 查询
www.kubernetes.io
(3 个点):仍触发search
补全(3 < 5); - 查询
a.b.c.d.e.f
(6 个点):直接解析原域名,不使用search
。
这一机制既简化了集群内短域名的使用,又避免了对外部域名解析的干扰。
2. DNS 配置的定制:dnsPolicy
与 dnsConfig
Pod 的 DNS 配置并非固定不变,可通过 dnsPolicy
策略和 dnsConfig
字段灵活调整。
(1)dnsPolicy
:定义 DNS 策略
dnsPolicy
是 Pod .spec 中的字段,用于指定 DNS 配置的生成规则,支持 4 种策略:
策略名称 | 说明 |
---|---|
Default |
继承 Pod 所在节点的 /etc/resolv.conf (使用节点的 DNS 服务器)。 |
ClusterFirst |
优先使用集群 DNS(CoreDNS),非集群域名转发到节点的上游 DNS。 |
ClusterFirstWithHostNet |
用于 hostNetwork: true 的 Pod,强制使用集群 DNS(避免继承节点配置)。 |
None |
忽略集群默认配置,完全使用 dnsConfig 自定义。 |
注意事项:
- 默认策略为
ClusterFirst
,适用于绝大多数场景; - 使用
hostNetwork: true
的 Pod 需显式设置ClusterFirstWithHostNet
,否则可能无法解析内部域名; - 自定义 DNS 需将
dnsPolicy
设为None
,并配合dnsConfig
配置。
(2)dnsConfig
:自定义 DNS 配置
dnsConfig
用于补充或覆盖默认 DNS 配置,支持 nameservers
(DNS 服务器列表)、searches
(搜索域)、options
(解析选项)。
示例:
apiVersion: v1
kind: Pod
metadata:
name: dns-example
namespace: default
spec:
containers:
- name: test
image: nginx
dnsPolicy: "None" # 必须与 dnsConfig 配合
dnsConfig:
nameservers:
- 114.114.114.114 # 外部 DNS 服务器
searches:
- my-custom.search # 自定义搜索域
options:
- name: ndots
value: "3" # 覆盖默认的 ndots:5
生成的 resolv.conf
如下:
search my-custom.search
nameserver 114.114.114.114
options ndots:3
3. /etc/resolv.conf
的生成流程
默认情况下(dnsPolicy: ClusterFirst
),resolv.conf
由 kubelet 动态生成,规则如下:
nameserver
:来自 kubelet 配置的clusterDNS
字段(通常为 CoreDNS 的 ClusterIP);search
:由 Pod 所在命名空间、svc
前缀和集群域名后缀拼接而成;options
:固定为ndots:5
(Kubernetes 优化集群内解析的默认设置)。
三、将内部服务暴露给外部:Ingress 与 Nginx 方案
Service 域名仅能在集群内部解析,外部客户端(如用户浏览器)需通过额外配置才能访问。目前主流方案有两种:Ingress Controller(推荐)和独立 Nginx 反向代理。
1. 通过 Ingress Controller 暴露服务(生产环境推荐)
Ingress 是 Kubernetes 官方定义的外部访问规则集合,而 Ingress Controller 是实现这些规则的组件(通常基于 Nginx、Traefik 等),负责接收外部请求并转发到内部 Service。
(1)核心组件与流程
- Ingress 资源:定义“外部域名 → 内部 Service”的映射规则(如
api.example.com
转发到chogori-openapi.chogori.svc.cluster.local
); - Ingress Controller:运行在集群中的 Pod,监听 Ingress 资源变化,自动生成代理配置,并暴露外部访问入口(如节点 IP + 端口)。
完整流程:
外部客户端 → 访问外部域名(如 api.example.com
)→ DNS 解析到 Ingress Controller 入口 IP → Ingress Controller 转发到内部 Service 域名 → Service 转发到后端 Pod。
(2)部署与配置示例(Nginx Ingress Controller)
步骤 1:部署 Ingress Controller
通过官方 YAML 部署 Nginx Ingress Controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
查看其暴露的入口(通常为 NodePort
类型):
kubectl get svc -n ingress-nginx
# 输出示例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# ingress-nginx-controller NodePort 10.109.xx.xx <none> 80:32080/TCP,443:32443/TCP 5m
外部可通过 节点 IP:32080(HTTP)访问。
步骤 2:创建 Ingress 规则
定义 Ingress 资源,将外部域名 api.example.com
映射到内部 Service:
# ingress-example.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: chogori-openapi-ingress
namespace: chogori
spec:
ingressClassName: nginx # 指定使用 Nginx Ingress Controller
rules:
- host: api.example.com # 外部域名(需解析到 Ingress 入口 IP)
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: chogori-openapi # 内部 Service 名称
port:
number: 80 # Service 暴露的端口
应用配置:
kubectl apply -f ingress-example.yaml
步骤 3:外部访问验证
- 在 DNS 服务器中将
api.example.com
解析到 Ingress Controller 所在节点的 IP(如192.168.1.100
); - 外部客户端访问
http://api.example.com:32080
,请求会转发到内部服务。
(3)Ingress 的优势
- 声明式配置:通过 YAML 定义规则,无需手动修改代理配置;
- 自动更新:监听 Service/Ingress 变化,自动更新转发规则;
- 功能丰富:支持 HTTPS、路径路由(如
/v1
到服务 A,/v2
到服务 B)、流量控制等。
2. 通过独立 Nginx 暴露服务(测试或简单场景)
若不使用 Ingress,可在集群外部署独立 Nginx 服务器,通过反向代理将外部请求转发到内部 Service 域名。
(1)核心原理
Nginx 配置中,将外部域名(如 api.example.com
)的请求转发到集群内 Service 域名(如 http://chogori-openapi.chogori.svc.cluster.local:80
)。
前提:Nginx 服务器需能访问集群网络(解析 Service 域名并连接 ClusterIP)。
(2)配置示例
在 Nginx 配置文件(nginx.conf
)中添加规则:
server {
listen 80;
server_name api.example.com; # 外部域名
location / {
# 转发到内部 Service 域名
proxy_pass http://chogori-openapi.chogori.svc.cluster.local:80;
# 传递客户端信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
重启 Nginx 后,外部访问 http://api.example.com
即可转发到内部服务。
(3)注意事项
- 域名解析:需在 Nginx 服务器的
/etc/resolv.conf
中添加 CoreDNS 的 IP(10.96.0.10
),确保能解析 Service 域名; - 网络可达:Nginx 需与集群网络打通(如同一 VPC),否则无法连接 Service 的 ClusterIP;
- 手动维护:Service 域名或端口变化时,需手动更新 Nginx 配置。
3. 两种方案的对比
方式 | 优势 | 劣势 | 适用场景 |
---|---|---|---|
Ingress Controller | 声明式配置、自动更新、支持复杂规则 | 需部署额外组件,学习成本稍高 | 生产环境、多服务暴露、动态更新需求 |
独立 Nginx | 配置简单、无额外依赖 | 需手动维护、扩展性差 | 测试环境、单服务临时暴露 |
四、总结
Kubernetes 的服务发现与外部访问体系围绕“固定域名”展开:
- 内部通过 CoreDNS 实现 Service 域名解析,Pod 的
resolv.conf
配置(search
、nameserver
、options
)简化了域名使用; - 外部通过 Ingress Controller 或独立 Nginx 建立“外部域名 → 内部 Service 域名”的映射,实现跨集群访问。
理解这一体系,不仅能解决日常的通信故障(如域名解析失败),还能根据场景选择合适的服务暴露策略,构建稳定、高效的 Kubernetes 网络架构。