Service Discovery in Microservices: Kubernetes DNS, Consul and Cloud Registries
Why discovery becomes necessary
A monolith calls functions in the same process. A microservice calls another process over a network.
The first version often looks innocent:
booking-service -> http://10.20.0.17:8080That address becomes wrong as soon as the instance restarts, scales or moves.
I have worked in environments where discovery came from Kubernetes Services, cloud-managed registries and explicit configuration. Today I prefer the platform-native mechanism unless there is a real hybrid/multi-runtime reason to introduce a separate registry.
Kubernetes Service + DNS
In Kubernetes, the application can call a logical service name:
http://payment-service:8080Kubernetes maps that identity to healthy endpoints.
apiVersion: v1
kind: Service
metadata:
name: payment-service
spec:
selector:
app: payment-service
ports:
- port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 3
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: payment
image: registry.example/payment:2026.09.1
ports:
- containerPort: 8080The caller does not need pod IPs:
@Bean
WebClient paymentClient(WebClient.Builder builder) {
return builder
.baseUrl("http://payment-service:8080")
.build();
}Discovery solves location. It does not solve dependency health.
A service can resolve in DNS and still be:
- returning errors;
- saturated;
- slow;
- partially unavailable.
That is why discovery normally works together with readiness, timeouts and circuit breakers.
Consul / registry-based discovery
A registry becomes useful when services are not all inside one Kubernetes cluster or when infrastructure spans VMs, containers and multiple environments.
Conceptually:
payment-service instance
|
+--> register + health
|
v
Consul
^
|
booking-service asks:
"where is payment-service?"The registry itself becomes critical infrastructure. I want to know:
- what clients do when it is unavailable;
- how stale registrations expire;
- how health is checked;
- whether clients cache known endpoints;
- how ACLs protect registry data.
Client-side vs server-side discovery
Client-side:
Service A
|
query registry
|
choose instance
|
Service B instanceServer-side:
Service A
|
stable virtual endpoint/load balancer
|
Service B instancesKubernetes typically hides endpoint choice behind the Service abstraction. That keeps discovery logic out of application code.
What I do not do
I do not add Eureka/Consul inside Kubernetes just because an older Spring Cloud diagram contains a service registry.
Every new control plane has a cost:
availability
upgrades
security
monitoring
backups
incident ownershipIf Kubernetes DNS already solves the discovery problem, adding another registry can create complexity without creating business value.
Readiness is part of discovery
A new pod should not receive traffic just because the process started.
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3The readiness endpoint should verify only conditions required to serve traffic. If it performs ten expensive external dependency checks every five seconds, the health system itself can create load.
Discovery failure scenarios
DNS resolves an unhealthy service
Use readiness, bounded timeouts and resilience. DNS success is not application health.
Registry returns stale endpoints
Use TTL/lease expiry and short network timeouts. Do not assume an address remains correct forever.
Discovery system itself fails
Understand cached behavior. A registry outage should not automatically make every already-running service forget all known endpoints.
Cross-region discovery
Do not accidentally route latency-sensitive synchronous traffic across regions unless that is part of the recovery design.
Production checklist
- Prefer platform-native discovery.
- Never hard-code pod/task IPs.
- Keep service names stable.
- Configure readiness carefully.
- Use short connect timeouts.
- Monitor endpoint count.
- Monitor DNS/registry errors.
- Define cross-region routing intentionally.
- Protect the registry with least privilege.
- Test discovery-system failure.
FAQ
Does Kubernetes need Eureka?
Usually no. Kubernetes Service and DNS already provide dynamic service discovery.
Is service discovery the same as load balancing?
No. Discovery finds available endpoints; load balancing chooses where traffic goes.
Does discovery remove the need for a circuit breaker?
No. A discoverable endpoint can still be slow or unhealthy.
Can service discovery work across clusters?
Yes, but the mechanism becomes a platform/networking decision: service mesh, multi-cluster DNS, global load balancers or an external registry.
Related architecture guides
- [Microservices Design Patterns I Have Used in Real Enterprise Projects](/articles/microservices-design-patterns-real-enterprise-projects)
- [API Gateway Pattern](/articles/api-gateway-pattern-kong-aws-azure-spring-nestjs)
-
Circuit Breaker with Resilience4j
Architect's final take
Service discovery should disappear into the platform as much as possible. Application teams should consume stable service identities and spend their design effort on contracts, timeouts and failure behavior.
Your feedback helps prioritize deeper technical content.






