Saltar al contenidoJMRG
Todas las entradas

Patrón Sidecar: Extendiendo Aplicaciones sin Modificarlas

architecturemicroservicessidecarkubernetes

¿Qué es el Patrón Sidecar?

El patrón Sidecar es un patrón de arquitectura donde un componente auxiliar se despliega junto a tu aplicación principal, compartiendo el mismo ciclo de vida. El sidecar extiende o mejora la funcionalidad de la aplicación sin requerir cambios en su código.

flowchart LR
    subgraph Pod["Pod / Host"]
        App[Aplicación Principal]
        Sidecar[Sidecar Container]
    end

    App <--> Sidecar
    Sidecar --> Logs[Logging Service]
    Sidecar --> Metrics[Metrics Service]
    Sidecar --> Config[Config Service]

Casos de Uso Comunes

1. Service Mesh (Envoy/Istio)

// El sidecar proxy maneja toda la comunicación de red
interface ServiceMeshSidecar {
  // Traffic management
  handleIngressTraffic(request: Request): Promise<Response>;
  handleEgressTraffic(request: Request): Promise<Response>;

  // Observability
  collectMetrics(): Metrics;
  traceRequest(request: Request): Span;

  // Security
  terminateTLS(connection: Connection): SecureConnection;
  validateMTLS(certificate: Certificate): boolean;
}

// La aplicación no necesita saber sobre networking
class OrderService {
  async createOrder(order: Order): Promise<Order> {
    // Simplemente hace la lógica de negocio
    // El sidecar maneja: TLS, retries, circuit breaking, tracing
    const inventory = await fetch('http://inventory-service/check');
    return this.repository.save(order);
  }
}

2. Logging y Monitoring

// Sidecar que recolecta logs sin modificar la app
class LoggingSidecar {
  private logBuffer: LogEntry[] = [];

  constructor(
    private logPath: string,
    private destination: LogDestination
  ) {
    this.watchLogFile();
  }

  private watchLogFile(): void {
    // Observa el archivo de logs de la aplicación
    fs.watch(this.logPath, async (eventType) => {
      if (eventType === 'change') {
        const newLogs = await this.readNewEntries();
        await this.processAndShip(newLogs);
      }
    });
  }

  private async processAndShip(logs: LogEntry[]): Promise<void> {
    // Enriquece los logs con metadata
    const enriched = logs.map(log => ({
      ...log,
      pod: process.env.POD_NAME,
      node: process.env.NODE_NAME,
      timestamp: new Date().toISOString(),
    }));

    await this.destination.send(enriched);
  }
}

3. Configuration Management

// Sidecar que sincroniza configuración
class ConfigSidecar {
  private currentConfig: Config;

  constructor(
    private configSource: ConfigSource,
    private configPath: string,
    private refreshInterval: number
  ) {
    this.startSync();
  }

  private async startSync(): Promise<void> {
    setInterval(async () => {
      const newConfig = await this.configSource.fetch();

      if (this.hasChanged(newConfig)) {
        // Escribe la nueva config al volumen compartido
        await fs.writeFile(
          this.configPath,
          JSON.stringify(newConfig, null, 2)
        );

        // Opcionalmente notifica a la app
        await this.notifyApp();
      }
    }, this.refreshInterval);
  }

  private hasChanged(newConfig: Config): boolean {
    return JSON.stringify(newConfig) !== JSON.stringify(this.currentConfig);
  }
}

Implementación en Kubernetes

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  # Aplicación principal
  - name: app
    image: my-app:latest
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app
    - name: shared-config
      mountPath: /etc/config

  # Sidecar de logging
  - name: log-shipper
    image: fluent-bit:latest
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app
      readOnly: true

  # Sidecar de config
  - name: config-sync
    image: config-sync:latest
    volumeMounts:
    - name: shared-config
      mountPath: /etc/config

  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: shared-config
    emptyDir: {}

Ventajas y Desventajas

Ventajas Desventajas
No modifica la aplicación Mayor uso de recursos
Reutilizable entre servicios Complejidad operacional
Políglota (cualquier lenguaje) Latencia adicional
Ciclo de vida independiente Debugging más complejo
Separation of concerns Overhead de comunicación

Cuándo Usar

Situación Recomendación
Cross-cutting concerns ✅ Ideal
Service mesh ✅ Ideal
Legacy applications ✅ Muy útil
Simple monolitos ❌ Overkill

Conclusión

El patrón Sidecar es fundamental en arquitecturas modernas de microservicios, permitiendo agregar funcionalidades cross-cutting sin acoplar la lógica de negocio con concerns de infraestructura.