Appearance
Consul by HashiCorp
Consul es una herramienta de HashiCorp para descubrimiento de servicios, configuración y segmentación de redes. Permite que los servicios se registren y descubran entre sí, proporciona health checks, y facilita la comunicación segura en arquitecturas distribuidas.
Conceptos clave
- Service Discovery: Registro y descubrimiento automático de servicios
- Health Checking: Monitoreo del estado de servicios y nodos
- KV Store: Almacenamiento clave-valor para configuración
- Agent: Proceso que se ejecuta en cada nodo del cluster
- Datacenter: Agrupación lógica de servicios y nodos
- Service Mesh: Comunicación segura entre servicios con Consul Connect
Ventajas de Consul
- Descubrimiento dinámico: Servicios se encuentran automáticamente
- Health checks: Detección automática de servicios caídos
- Multi-datacenter: Soporte nativo para múltiples datacenters
- DNS y HTTP: Múltiples interfaces de consulta
- Service Mesh: Comunicación segura con mTLS
- KV Store: Configuración centralizada
Esta es una guía esencial para introducirse en el descubrimiento de servicios con Consul
Instalación y configuración de Consul
Instalación de Consul por Sistema Operativo
bash
# Linux/macOS
wget https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip
unzip consul_1.17.0_linux_amd64.zip
sudo mv consul /usr/local/bin/
# macOS con Homebrew
brew install consul
# Verificar instalación
consul --versionModo desarrollo (solo para pruebas)
bash
# Iniciar Consul en modo dev
consul agent -dev
# En otra terminal, verificar miembros
consul members
# Ver servicios registrados
consul catalog servicesDocker
bash
docker run -d \
--name consul \
-p 8500:8500 \
-p 8600:8600/udp \
-e CONSUL_BIND_INTERFACE=eth0 \
hashicorp/consul:latest agent -dev -ui -client=0.0.0.0
# Acceder a UI
open http://localhost:8500Operaciones básicas
Registrar y consultar servicios
bash
# Registrar servicio manualmente
consul services register -name=web -port=8080
# Listar servicios
consul catalog services
# Consultar servicio específico
consul catalog nodes -service=web
# Consultar via DNS
dig @127.0.0.1 -p 8600 web.service.consul
# Consultar via HTTP API
curl http://localhost:8500/v1/catalog/service/web
# Deregistrar servicio
consul services deregister -id=webKey-Value Store
bash
# Escribir valor
consul kv put config/app/db_host localhost
consul kv put config/app/db_port 5432
# Leer valor
consul kv get config/app/db_host
# Leer en formato JSON
consul kv get -detailed config/app/db_host
# Listar claves
consul kv get -recurse config/app/
# Eliminar clave
consul kv delete config/app/db_hostEjemplo con JavaScript (Node.js)
Primero instalas el módulo consul (npm install consul) y como ejemplo esencial tendríamos un código como el siguiente:
javascript
const Consul = require('consul');
const consul = new Consul({
host: 'localhost',
port: 8500
});
async function consulEasy() {
try {
// Registrar servicio
await consul.agent.service.register({
name: 'api-service',
port: 3000,
check: {
http: 'http://localhost:3000/health',
interval: '10s'
}
});
console.log('Service registered successfully');
// Consultar servicios
const services = await consul.catalog.service.nodes('api-service');
console.log('\nRegistered services:');
services.forEach(service => {
console.log(` - ${service.ServiceName} at ${service.ServiceAddress}:${service.ServicePort}`);
});
// Escribir en KV Store
await consul.kv.set('config/api/timeout', '30');
await consul.kv.set('config/api/retries', '3');
console.log('\nConfiguration stored in KV');
// Leer de KV Store
const timeout = await consul.kv.get('config/api/timeout');
const retries = await consul.kv.get('config/api/retries');
console.log('\nConfiguration:');
console.log(` Timeout: ${timeout.Value}`);
console.log(` Retries: ${retries.Value}`);
// Listar todas las claves
const keys = await consul.kv.keys('config/api/');
console.log('\nAvailable config keys:', keys);
} catch (error) {
console.error('Error:', error.message);
}
}
consulEasy();Ejemplo con Java (JBang)
Semejante al anterior ejemplo, para Java podemos usar JBang. Veamos el código:
java
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.orbitz.consul:consul-client:1.5.3
//DEPS com.google.guava:guava:32.1.3-jre
//JAVA 21
import com.orbitz.consul.Consul;
import com.orbitz.consul.KeyValueClient;
import com.orbitz.consul.model.health.ServiceHealth;
import com.orbitz.consul.AgentClient;
import com.orbitz.consul.model.agent.ImmutableRegistration;
import com.orbitz.consul.model.agent.Registration;
import java.util.List;
public class ConsulEasy {
public static void main(String[] args) {
System.out.println("Consul with Java");
System.out.println("================\n");
// Conectar a Consul
Consul consul = Consul.builder()
.withUrl("http://localhost:8500")
.build();
AgentClient agentClient = consul.agentClient();
KeyValueClient kvClient = consul.keyValueClient();
// Registrar servicio
System.out.println("Registering service...");
Registration service = ImmutableRegistration.builder()
.id("java-service-1")
.name("java-service")
.port(8080)
.address("localhost")
.build();
agentClient.register(service);
System.out.println("Service registered successfully\n");
// Consultar servicios
System.out.println("Querying services...");
List<ServiceHealth> services = consul.healthClient()
.getHealthyServiceInstances("java-service")
.getResponse();
System.out.println("Healthy services:");
services.forEach(s -> {
System.out.println(" - " + s.getService().getService() +
" at " + s.getService().getAddress() +
":" + s.getService().getPort());
});
// Escribir en KV Store
System.out.println("\nWriting to KV store...");
kvClient.putValue("config/java/max_connections", "100");
kvClient.putValue("config/java/timeout", "5000");
System.out.println("Configuration stored\n");
// Leer de KV Store
System.out.println("Reading from KV store...");
String maxConn = kvClient.getValueAsString("config/java/max_connections").orElse("N/A");
String timeout = kvClient.getValueAsString("config/java/timeout").orElse("N/A");
System.out.println("Configuration:");
System.out.println(" Max Connections: " + maxConn);
System.out.println(" Timeout: " + timeout + "ms");
// Listar claves
System.out.println("\nListing keys...");
List<String> keys = kvClient.getKeys("config/java/");
System.out.println("Available keys:");
keys.forEach(key -> System.out.println(" - " + key));
}
}Ejecutar:
bash
jbang ConsulEasy.javaEjemplos para integración con aplicaciones
Definición de servicio con archivo JSON
json
{
"service": {
"name": "web",
"port": 8080,
"tags": ["production", "v1"],
"check": {
"http": "http://localhost:8080/health",
"interval": "10s",
"timeout": "1s"
}
}
}Registrar:
bash
consul services register web-service.jsonDocker Compose con Consul
yaml
version: '3.8'
services:
consul:
image: hashicorp/consul:latest
ports:
- "8500:8500"
- "8600:8600/udp"
command: agent -dev -ui -client=0.0.0.0
web:
image: nginx:alpine
ports:
- "8080:80"
depends_on:
- consul
environment:
CONSUL_HTTP_ADDR: consul:8500
registrator:
image: gliderlabs/registrator:latest
command: -internal consul://consul:8500
volumes:
- /var/run/docker.sock:/tmp/docker.sock
depends_on:
- consulHealth Check avanzado
bash
# Registrar servicio con múltiples checks
consul services register - <<EOF
{
"name": "database",
"port": 5432,
"checks": [
{
"tcp": "localhost:5432",
"interval": "10s"
},
{
"script": "/usr/local/bin/check_db.sh",
"interval": "30s"
}
]
}
EOFConsul es fundamental para arquitecturas de microservicios, proporcionando descubrimiento de servicios, configuración centralizada y comunicación segura en entornos distribuidos.