The microservice count is growing fast. The monolith is mostly gone and what replaced it is dozens of services across datacenters. We don’t have a uniform naming convention. Finding a service means knowing which team owns it, which cloud it’s on, and what they called it. That’s not scalable.
Consul fixed the naming problem first.
Service discovery
Every service registers with Consul. The DNS interface gives us a consistent way to find anything:
search.service.consul
search-staging.service.consul
search-beta.service.consul
A service that needs to talk to search doesn’t hardcode a hostname or an IP – it resolves search.service.consul and gets back healthy nodes. The -staging and -beta suffixes are just service names. Same convention, separate pools.
We’re experimenting with a multi-cloud setup. Some services run in one datacenter, some in the other, some in both. For the default datacenter, search.service.consul is enough. When you need to reach a specific datacenter, you qualify it:
search.dc1.service.consul
search.dc2.service.consul
Most services never use the datacenter qualifier. Cross-datacenter queries work through the same DNS interface when you need them.
Node names follow a similar pattern. web-01.node.consul, worker-03.node.consul – predictable enough that you can guess the address before looking it up.
Health checks
Consul runs health checks on every registered service. If a node fails its check, it gets pulled from the DNS results. No manual intervention, no on-call rotation to remove a bad node. Services resolve the DNS name and only get back nodes that are passing.
This matters most during deploys. A new version comes up, registers, passes its health check, and starts receiving traffic. The old version deregisters and drains. If the new version fails its health check, it never enters the pool. The deploy effectively rolls back without anyone doing anything.
KV store
The key-value store became the dynamic config layer. Feature flags, rate limits, circuit breaker thresholds, numeric constants – anything that used to be a hardcoded value or an environment variable now lives in Consul KV.
A service watches its config path. When a value changes, the service picks it up without a restart. Changing a rate limit from 100 to 200 requests per second is a KV write, not a release. Enabling a feature flag for 10% of users is a KV write. Adjusting a timeout threshold during a traffic spike is a KV write.
No deploy pipeline. No code review for a config change. The value propagates in seconds.
This got popular fast. Too fast. Teams started putting everything in KV – not just operational thresholds but business logic constants, A/B test percentages, UI copy. We had to push back. KV is for operational config that needs to change without a release. Business logic belongs in code where it gets reviewed and versioned. The line between “config” and “code” gets blurry when changing a value is this easy.
What Consul replaced
Before Consul, service locations were in config files. A new service meant updating every config file that referenced it. A cloud migration meant updating hostnames everywhere. A dead node meant someone noticing and removing it manually.
Now there’s one source of truth for where services live and whether they’re healthy. The naming convention came for free – once everything registers with Consul, the DNS names are the convention. payment.service.consul is the payment service.