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:

  1. Configuration files — JSON or HCL files in the agent's config directory, loaded at startup or on consul reload
  2. HTTP APIPUT /v1/agent/service/register with a JSON body, useful for dynamic registration at application boot
  3. 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:

TypeHow It WorksBest For
HTTPGET request; 2xx = passingWeb services, APIs
TCPOpens a TCP connectionDatabases, raw sockets
ScriptRuns a shell command; exit 0 = passingCustom logic
gRPCUses gRPC health protocolgRPC services
TTLService must check in periodicallyBackground workers
DockerRuns script inside a containerContainerized 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