3. 服务发现与注册

在微服务架构中,服务实例的地址是动态变化的:Pod 会因扩缩容被重建,VM 会因升级被替换,IP 地址几乎不可能长期稳定。服务发现要解决的核心问题就是——调用方如何在运行时拿到一个当前可用的目标地址列表,并在实例变化时及时更新。本节围绕三条主流路径展开:Azure 原生服务发现、Consul on Azure,以及 Kubernetes DNS 与服务注册表的集成,并给出可落地的配置与验证方法。

一、三种服务发现路径的定位

Azure 原生服务发现主要依托 Azure 平台的负载均衡与 DNS 能力。对于部署在 AKS 上的服务,最常用的是 Kubernetes Service 提供的集群内 DNS 名称;对于 VM/VMSS 或容器实例,则可用 Azure 内部负载均衡器(ILB)或 Private DNS 区域提供稳定入口。它的优点是零额外组件、与 Azure 网络天然集成;局限是跨集群、跨云或混合场景下表达能力有限。

Consul on Azure 提供的是独立于编排平台的服务注册表。服务实例通过 Consul Agent 注册,调用方通过 DNS 接口或 HTTP API 查询健康实例。它适合多运行时(AKS + VM + 本地数据中心)混合部署,支持健康检查、KV 配置、意图(intentions)等能力。代价是需要自行运维 Consul 集群,并处理与 Azure 网络的打通。

Kubernetes DNS 与服务注册表集成,则是把 Kubernetes 的 Service/Endpoint 信息同步到外部注册表(如 Consul、Azure Private DNS 或自建注册中心),让集群外调用方也能发现集群内服务。这条路径的关键在于“同步方向”和“健康状态来源”的确定。

服务发现三条路径与调用链 调用方服务 OrderService 发起名称解析 路径 A:Azure 原生 K8s Service DNS Azure Private DNS 内部负载均衡 ILB 零额外组件 路径 B:Consul on Azure Consul Server 集群 Agent 注册 + 健康检查 DNS / HTTP API 查询 跨运行时统一注册表 路径 C:K8s DNS 集成 Service / Endpoint 同步 ExternalDNS / Consul Sync 外部注册表写入 集群内外互通 AKS Pod 10.244.1.7:8080 10.244.2.9:8080 Azure VM 10.1.0.4:8080 10.1.0.5:8080 外部调用方 本地数据中心 或其它云 解析结果 = 健康实例列表;注册表更新延迟与健康检查周期共同决定收敛时间

二、Azure 原生服务发现:从 Service 到 DNS 名称

在 AKS 中,创建一个 ClusterIP 类型的 Service 后,Kubernetes 会自动在集群 DNS(CoreDNS)中写入一条 A 记录,格式为 <service>.<namespace>.svc.cluster.local。调用方只需使用这个名称,CoreDNS 会返回 Service 的 ClusterIP,再由 kube-proxy 转发到后端 Pod。这是最基础、最常用的服务发现方式。

如果服务需要暴露给集群外,可以创建 LoadBalancer 类型 Service,Azure 会自动分配一个公共或内部 IP。若希望获得稳定的 DNS 名称,可结合 Azure Private DNS 区域,把该 IP 注册为一条 A 记录。例如,为订单服务创建私有 DNS 区域 contoso.internal,并添加记录 orders.contoso.internal → 10.0.1.20。这样,跨 VNet 的调用方只需解析该名称即可。

# 创建 ClusterIP Service
kubectl expose deployment orders --name=orders --port=8080 --target-port=8080

# 在集群内验证 DNS 解析
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup orders.default.svc.cluster.local

# 输出示例(教学示例,非实测)
Server:    10.0.0.10
Address:   10.0.0.10:53
Name:      orders.default.svc.cluster.local
Address:   10.0.0.55

验证要点:解析结果应返回 ClusterIP;若返回 NXDOMAIN,检查 Service 是否创建成功、CoreDNS Pod 是否正常、调用方是否在同一集群或已配置 DNS 转发。

三、Consul on Azure:注册、健康检查与查询

Consul 的部署通常采用 3 或 5 个 Server 节点组成 Raft 集群,每个业务节点运行 Consul Agent。服务注册有两种方式:配置文件注册和 HTTP API 注册。推荐使用配置文件,便于版本化管理。

{
  "service": {
    "name": "orders",
    "id": "orders-10.244.1.7-8080",
    "address": "10.244.1.7",
    "port": 8080,
    "tags": ["v1", "aks"],
    "check": {
      "http": "http://10.244.1.7:8080/health",
      "interval": "10s",
      "timeout": "2s",
      "deregister_critical_service_after": "60s"
    }
  }
}

该配置表示:服务名为 orders,实例 ID 唯一标识该实例,健康检查每 10 秒访问一次 /health,超时 2 秒;若连续 60 秒处于 critical 状态,则自动注销。调用方通过 DNS 查询 orders.service.consul 或 HTTP API /v1/health/service/orders?passing 获取健康实例列表。

在 Azure 上部署时,需注意:Consul Server 应跨可用区分布;Agent 与 Server 之间使用 8300/8301/8302 端口;若 AKS 与 VM 混合,需通过 VNet Peering 或 VPN 打通,并确保 Consul 的 gossip 加密与 TLS 配置正确。一个常见的验证命令如下:

# 查询健康实例
curl "http://consul.contoso.internal:8500/v1/health/service/orders?passing=true"

# DNS 查询
dig @127.0.0.1 -p 8600 orders.service.consul SRV

结果判读:HTTP API 返回的数组中,每个元素包含 Service 和 Checks;只有 Checks 全部为 passing 的实例才应被调用方使用。若返回空数组,说明没有健康实例,需检查 Agent 日志与健康检查端点。

四、Kubernetes DNS 与服务注册表集成

当集群外调用方需要发现 AKS 内部服务时,单纯依赖 CoreDNS 不够,因为 CoreDNS 只在集群内可达。此时需要把 Kubernetes 的 Service/Endpoint 信息同步到外部注册表。常见做法有两种:

  • ExternalDNS + Azure Private DNS:ExternalDNS 监听 Service/Ingress 变化,自动在 Azure Private DNS 区域中创建或更新 A 记录。适合以 DNS 为主要发现方式的场景。
  • Consul Sync Catalog:Consul 的 sync catalog 组件监听 Kubernetes Service,把服务注册到 Consul 注册表,并反向同步 Consul 服务到 Kubernetes。适合混合运行时统一注册表。

以 Consul Sync Catalog 为例,部署后它会为每个 Kubernetes Service 创建对应的 Consul 服务条目。同步方向可配置为 k8s-to-consul、consul-to-k8s 或双向。健康状态来源需明确:若以 Kubernetes readiness 为准,则 Consul 中的健康状态会跟随 Pod 就绪状态变化。

# 查看同步后的 Consul 服务
curl "http://consul.contoso.internal:8500/v1/catalog/service/orders"

# 查看 Kubernetes 侧 Service
kubectl get svc orders -o wide

验证闭环:在外部调用方上解析 orders.service.consul,应得到 AKS 中健康 Pod 的地址;然后手动删除一个 Pod,观察 Consul 中该实例是否在预期时间内被标记为 critical 并移除。若移除延迟过长,检查 readiness 探针周期与 Consul 健康检查间隔是否匹配。

选择建议:纯 AKS 内部调用优先用 Kubernetes DNS;需要跨 AKS、VM 和本地统一注册表时选 Consul;只需把集群内服务暴露给少量外部调用方且以 DNS 为主时,ExternalDNS + Azure Private DNS 最轻量。
常见误区:把服务发现等同于负载均衡。服务发现解决“地址从哪来”,负载均衡解决“请求发给谁”。两者常配合使用,但注册表本身不转发流量。另一个误区是忽略健康检查收敛时间,导致调用方仍拿到已失效实例。

综合来看,三条路径并非互斥。实际项目中常见组合是:AKS 内部用 CoreDNS,跨运行时统一注册用 Consul,外部 DNS 入口用 Azure Private DNS。关键是把注册来源、健康状态来源和查询接口三者对齐,并用可重复的命令验证解析结果与实例变化后的收敛行为。