Why Service Discovery Matters
In a dynamic infrastructure where services scale up and down, change IPs, or move between hosts, hardcoding addresses is a recipe for failure. Service discovery solves this by maintaining a live registry of where every service is running — and critically, whether it's actually healthy.
Consul provides two primary interfaces for querying this registry: a DNS interface and an HTTP API. Either can be used by your applications, often without any code changes.
How Services Get Registered
Consul supports three registration methods:
- Configuration files — JSON or HCL files in the agent's config directory, loaded at startup or on
consul reload - HTTP API —
PUT /v1/agent/service/registerwith a JSON body, useful for dynamic registration at application boot - Consul SDK libraries — Official and community libraries for Go, Python, Ruby, Java, and more
The Service Catalog
Every registered service lands in Consul's catalog, which is replicated across all server nodes via the Raft consensus algorithm. The catalog stores:
- Service name, ID, and tags
- Node name and IP address
- Port number
- Health check status
- Custom metadata (key/value pairs)
You can query the catalog directly with curl http://localhost:8500/v1/catalog/service/web to get a full JSON response for every registered instance of the "web" service.
Querying with DNS
Consul runs a DNS server on port 8600 by default. Any service registered in the catalog is immediately queryable via DNS using the format:
<service-name>.service.consul
For example:
dig @127.0.0.1 -p 8600 web.service.consul
This returns an A record pointing to a healthy instance. Consul automatically excludes unhealthy instances from DNS results — no stale IPs, no failed connections.
Tag-Based Filtering
If your service has multiple variants (e.g., primary and replica database instances), you can filter by tag:
dig @127.0.0.1 -p 8600 primary.web.service.consul
SRV Records for Port Discovery
Use the SRV record type to get both the IP address and the port in a single DNS query:
dig @127.0.0.1 -p 8600 web.service.consul SRV
Health Checks
Health checks determine which service instances are included in query results. Consul supports several check types:
| Type | How It Works | Best For |
|---|---|---|
| HTTP | GET request; 2xx = passing | Web services, APIs |
| TCP | Opens a TCP connection | Databases, raw sockets |
| Script | Runs a shell command; exit 0 = passing | Custom logic |
| gRPC | Uses gRPC health protocol | gRPC services |
| TTL | Service must check in periodically | Background workers |
| Docker | Runs script inside a container | Containerized workloads |
Filtering with the HTTP API
The HTTP API offers richer filtering than DNS. Use the filter query parameter with Consul's filtering language:
curl "http://localhost:8500/v1/health/service/web?filter=ServiceTags contains 'v2'"
This returns only instances of "web" tagged with "v2" — extremely useful for blue/green deployments or canary releases.
Blocking Queries for Real-Time Updates
Consul supports blocking queries — long-polling requests that return only when the data changes. Pass the index parameter from a previous response to hold the connection open until the catalog updates. This enables near-instant configuration updates without polling overhead.
Key Takeaways
- Consul's catalog is the source of truth for all service locations
- DNS integration requires zero application code changes
- Health checks automatically remove unhealthy instances from results
- Blocking queries enable reactive, event-driven service discovery