skip to content

What is Kubernetes-native service discovery in Spring Cloud, and how does it differ from using Eureka?

level: juniorimportance: must knowfreq 60%

answer

  1. Cluster IS the registry
  2. Reads Service + Endpoints from kube-apiserver
  3. No self-register, no heartbeat
  4. Same DiscoveryClient SPI as Eureka
  5. Readiness probe gates instances

basics

~20 s

Spring Cloud Kubernetes provides a DiscoveryClient that looks up other services by reading Kubernetes' own Service and Endpoints records from the API server. Unlike Eureka, there is no separate registry to run and apps do not self-register.

solid answer

~40 s

Spring Cloud Kubernetes ships a DiscoveryClient implementation that treats the Kubernetes cluster itself as the service registry. Instead of running a Eureka server and having each app register/heartbeat, it queries the kube-apiserver for Service objects and their backing Endpoints, mapping each ready pod behind a Service into a ServiceInstance. So you keep the familiar Spring abstractions — DiscoveryClient.getServices(), getInstances(serviceId), and integration with Spring Cloud LoadBalancer — but the source of truth is Kubernetes, which already knows every pod's IP and readiness state. Benefits: no extra registry to operate, no registration heartbeats, and readiness probes automatically gate which instances are discoverable. You add spring-cloud-starter-kubernetes-fabric8 (or -client) and enable discovery; the same @LoadBalanced RestTemplate/WebClient or Feign code works unchanged.

code

java · 26 lines
java
// Dependency (Maven): spring-cloud-starter-kubernetes-fabric8

@SpringBootApplication
public class OrdersApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrdersApplication.class, args);
    }

    // Client-side load balanced across pods behind the 'inventory' Service
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
class InventoryGateway {
    private final RestTemplate rt;
    InventoryGateway(RestTemplate rt) { this.rt = rt; }

    String stock(String sku) {
        // 'inventory' resolves via K8s Endpoints -> a ready pod IP
        return rt.getForObject("http://inventory/stock/" + sku, String.class);
    }
}

go deeper

for a junior

Know the one-liner: Kubernetes is the registry, apps don't self-register, you read Services/Endpoints instead of running Eureka.

for a middle

Should connect it to the DiscoveryClient SPI and @LoadBalanced clients working unchanged.

for a senior

Should articulate readiness-driven membership and the DNS-vs-DiscoveryClient tradeoff.

for a principal

Should frame it as a migration/portability story and know when plain Service DNS is sufficient versus needing pod-level instance lists.

**The problem.** In a microservice system, service A needs to find where service B is running. The classic Spring Cloud Netflix answer was **Eureka**: a standalone registry server where each instance *registers* itself on startup, sends periodic *heartbeats*, and other clients *fetch* the registry to get a list of instances. That means you operate an extra server and every app carries a Eureka client. **The Kubernetes insight.** When you run on Kubernetes, the cluster *already is* a service registry. A **Service** is a stable named abstraction over a set of pods; the **Endpoints** (or **EndpointSlice**) object attached to a Service lists the actual pod IP:port pairs that are currently *ready* (passing readiness probes). Kubernetes maintains this automatically as pods start, die, or scale. So you don't need Eureka — you just ask the **kube-apiserver**. **What Spring Cloud Kubernetes does.** It provides a `DiscoveryClient` implementation (historically `KubernetesDiscoveryClient`, and in recent versions `KubernetesInformerDiscoveryClient`) that implements the standard Spring Cloud Commons `org.springframework.cloud.client.discovery.DiscoveryClient` SPI. Its methods: - `getServices()` → lists Kubernetes **Service** names (optionally filtered by labels/namespace). - `getInstances(String serviceId)` → returns `List<ServiceInstance>`, one per ready pod behind that Service, resolved from the **Endpoints** subsets. Each `ServiceInstance` exposes host (pod IP), port, and metadata (labels, annotations, ports). Because it implements the same SPI as the Eureka client, everything downstream is unchanged: **Spring Cloud LoadBalancer** consumes the instance list, and a `@LoadBalanced` `RestTemplate`/`WebClient` or **OpenFeign** client calls `http://service-b/...` and gets client-side load-balanced to a real pod. **Key differences vs Eureka:** 1. **No registration.** Apps do not self-register or heartbeat. Kubernetes tracks membership via the Endpoints controller and readiness probes. 2. **No separate server.** The registry is the kube-apiserver you already run. 3. **Readiness-driven.** Only pods that pass their readiness probe appear in Endpoints (unless you opt in to not-ready addresses). 4. **RBAC required.** The pod's ServiceAccount needs permission to read services/endpoints from the API. **When to use it.** Choose it when running on Kubernetes and you want client-side load balancing, per-instance metadata, or gradual migration of existing Spring Cloud discovery code — without operating Eureka. If you only need simple request routing, plain **Kubernetes DNS** (`http://service-b.namespace.svc.cluster.local`) via the Service's ClusterIP may be enough and needs no library at all; Spring Cloud Kubernetes discovery adds value when you want pod-level instance lists and Spring's DiscoveryClient/LoadBalancer abstractions. **Out of scope here:** ConfigMap/Secret-based configuration is a separate concern; this leaf is only about discovery.

  • If Kubernetes already gives me DNS for Services, why use the Spring DiscoveryClient at all?
    Plain Service DNS resolves to the ClusterIP and lets kube-proxy round-robin at L4, giving you one virtual endpoint. The DiscoveryClient enumerates the actual pod instances, so you can do client-side load balancing with Spring Cloud LoadBalancer, read per-instance metadata (labels/annotations), and keep existing DiscoveryClient/Feign code portable across Eureka and Kubernetes.
  • Does an app need to call an API to register itself at startup?
    No. Registration is implicit: when the pod becomes ready, Kubernetes' Endpoints controller adds it to the Service's Endpoints. Spring just reads that list. There is nothing like Eureka's register/heartbeat call.

saying these in an interview costs you the question

  • Claiming apps must self-register with a heartbeat like Eureka
  • Saying you still need to run a Eureka server alongside Kubernetes
  • Confusing it with ConfigMap/Secret configuration (different feature)

context