Skip to content

Service Discovery and Health Checks

πŸ“– Service Discovery - Service registration πŸ“– Health Checks - Check types

Overview

This document covers service registration, DNS and HTTP discovery, health check types, and prepared queries. Service discovery is 17% of the exam and is one of Consul's core features.

Service Registration

Registration Methods

Method Use Case Persistence
Config file Static services Survives agent restart
HTTP API Dynamic registration Lost on agent restart
CLI Quick registration Lost on agent restart

Config File Registration

{
  "service": {
    "name": "web",
    "id": "web-1",
    "port": 8080,
    "address": "10.0.1.20",
    "tags": ["v2", "production", "primary"],
    "meta": {
      "version": "2.0.0",
      "environment": "production"
    },
    "check": {
      "http": "http://localhost:8080/health",
      "interval": "10s",
      "timeout": "3s"
    }
  }
}
  • Place in agent config directory (-config-dir)
  • Loaded on agent startup or consul reload
  • Service ID must be unique within the agent
  • Service name used for discovery (can have duplicates across agents)

HTTP API Registration

# Register via API
curl -X PUT http://localhost:8500/v1/agent/service/register \
  -d '{
    "Name": "api",
    "Port": 9090,
    "Tags": ["v1"],
    "Check": {
      "HTTP": "http://localhost:9090/health",
      "Interval": "10s"
    }
  }'

# Deregister via API
curl -X PUT http://localhost:8500/v1/agent/service/deregister/api

πŸ“– Agent Service API - Service API

CLI Registration

# Register from file
consul services register web.json

# Deregister
consul services deregister -id=web-1

DNS Discovery

Query Format

<service>.service[.<datacenter>].consul
<tag>.<service>.service[.<datacenter>].consul

Standard Queries

# Basic service lookup (returns A records)
dig @127.0.0.1 -p 8600 web.service.consul

# SRV record (includes port number)
dig @127.0.0.1 -p 8600 web.service.consul SRV

# Tag-based query
dig @127.0.0.1 -p 8600 v2.web.service.consul

# Cross-datacenter query
dig @127.0.0.1 -p 8600 web.service.dc2.consul

# Node lookup
dig @127.0.0.1 -p 8600 node-1.node.consul

πŸ“– DNS Interface - DNS documentation

DNS Behavior

  • Default port: 8600 (configurable)
  • Only returns healthy service instances
  • Round-robin load balancing for multiple instances
  • TTL configurable per service or globally
  • Supports A, AAAA, SRV, and TXT record types
  • Can forward to upstream DNS via recursors

DNS Forwarding

# Configure system DNS to forward .consul queries to Consul
# In /etc/resolv.conf or systemd-resolved or dnsmasq:
# server=/consul/127.0.0.1#8600

HTTP API Discovery

Catalog API

# List all services
curl http://localhost:8500/v1/catalog/services

# List service instances
curl http://localhost:8500/v1/catalog/service/web

# List nodes
curl http://localhost:8500/v1/catalog/nodes

πŸ“– Catalog API - Catalog endpoints

Health API

# Healthy service instances only
curl http://localhost:8500/v1/health/service/web?passing=true

# All service instances with health status
curl http://localhost:8500/v1/health/service/web

# Health checks for a service
curl http://localhost:8500/v1/health/checks/web

# Health checks on a node
curl http://localhost:8500/v1/health/node/node-1

πŸ“– Health API - Health endpoints

Blocking Queries (Long Polling)

# Initial query returns X-Consul-Index header
curl -v http://localhost:8500/v1/health/service/web?passing=true
# Response header: X-Consul-Index: 42

# Blocking query waits for changes
curl http://localhost:8500/v1/health/service/web?passing=true&index=42&wait=5m
# Returns immediately when data changes, or after 5 minutes timeout
  • Efficient change detection without polling
  • Client provides last index, server blocks until data changes
  • Used by consul-template and watches internally

Health Checks

Check Types

Type How It Works Configuration
Script Executes command, checks exit code args, interval
HTTP Sends GET request, checks status code (2xx = pass) http, interval
TCP Opens TCP connection tcp, interval
TTL Service must actively report health ttl
gRPC Uses gRPC health check protocol grpc, interval
Docker Executes command in Docker container docker_container_id, args
Alias Mirrors another check's status alias_service

Health Check Examples

{
  "service": {
    "name": "web",
    "port": 8080,
    "checks": [
      {
        "id": "http-check",
        "name": "HTTP Health",
        "http": "http://localhost:8080/health",
        "interval": "10s",
        "timeout": "3s"
      },
      {
        "id": "tcp-check",
        "name": "TCP Port",
        "tcp": "localhost:8080",
        "interval": "15s"
      }
    ]
  }
}

Script Check

{
  "check": {
    "id": "disk-check",
    "name": "Disk Usage",
    "args": ["/usr/local/bin/check-disk.sh"],
    "interval": "30s"
  }
}
  • Exit code 0 = passing
  • Exit code 1 = warning
  • Any other exit code = critical

TTL Check

{
  "check": {
    "id": "app-ttl",
    "name": "Application TTL",
    "ttl": "30s"
  }
}
# Service reports health via API
curl -X PUT http://localhost:8500/v1/agent/check/pass/app-ttl
curl -X PUT http://localhost:8500/v1/agent/check/warn/app-ttl
curl -X PUT http://localhost:8500/v1/agent/check/fail/app-ttl
  • Service must actively report health within TTL
  • If TTL expires without update, check becomes critical
  • Useful when external checks are not feasible

Health Status Values

Status Meaning Discovery Impact
passing Service is healthy Included in results
warning Service has issues Included in results
critical Service is unhealthy Excluded from results

Deregister After Critical

{
  "check": {
    "http": "http://localhost:8080/health",
    "interval": "10s",
    "deregister_critical_service_after": "90s"
  }
}
  • Automatically deregisters service after sustained critical status
  • Useful for ephemeral services (containers, serverless)
  • Prevents stale service entries in the catalog

Prepared Queries

Overview

  • Pre-defined service queries with advanced options
  • Support failover to other datacenters
  • Can filter by tags, node metadata, and service metadata
  • Executed via DNS or HTTP API

πŸ“– Prepared Queries - Query documentation

# Create prepared query
curl -X POST http://localhost:8500/v1/query \
  -d '{
    "Name": "web-production",
    "Service": {
      "Service": "web",
      "Tags": ["production"],
      "Failover": {
        "Datacenters": ["dc2", "dc3"]
      }
    }
  }'

# Execute via HTTP
curl http://localhost:8500/v1/query/<query-id>/execute

# Execute via DNS
dig @127.0.0.1 -p 8600 web-production.query.consul

Failover Behavior

  • Try local datacenter first
  • If no healthy instances locally, try failover datacenters in order
  • Transparent to the querying application
  • Configurable nearest-datacenter sorting

Service Tags and Metadata

Tags

  • Simple string labels attached to services
  • Used for filtering in DNS and API queries
  • Common uses: version, environment, region
  • Multiple tags per service supported
  • Tag-based DNS: <tag>.<service>.service.consul

Metadata

  • Key-value pairs with richer structure than tags
  • Not queryable via DNS (API only)
  • Used for additional service information
  • Displayed in UI and API responses
{
  "service": {
    "name": "api",
    "tags": ["v2", "production"],
    "meta": {
      "version": "2.3.1",
      "team": "backend",
      "git_sha": "abc123"
    }
  }
}