Pattern: container sidecar, ambasciatori e adattatori

4 min

Container e pattern architetturali: se hai sviluppato soluzioni distribuite, composte da più microservizi, avrai sicuramente utilizzato uno di questi approcci per la risoluzioni di problemi “comuni”. Se come me, non sapevi che il pattern da te scelto per l’implementazione avesse già un nome, ecco un pò di teoria per battezzare soluzioni che hai già verificato essere “di buon senso” grazie alla tua esperienza. E magari qualche spunto in più per il futuro. Vediamo cosa sono i container “sidecar”, “ambasciatori” e “adattatori”.

Introduzione

Il tuo microservizio è un container, che implementa parte della business logic della tua applicazione. Ti sarai reso subito conto che, in una soluzione distribuita composta da molti microservizi, ciascuno con il suo scopo di business, esistono una serie di funzioni comuni e indipendenti proprio dalla logica di business: logging, configurazione, security sono solo alcuni aspetti trasversali. Pattern noti come “sidecar”, “ambasciatore” o “adattare” nascono proprio dall’esigenza di implementare tali funzioni al di fuori del container di business e per essere riutilizzati ove necessario nell’intera soluzione.

Sidecar

Esempi di container Sidecar

Analizziamo subito un esempio pratico: il nostro container implementa un semplice servizio web, in grado di rispondere alle richieste HTTP da parte dei client. Supponiamo di avere la necessità di evolvere la nostra soluzione aggiungendo un layer di sicurezza, implementando quindi il protocollo HTTPS per servire i client. Di fronte a tale nuovo requisito, abbiamo due possibili approcci: intervenire direttamente sul codice del container originale o utilizzare un container “sidecar”.

Come per le motociclette il sidecar è posto al fianco della moto stessa, anche il container sidecar si posiziona al fianco del container legacy, in modo da estenderne le funzionalità.

Si viene a creare un gruppo di container (un POD) che serve le richieste dei client tramite protocollo HTTPS a cui risponde il servizio sidecar, il quale ruota le richieste (questa volta in HTTP) al container originale.

I vantaggi di questo approccio sono molti: per primo non è richiesto alcun intervento sul container originale. Inoltre il container sidecar:

  • Implementa il solo layer di sicurezza aggiuntivo ed è indipendente dalla business logic
  • Può essere riutilizzato ove necessario
  • Gestisce i certificati SSL

Un approccio simile può essere utilizzato in altre situazioni. Supponiamo per esempio di voler gestire in modo centralizzato tutti i parametri di configurazione della nostra soluzione, utilizzando un servizio specifico. Il servizio probabilmente esporrà le informazioni tramite delle API che i vari microservizi potranno interrogare per ottenere le informazioni necessarie. Per introdurre questa nuova gestione, l’utilizzo di container sidecar può rivelarsi molto indicato. Pensiamo per esempio a servizi legacy che prevedono di leggere la propria configurazione da file system (ad esempio da un file JSON). Analogamente a quanto visto nell’esempio precedente, condividendo il file system tra i due container, è possibile che il microservizio sidecar si occupi di richiedere tramite API la versione più recente della configurazione di sistema, per poi memorizzarla su file system e renderla disponibile al container legacy.

Ambasciatore

Esempi di container Ambassador

Un container “ambasciatore” ci viene d’aiuto quando l’accesso ad un servizio, essenziale per il nostro container legacy, deve essere reindirizzato secondo nuove policy.

Prendiamo ad esempio l’accesso ad un’area di storage che, crescendo di dimensioni, deve essere frammentata in più sottosistemi. In questo caso, per non intervenire sul container principale e dover implementare la medesima, nuova, logica di accesso su tutti i servizi impattati, si realizza un container ambasciatore che media l’accesso all’area di storage. La logica di routing verso i singoli sottosistemi viene quindi implementata su questo nuovo container e replicata ove serve.

Una delle applicazioni più interessati di un container di tipo ambasciatore è in ambito sperimentale: immaginiamo di voler testare il deployment di una nuova versione di un nostro microservizio, dirottando solo una piccola percentuale del totale delle richieste. Questa modalità di deployment, chiamata Canary, può essere appunto gestita con un container ambasciatore che ruoti la voluta percentuale di traffico al nuovo container.

Adattatore

Esempio di container Adapter

L’ultima tipologia di container che andiamo a trattare in questo post è “adattatore”: in questo caso abbiamo la necessità di adattare un’interfaccia esposta del nostro container legacy in modo che questa diventi fruibile da un servizio esterno sul quale non abbiamo possibilità di intervenire.

Un esempio di utilizzo di container adattatore è l’introduzione di un layer di monitoraggio del container legacy, per raccogliere, ad esempio, metriche collezionate da applicativi come Prometheus.

Esempio pratico

Esempio applicazione Flask con update da repository

Consideriamo una semplice web application realizzata in Flask e dotata di cache Redis. La soluzione è realizzata con due container e un volume dedicato a ospitare le risorse HTML da pubblicare.

Introduciamo un container sidecar che si occupi di rendere dinamico l’aggiornamento delle risorse HTML, monitorando periodicamente un repository Git ed eseguendo un’operazione di PULL per aggiornare la copia locale delle risorse.

Vediamo il relativo file di docker-compose.

I sorgenti dell’intera soluzione sono disponibili in questo repository.

Flask page
Docker Compose output

Conclusioni

Che si tratti di estendere le funzionalità di un nostro microservizio, di mediare l’accesso ad un servizio da cui dipende o di adattare la risposta dello stesso ad un servizio esterno, abbiamo visto come l’affiancamento di un container dedicato e riutilizzabile perché indipendente dalla business logic, è probabilmente la soluzione più indicata.

Quale altre applicazioni ci vengono in mente? Un ottimo libro per approfondire l’argomento è Designing Distributed Systems, di Brendan Burns.

Ci siamo divertiti? Alla prossima!

Leave a Comment