Consul’s service registration API is surprisingly flexible, allowing you to define services not just through static configuration files, but dynamically as they spin up and down.
Let’s see this in action. Imagine we have a simple web application that needs to register itself with Consul.
# First, let's check if the service is already registered (it shouldn't be)
curl http://localhost:8500/v1/catalog/service/my-web-app
# Now, we'll register it using the API
curl --request PUT --data '{
"Name": "my-web-app",
"ID": "my-web-app-123",
"Port": 8080,
"Address": "192.168.1.100",
"Check": {
"HTTP": "http://192.168.1.100:8080/health",
"Interval": "10s",
"Timeout": "1s"
}
}' http://localhost:8500/v1/catalog/register
# Let's check again to see our service registered
curl http://localhost:8500/v1/catalog/service/my-web-app
This PUT request to /v1/catalog/register is the core mechanism. You’re sending a JSON payload describing the service.
Name: This is the logical name for your service. Other services will query Consul using this name to discover instances.ID: A unique identifier for this specific instance of the service. It’s crucial for de-registration and for differentiating multiple instances of the sameName.Port: The port on which the service is listening. Consul uses this for health checks and for other services to connect.Address: The IP address where the service is running. If omitted, Consul typically defaults to the agent’s IP.Check: This defines a health check. Consul will periodically run this check to determine if the service instance is healthy. Here, we’re using an HTTP check against a/healthendpoint.Intervalis how often to run it, andTimeoutis how long to wait for a response.
The true power here is that this registration is not persistent. If the Consul agent restarts, or if the service instance itself dies and restarts on a different IP, you’ll need to re-register. This is by design, as it ties service registration directly to the lifecycle of the application instance. This dynamic registration is often managed by orchestration systems like Kubernetes or Nomad, which can detect when a new application instance starts and automatically call the Consul API.
When a service is registered with a health check, Consul doesn’t just store its existence; it actively monitors its health. If the health check fails repeatedly, Consul will mark that service instance as "critical" and stop returning it in discovery queries. This ensures that other services only discover and attempt to connect to healthy instances.
The ID field is more than just a label; it’s the primary key for managing the service instance. To remove a service registration, you use a PUT request to /v1/catalog/deregister with the exact same ID you used for registration. This idempotency is key for automation, as you can safely send a deregister request even if the service was already removed.
Consider the implications for scaling. When you scale up your web application, each new instance can independently register itself with a unique ID but the same Name. Consul then presents a unified view of all healthy instances of "my-web-app" to any querying service. When you scale down, the instances that shut down can deregister themselves, or if they don’t, their health checks will eventually fail, and Consul will automatically stop advertising them.
The Check field can be much more sophisticated than a simple HTTP endpoint. You can define TCP checks, script checks that run arbitrary commands, and TTL checks where the service itself periodically "heartbeats" to prove it’s alive. The flexibility in checks allows you to accurately represent the health of diverse application types.
The Consul API offers other endpoints for service discovery, but the /v1/catalog/register and /v1/catalog/deregister endpoints are fundamental for integrating your applications directly into Consul’s service mesh.
One subtle point often missed is how Consul handles IP addresses. If you register a service with Address: "192.168.1.100" and your Consul agent is running on a machine with multiple network interfaces, Consul will still use that specific IP. However, if you omit the Address, the Consul agent will typically bind the service registration to its own IP address. This can be a source of confusion if your Consul agents are running on nodes with ephemeral IPs or IPs that aren’t directly routable from other parts of your network. Always be explicit with Address if the service is not running on the same host as the Consul agent.
The next logical step after programmatic registration is to explore how Consul’s ACLs can secure these API endpoints, preventing unauthorized services from registering or deregistering critical infrastructure components.