服务发现是分布式系统中一个核心问题:在动态变化的网络环境中,如何让一个服务(消费者)找到另一个服务(提供者)的访问地址(IP 和端口)。下面分别介绍传统架构和 Kubernetes(k8s)是如何解决这个问题的。


一、传统架构下的服务发现

传统架构通常指物理机或虚拟机时代,应用部署在相对静态的基础设施上,服务的上下线频率较低。常见的服务发现方式有以下几种:

1. 静态配置
  • 方式:将服务提供者的地址(IP:Port)直接写在消费者的配置文件或代码中。
  • 特点:简单直接,但任何地址变更都需要手动修改配置、重启应用,灵活性差,难以应对动态扩缩容或故障转移。
2. 基于 DNS 的简单负载均衡
  • 方式:为服务配置一个域名,DNS 服务器中该域名对应多个 A 记录(即多个服务实例的 IP)。消费者通过域名访问,DNS 轮询返回不同 IP 实现负载均衡。
  • 特点:无需改动应用代码,但 DNS 缓存可能导致更新延迟(TTL 时间内无法感知 IP 变化),且无法自动剔除故障实例(除非结合健康检查动态更新 DNS,但这通常需要额外脚本或组件)。
3. 负载均衡器(反向代理)
  • 方式:部署集中式负载均衡器(如 Nginx、HAProxy),将所有请求先打到负载均衡器,再由它转发给后端服务。后端服务列表通过配置文件静态定义,或通过脚本/API 动态更新。
  • 特点:中心化流量管理,支持健康检查和负载均衡策略。但负载均衡器本身可能成为单点,且配置更新仍需人工介入或借助外部工具(如 Consul Template、Confd)自动同步。
4. 服务注册中心(如 ZooKeeper、Consul、Eureka)
  • 方式:引入一个独立的服务注册表(Registry)。服务提供者在启动时向注册中心注册自己的地址,并定期发送心跳;服务消费者从注册中心获取提供者列表,然后自行选择调用(客户端发现模式),或者通过注册中心动态更新负载均衡器的配置(服务端发现模式)。
  • 特点:实现了服务的动态注册与发现,能快速感知实例变化。但需要额外部署和维护注册中心集群,且客户端往往需要集成 SDK 或库来与注册中心交互,增加了复杂性和耦合度。

二、Kubernetes 中的服务发现

Kubernetes 作为容器编排平台,将服务发现作为其核心内置能力,通过 Service 资源和 DNS 的配合,实现了简洁、自动化的服务发现机制。

1. Service 抽象与稳定入口
  • 在 Kubernetes 中,一组功能相同的 Pod(即服务实例)会被定义为一个 Service 对象。Service 拥有一个固定的虚拟 IP(ClusterIP)和一个不变的 DNS 名称(如 my-service.namespace.svc.cluster.local)。
  • 无论背后的 Pod 如何创建、销毁或迁移,这个虚拟 IP 和 DNS 名称都保持不变,消费者只需访问这个稳定入口。
2. 自动端点管理
  • Service 通过标签选择器关联后端 Pod。Kubernetes 会动态维护一个 Endpoint(或 EndpointSlice)对象,实时记录匹配该 Service 的所有 Pod 的 IP 地址和端口。
  • 当 Pod 变化(如新副本启动、旧副本终止)时,Endpoint 会自动更新,无需人工干预。
3. 内置服务发现机制

Kubernetes 提供了两种主要方式来发现服务:

  • 环境变量:Pod 启动时,kubelet 会将当前命名空间中所有 Service 的信息(如 ClusterIP)以环境变量的形式注入到 Pod 中。但这种方式依赖启动顺序(先有 Service 后有 Pod 才能获取变量),不够灵活。
  • DNS(推荐):集群中运行着一个 DNS 服务(如 CoreDNS),它会为每个 Service 创建对应的 DNS 记录。Pod 内的应用可以直接通过 Service 名称(如 my-service)访问,DNS 解析出 ClusterIP,请求随即被转发到后端 Pod。
4. 流量转发与负载均衡
  • 节点上的 kube-proxy 组件负责实现 Service 的流量转发。它通过 watch 机制监听 Kubernetes API 中 Service 和 Endpoint 的变化,动态更新节点上的 iptables 或 IPVS 规则。
  • 当请求到达 Service 的 ClusterIP 时,这些规则会将流量随机或按策略转发到其中一个健康的 Pod 上,实现了负载均衡和故障转移。
5. Headless Service(直接发现 Pod IP)
  • 如果应用需要直接获取所有后端 Pod 的真实 IP(例如某些数据库集群需要直接连接),可以将 Service 定义为 Headless(设置 clusterIP: None)。此时 DNS 会直接返回所有 Pod 的 IP 列表,而不是一个虚拟 IP,应用可以自行选择或处理。
6. Ingress 与 Gateway API
  • 对于外部流量进入集群,Kubernetes 提供了 Ingress 资源,它可以根据域名或路径将请求路由到不同的 Service,本质上是在集群入口处实现了更高级的 HTTP 层服务发现和路由。

三、对比总结

维度 传统架构 Kubernetes
动态性 依赖手动配置或外部工具更新,对扩缩容/故障响应慢 内置自动检测 Pod 变化,实时更新 Endpoint 和转发规则
复杂度 需要额外部署注册中心、负载均衡器等组件,并考虑高可用 服务发现是平台原生的,无需额外组件,开箱即用
客户端耦合 客户端可能需集成 SDK 与注册中心交互 客户端只需通过 DNS 名称访问,完全无侵入
运维成本 配置管理复杂,需要监控多个外部组件 由 Kubernetes 统一管理,简化运维
适用场景 相对静态的环境,或已有成熟基础设施的企业 容器化、微服务化、频繁变动的云原生应用

总的来说,Kubernetes 将服务发现与容器调度紧密集成,以声明式 API 和自动化控制器的方式,大大降低了服务发现的复杂度和人力成本,成为云原生时代的标配解决方案。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐