patterntypescriptModerate
Service discovery with DNS vs client-side registry in Kubernetes
Viewed 0 times
service discoveryconsuleurekadnsclient-sideserver-sidekubernetes serviceClusterIPheadless service
Problem
When services need to find each other at runtime, hardcoded URLs break in dynamic environments. Two main approaches exist — DNS-based (server-side) and client-side registry (Consul/Eureka) — and choosing the wrong one creates operational complexity or missed features.
Solution
In Kubernetes, prefer DNS-based discovery: every Service gets a stable DNS name
<service>.<namespace>.svc.cluster.local. For cross-cluster or bare-metal scenarios, use Consul with health-checked service registrations and resolve via Consul DNS or HTTP API.// client-side discovery via Consul HTTP API
const { data } = await axios.get(
'http://consul:8500/v1/health/service/payment-service?passing=true'
);
const { Address, Port } = data[0].Service;
const baseUrl = `http://${Address}:${Port}`;Why
DNS-based discovery is operationally simple and works with any HTTP client. Client-side discovery gives the caller control over load-balancing strategies (round-robin, least-connections, weighted) but requires embedding a registry client in every service.
Gotchas
- DNS TTL caching can serve stale addresses — set TTL to 5-10 s and configure JVM/Node DNS cache accordingly
- Kubernetes DNS resolves ClusterIP, not individual pod IPs — combine with headless Services when you need pod-level addressing
- Client-side discovery increases coupling: every service must speak the registry API
- Health-check intervals determine how quickly failed instances are removed — tune for your SLA
Code Snippets
DNS vs Consul client-side resolution
// DNS-based (K8s): just use the stable hostname
const PAYMENT_URL = process.env.PAYMENT_URL ?? 'http://payment-svc.payments.svc.cluster.local:3000';
// Client-side (Consul)
async function resolveService(name: string): Promise<string> {
const res = await fetch(`http://consul:8500/v1/health/service/${name}?passing=true`);
const [entry] = await res.json();
return `http://${entry.Service.Address}:${entry.Service.Port}`;
}Context
Designing inter-service communication in a microservices deployment
Revisions (0)
No revisions yet.