Gestión de Microservicios con Consul: Descubrimiento y Configuración Distribuida

Consul, desarrollado por HashiCorp bajo el lenguaje Go, es una solución de infraestructura diseñada para el descubrimiento de servicios, la configuración y la segmentación en sistemas distribuidos. Su arquitectura ligera y su facilidad de deslpiegue lo convierten en una pieza fundamental para entornos de microservicios que requieren alta disponibilidad y escalabilidad horizontal.

Capacidades Principales de Consul

  • Descubrimiento de Servicios: Permite que los servicios se registren y sean localizados a través de interfaces DNS o HTTP. Esto facilita la comunicación entre componentes sin depender de direcciones IP estáticas.
  • Monitoreo de Salud (Health Checking): Los agentes de Consul realizan verificaciones constantes tanto de los servicios ("¿Responde el servidor web?") como de los nodos locales ("¿El uso de CPU es inferior al 90%?"). Los datos obtenidos permiten al router de tráfico evitar instancias defectuosas.
  • Almacén de Clave/Valor: Proporciona un sistema de almacenamiento jerárquico para configuraciones dinámicas, coordinación de flags de funciones y elección de líderes en sistemas distribuidos.
  • Seguridad en la Comunicación: Facilita la generación y distribución de certificados TLS para establecer conexiones mTLS automáticas, gestionando la segmentación de servicios mediante intenciones (intentions) en lugar de reglas de firewall complejas.
  • Soporte Multi-Datacenter: Soporta múltiples regiones de forma nativa, permitiendo que las aplicaciones escalen globalmente sin capas de abstracción adicionales.

Guía de Instalación

Entorno Windows

  1. Descargar el binario de 64 bits desde el sitio oficial de HashiCorp.
  2. Abrir una terminal en el directorio del ejecutable y lanzar el agente en modo desarrollo:
consul.exe agent -dev

El acceso a la interfaz administrativa se realiza mediante la URL http://localhost:8500.

Entorno Linux (RHEL/CentOS)

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install consul

# Verificar instalación
consul version

# Iniciar agente
consul agent -dev

Despliegue con Docker

Para un despliegue rápido y persistente, se puede utilizar el siguiente comando:

docker run -d -p 8500:8500 --restart=always --name=consul-node \
consul agent -server -bootstrap -ui -node=server-1 -client='0.0.0.0'
  • -server: Define el nodo como servidor de Consul.
  • -bootstrap: Indica que este nodo puede auto-proclamarse líder (solo para el primer nodo del clúster).
  • -client: Define la dirección de escucha para servicios HTTP/RPC; 0.0.0.0 permite conexiones externas.

Implementación en ASP.NET Core

Para integrar Consul en una arquitectura de .NET 6 o superior, se requiere el paquete Consul.AspNetCore.

Configuración en appsettings.json

{
  "DiscoveryConfig": {
    "ConsulAddress": "http://localhost:8500",
    "ServiceName": "InventoryAPI",
    "ServiceHost": "192.168.1.50",
    "ServicePort": 5100
  }
}

Extensión para el Registro de Sevricios

public class DiscoverySettings
{
    public string ConsulAddress { get; set; }
    public string ServiceName { get; set; }
    public string ServiceHost { get; set; }
    public int ServicePort { get; set; }
}

public static class ConsulRegistrationExtensions
{
    public static IServiceCollection RegisterWithConsul(this IServiceCollection services, IConfiguration config)
    {
        var settings = config.GetSection("DiscoveryConfig").Get<DiscoverySettings>();

        services.AddConsul(options => {
            options.Address = new Uri(settings.ConsulAddress);
        });

        services.AddConsulServiceRegistration(reg => {
            reg.ID = $"{settings.ServiceName}-{Guid.NewGuid()}";
            reg.Name = settings.ServiceName;
            reg.Address = settings.ServiceHost;
            reg.Port = settings.ServicePort;

            reg.Check = new AgentServiceCheck()
            {
                HTTP = $"http://{settings.ServiceHost}:{settings.ServicePort}/api/health",
                Interval = TimeSpan.FromSeconds(15),
                Timeout = TimeSpan.FromSeconds(5),
                DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1)
            };
        });

        return services;
    }
}

Consumo de Servicios desde un Cliente

El cliente consulta a Consul para obtener las instancias disponibles y realiza una selección (en este caso, aleatoria) para balancear la carga.

[Route("api/[controller]")]
[ApiController]
public class GatewayController : ControllerBase
{
    private readonly IConsulClient _consulClient;

    public GatewayController(IConsulClient consulClient)
    {
        _consulClient = consulClient;
    }

    [HttpGet("fetch-data")]
    public async Task<IActionResult> GetData()
    {
        var services = await _consulClient.Catalog.Service("InventoryAPI");
        var instances = services.Response;

        if (!instances.Any()) return NotFound("No se encontraron instancias del servicio.");

        var target = instances[Random.Shared.Next(instances.Length)];
        
        using var httpClient = new HttpClient();
        var response = await httpClient.GetStringAsync($"http://{target.ServiceAddress}:{target.ServicePort}/api/inventory");
        
        return Ok(response);
    }
}

Consul como Centro de Configuración

Mediante el sistema Key/Value, Consul permite centralizar los parámetros de la aplicación. Utilizando la librería Winton.Extensions.Configuration.Consul, es posible inyectar estas configuraciones directamente en el IConfiguration de .NET.

// Configuración en Program.cs
builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    var env = hostingContext.HostingEnvironment;
    var consulUrl = builder.Configuration["ConsulUrl"];
    
    // Estructura jerárquica: NombreApp/appsettings.json
    string keyPath = $"{env.ApplicationName}/settings.{env.EnvironmentName}.json";

    config.AddConsul(keyPath, options =>
    {
        options.ConsulConfigurationOptions = c => { c.Address = new Uri(consulUrl); };
        options.Optional = true;
        options.ReloadOnChange = true;
        options.OnLoadException = ctx => ctx.Ignore = true;
    });
});

Una vez configurado, los valores se recuperan de forma estándar mediante la inyección de IConfiguration, permitiendo actualizaciones en tiempo real sin necesidad de reiniciar el servicio cuando se modifican los valores en el panel de Consul.

Etiquetas: Consul Microservices DotnetCore ServiceDiscovery HashiCorp

Publicado el 6-19 00:43