Il modello Sidecar: estendere i microservizi senza modificare il codice

Il modello Sidecar: estendere i microservizi senza modificare il codice

Nei moderni sistemi cloud-native, ci si aspetta che i microservizi facciano molto di più che eseguire la logica aziendale. Devono gestire la registrazione, gestire i certificati SSL/TLS, raccogliere parametri, implementare meccanismi di ripetizione dei tentativi e coordinare le comunicazioni sicure con altri servizi.

Se incorporiamo tutte queste funzionalità trasversali direttamente all’interno della base di codice di ciascuna applicazione, ci ritroveremo con un ingrossamento del codice, un accoppiamento stretto e un blocco del linguaggio.

È qui che entra in gioco il modello Sidecar. In questa guida analizzeremo cos’è il modello Sidecar, perché è essenziale per le moderne architetture di microservizi e come funziona utilizzando semplici analogie ed esempi di configurazione Kubernetes.


L’analogia con il mondo reale: il sidecar della motocicletta

Il modo più semplice per comprendere questo schema è pensare a una motocicletta con sidecar.

Diagramma dell'architettura del modello Sidecar che mostra l'applicazione e i contenitori Sidecar all'interno di un pod

Immagina di avere una motocicletta ad alte prestazioni. È progettato per fare una cosa eccezionalmente bene: trasportare rapidamente un ciclista. Supponiamo ora di dover trasportare i bagagli dei passeggeri o aggiungere un posto extra.

Potresti riprogettare completamente il telaio, il motore e le ruote della motocicletta per trasformarla in un’auto. Tuttavia, ciò richiede uno sforzo enorme, rovina la semplicità della bici e ne rende difficile la manutenzione.

Invece, alleghi un sidecar.

Il sidecar è un’unità separata e autonoma che si collega alla motocicletta. Condivide il viaggio della moto, va ovunque vada la moto e opera in stretto tandem. Tuttavia, il motore principale della motocicletta rimane intatto.

Nell’architettura software:

  • La motocicletta è il contenitore della tua applicazione principale (che esegue la logica aziendale principale, come il checkout o l’autenticazione dell’utente).
  • Il Sidecar è un contenitore di supporto separato (che esegue attività di utilità, come la terminazione SSL, il monitoraggio o la spedizione dei log).
  • Il Viaggio è il ciclo di vita della distribuzione (ad esempio, un pod Kubernetes).

Il problema: preoccupazioni trasversali e ingorgo del codice

Prima dei sidecar, gli sviluppatori dovevano includere le librerie helper direttamente nel codice dell’applicazione. Ad esempio, se volessi inviare i log a un server centrale, hai importato una libreria di log. Se avevi bisogno di metriche, hai aggiunto un SDK per le metriche.

Questo approccio basato sulle biblioteche ha creato diverse sfide significative:

  • Blocco della lingua: se una libreria di monitoraggio è scritta solo in Go, non è possibile utilizzarla facilmente in un microservizio Python o Java. Devi trovare o creare una libreria per ogni lingua nel tuo stack.
  • Inquinamento del codice: la logica aziendale diventa ingombra di codice specifico dell’infrastruttura per nuovi tentativi, rilevamento dei servizi, crittografia e registrazione.
  • Aggiornamenti complessi: se viene rilevata una vulnerabilità di sicurezza nella libreria di comunicazione, ogni singolo microservizio deve aggiornare la propria dipendenza, ricompilare e ridistribuire.
  • Contesa di risorse: il codice helper viene eseguito nello stesso processo di runtime dell’applicazione principale, il che significa che una perdita di memoria nel logger può causare l’arresto anomalo dell’intera applicazione principale.

La soluzione: il modello Sidecar

Il Sidecar Pattern risolve questi problemi spostando le attività di supporto al di fuori del processo principale dell’applicazione e inserendole in un processo separato e indipendente eseguito proprio accanto all’applicazione.

Negli ambienti containerizzati come Kubernetes, il contenitore dell’applicazione e il contenitore sidecar vengono eseguiti all’interno dello stesso Pod. Perché condividono lo stesso Pod:

  • Stesso spazio dei nomi di rete: condividono lo stesso indirizzo IP e le stesse porte di rete. Possono parlare tra loro istantaneamente tramite localhost con una latenza praticamente pari a zero.
  • Volumi di archiviazione condivisi: possono accedere esattamente allo stesso spazio di archiviazione su disco, consentendo al sidecar di leggere file di registro o caricare file di configurazione scritti dall’applicazione principale.
  • Ciclo di vita identico: il sidecar viene distribuito, avviato, arrestato e ridimensionato insieme all’applicazione primaria.

Casi d’uso chiave del modello Sidecar

I sidecar sono incredibilmente versatili. Alcune delle applicazioni più comuni includono:

1. Service Mesh Proxying (ad esempio, Envoy, Linkerd)

Invece di effettuare chiamate HTTP dirette ad altri servizi, l’applicazione invia richieste al proxy sidecar locale. Il proxy sidecar gestisce il routing, i nuovi tentativi, il bilanciamento del carico, l’interruzione del circuito e la crittografia Mutual TLS (mTLS), quindi inoltra la richiesta. L’applicazione rimane completamente ignara di queste complessità di rete.

2. Raccolta e inoltro dei registri (ad es. Fluent Bit)

La tua applicazione scrive semplicemente le sue istruzioni di registro sull’output standard o su un file di registro locale. Un contenitore sidecar monitora quel file, analizza i log e li inoltra a un motore di analisi centrale come Elasticsearch o Datadog.

3. Configurazione e ricarica segreta

Un sidecar può monitorare un server remoto (come Consul o Vault) per aggiornamenti di configurazione o rotazioni di chiavi crittografiche. Quando viene rilevata una modifica, scarica i nuovi file su un volume condiviso e segnala all’applicazione principale di ricaricarli, senza bisogno di riavviare.


Esempio di implementazione di Kubernetes

Configurare un sidecar è semplice in Kubernetes. Ecco una semplice configurazione YAML che mostra un contenitore dell’applicazione che scrive i log su un volume condiviso e un contenitore sidecar Fluent Bit che legge e invia tali log:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logging-sidecar
  labels:
    app: billing-service
spec:
  containers:
    # 1. Primary Application Container
    - name: web-app
      image: node:18-alpine
      command: ["/bin/sh", "-c"]
      args:
        - >
          while true; do
            echo "$(date) [INFO] Transaction processed successfully" >> /var/log/app/output.log;
            sleep 5;
          done
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/app

    # 2. Sidecar Container (Log Shipper)
    - name: log-shipper
      image: fluent/fluent-bit:latest
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/app
      # In a real setup, Fluent Bit config would read /var/log/app/output.log
      # and forward it to an external logging system.

  # Shared disk storage accessible by both containers
  volumes:
    - name: shared-logs
      emptyDir: {}

Pro e contro del modello Sidecar

Come ogni modello di progettazione, i sidecar presentano dei compromessi:

Vantaggio (Pro) Svantaggio (Con)
Indipendente dalla lingua: il sidecar funziona nel proprio ambiente. Puoi utilizzare lo stesso assistente sidecar accanto alle app Go, Java, Python o Ruby. Carico eccessivo delle risorse: l’esecuzione di più contenitori per pod aumenta il consumo di CPU e memoria.
Ciclo di vita disaccoppiato: i team dell’infrastruttura possono aggiornare le patch di sicurezza del sidecar senza toccare il codice dell’applicazione. Maggiore complessità: la gestione del doppio dei contenitori complica le configurazioni di distribuzione, il debug e la pianificazione.
Isolamento indipendente degli errori: se il contenitore sidecar si blocca, Kubernetes può riavviarlo automaticamente senza disattivare l’applicazione principale. Leggera latenza di rete: l’instradamento del traffico attraverso un sidecar proxy locale aggiunge un piccolo salto, sebbene in genere sia trascurabile (< 1ms).

Conclusione

Il modello Sidecar è un elemento fondamentale delle moderne architetture cloud-native. Isolando le preoccupazioni trasversali, come proxy di rete, sicurezza, registrazione e gestione della configurazione, in un processo associato separato, consente agli sviluppatori di concentrarsi esclusivamente sulla creazione di valore aziendale.

Sebbene introduca un sovraccarico di risorse aggiuntivo e richieda piattaforme di orchestrazione dei contenitori come Kubernetes per una gestione efficace, i vantaggi di basi di codice più pulite, flessibilità del linguaggio e scalabilità indipendente lo rendono un modello indispensabile per i microservizi aziendali.


Scopri ulteriori approfondimenti sullo sviluppo software e sull’ingegneria backend sul blog di Ghaznix →