k8s之NDS解析到Ingress服务暴露

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 中,可直接通过以下命令访问目标服务:

bash 复制代码
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,会看到类似以下的配置:

bash 复制代码
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 服务:

bash 复制代码
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 配置的定制:dnsPolicydnsConfig

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(解析选项)。

示例

yaml 复制代码
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 如下:

bash 复制代码
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:

bash 复制代码
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml

查看其暴露的入口(通常为 NodePort 类型):

bash 复制代码
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:

yaml 复制代码
# 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 暴露的端口

应用配置:

bash 复制代码
kubectl apply -f ingress-example.yaml

步骤 3:外部访问验证

  1. 在 DNS 服务器中将 api.example.com 解析到 Ingress Controller 所在节点的 IP(如 192.168.1.100);
  2. 外部客户端访问 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)中添加规则:

nginx 复制代码
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 配置(searchnameserveroptions)简化了域名使用;
  • 外部通过 Ingress Controller 或独立 Nginx 建立"外部域名 → 内部 Service 域名"的映射,实现跨集群访问。

理解这一体系,不仅能解决日常的通信故障(如域名解析失败),还能根据场景选择合适的服务暴露策略,构建稳定、高效的 Kubernetes 网络架构。

相关推荐
jack-hui61 小时前
docker配置gpu运行环境:linux离线安装nvidia-container,避免网络问题
linux·docker·容器
陈陈CHENCHEN2 小时前
【Kubernetes】集群环境下的应用部署案例
kubernetes
东风微鸣7 小时前
职场生存指南:如何优雅应对"双面人"同事
docker·云原生·kubernetes·可观察性
Java侠7 小时前
graylog6.3 docker-compose部署全流程
运维·docker·容器·graylog·docker compose
云和数据.ChenGuang7 小时前
云计算k8s集群部署配置问题总结
云原生·容器·kubernetes·云计算
斯普信专业组8 小时前
k8s云原生rook-ceph pvc快照与恢复(下)
ceph·云原生·kubernetes
爱吃芝麻汤圆9 小时前
k8s之DevicePlugin
云原生·容器·kubernetes
kfepiza10 小时前
Dockerfile模板 笔记250801
docker·容器
赵文宇(温玉)11 小时前
1.6万 Star 的流行容器云平台停止开源
云原生·容器·开源·容器云·kubespere