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 或自建注册中心),让集群外调用方也能发现集群内服务。这条路径的关键在于“同步方向”和“健康状态来源”的确定。
二、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 内部用 CoreDNS,跨运行时统一注册用 Consul,外部 DNS 入口用 Azure Private DNS。关键是把注册来源、健康状态来源和查询接口三者对齐,并用可重复的命令验证解析结果与实例变化后的收敛行为。