Come containerizzare un'applicazione legacy

0
125
Shutterstock.com/Sergey Novikov

La containerizzazione ha trasformato il modo in cui le nuove applicazioni vengono sviluppate e distribuite. Tuttavia, molte organizzazioni conservano un catalogo arretrato di sistemi precedenti che richiedono un approccio diverso. Questa disconnessione tra vecchio e nuovo non deve essere perpetuata: puoi anche impacchettare i vecchi sistemi come contenitori, rendendo più facile continuare a evolverli con metodi di sviluppo più moderni.

In questo articolo, esamineremo un processo che puoi utilizzare per iniziare a containerizzare “legacy” Software. Anche se non ci saranno due prodotti uguali e il termine “legacy” è soggettivo, ci concentreremo su passaggi ampiamente applicabili per il confezionamento di sistemi strettamente accoppiati attualmente legati a singoli ambienti.

1. Identifica i sistemi candidati

Vale la pena prima preparare un inventario dei sistemi che ti consenta di identificare buoni candidati per la containerizzazione. In alcuni casi, potresti concludere che una particolare applicazione semplicemente non può essere containerizzata. Questo di solito accade quando ha requisiti hardware profondamente radicati o si basa su funzionalità del kernel e linguaggi di programmazione obsoleti.

I migliori candidati sono i sistemi utilizzati di frequente che beneficeranno immediatamente di uno sviluppo futuro accelerato. Cerca applicazioni che siano già abbastanza autonome se sei completamente nuovo alla containerizzazione. Selezionare un sistema che sia ben utilizzato ma non mission-critical ti darà la possibilità di risolvere eventuali problemi, consentendoti di riconoscere i vantaggi di una migrazione riuscita.

2 . Componentizza il sistema

Puoi containerizzare il tuo sistema candidato scrivendo un Dockerfile, comprese tutte le dipendenze dell'applicazione, e chiamandolo un giorno. Sebbene questo sia un modo valido per inserire rapidamente un sistema in un container, non dovrebbe essere l'obiettivo finale dei tuoi sforzi. Un contenitore monolitico risulterà in build lunghe, dimensioni enormi dell'immagine e scarsa scalabilità.

Invece dovresti cercare opportunità per dividere ciascuno dei tuoi sistemi in singoli componenti. Tali componenti dovrebbero finire nei propri contenitori, evitando che ogni singolo pezzo diventi troppo grande. Potrai ridimensionare i componenti individualmente creando repliche aggiuntive di contenitori con risorse limitate.

Questo passaggio è importante anche per stabilire la modularità generale e incoraggiare un'ulteriore adozione di contenitori. Man mano che separi più sistemi nei loro componenti, inizierai a trovare sovrapposizioni che ti consentiranno di riutilizzare le immagini del contenitore che hai già creato. Noterai che diventa gradualmente più facile continuare a containerizzare.

Decidere dove dividere i componenti non dovrebbe sembrare troppo faticoso. Inizia identificando dove il sistema fa affidamento su servizi che sono già esterni al suo codice sorgente. Le connessioni al database, le code di messaggi, i server di posta elettronica, i proxy e i gateway dovrebbero essere tutti indipendenti dal componente che potenziano. Separerai questi nei loro contenitori che si trovano accanto all'istanza che esegue il tuo codice.

Vale anche la pena cercare opportunità per rifattorizzare ciò che è rimasto. Il tuo servizio ha troppe responsabilità che potrebbero essere suddivise in unità funzionali separate? Potresti avere un'API del profilo utente che accetta i caricamenti di foto; il servizio che ridimensiona quelle foto potrebbe essere un buon candidato per essere eseguito autonomamente nel proprio contenitore.

3. Prepara i tuoi componenti

Dopo aver separato i componenti, devi prepararli per funzionare in un ambiente containerizzato. I contenitori presentano diverse differenze chiave rispetto alle macchine virtuali tradizionali. Archiviazione persistente, configurazione e collegamenti tra i componenti sono i tre più importanti da considerare in anticipo.

Memoria persistente

I contenitori sono ambienti effimeri. Le modifiche al filesystem vengono perse quando i tuoi contenitori si fermano. Sei responsabile della gestione dei dati persistenti della tua applicazione utilizzando i meccanismi forniti dal runtime del contenitore.

Nel caso di Docker, i volumi vengono utilizzati per rendere persistenti i dati al di fuori delle istanze del contenitore. I volumi vengono montati su percorsi specifici all'interno dei contenitori. Per evitare di dover montare dozzine di volumi, è meglio concentrare i dati dell'applicazione in poche directory di primo livello. Il montaggio dei volumi in tali posizioni garantirà la persistenza dei file archiviati dall'applicazione.

È importante controllare le interazioni del filesystem della tua applicazione per capire quali volumi ti servono e gli eventuali problemi che incontrerai. Non prestare attenzione a questo passaggio potrebbe essere costoso se i dati che si presume siano persistenti vengono persi ogni volta che un container viene riavviato.

Gestione della configurazione

Molte applicazioni legacy sono configurate utilizzando file di configurazione statici. Questi potrebbero essere in un formato dedicato, come XML, JSON o INI, o codificati utilizzando il linguaggio di programmazione del sistema.

I contenitori sono normalmente configurati da variabili di ambiente esterne. Le variabili vengono definite quando vengono creati i contenitori, utilizzando meccanismi come il flag -e di Docker con docker run. Vengono iniettati nell'ambiente del container in esecuzione.

L'utilizzo di questo sistema garantisce che tu possa fare affidamento sulla tua toolchain del contenitore per impostare e modificare i parametri di configurazione. Potrebbe essere necessario eseguire prima il refactoring dell'applicazione per supportare la lettura delle impostazioni dalle variabili di ambiente. Un modo comune per facilitare la transizione è inserire un piccolo script all'interno del punto di ingresso del contenitore. Questo può enumerare le variabili di ambiente al momento della creazione del contenitore e scriverle in un file di configurazione per la tua applicazione.

La containerizzazione ti fa pensare anche alla rete tra servizi. I servizi non sono generalmente esposti l'uno all'altro se non per configurazione esplicita. Puoi impostare il collegamento automatico in Docker unendo più contenitori alla stessa rete Docker. Questo offre una funzione di rilevamento dei servizi che consente ai contenitori di raggiungersi per nome.

Altre tecnologie di containerizzazione utilizzano approcci diversi al networking e all'individuazione dei servizi. Dopo aver separato i sistemi in singoli componenti, è necessario ricollegarli insieme utilizzando le funzionalità offerte dal runtime. La natura delle distribuzioni containerizzate significa che spesso c'è più complessità rispetto alla rete tra macchine virtuali o host fisici. Il traffico deve essere instradato e bilanciato il carico tra tutte le repliche dei container e le relative dipendenze, quindi dovresti riconoscere questi requisiti in anticipo.

4. Scrivi i tuoi file Docker

Dopo aver pianificato la tua architettura, puoi iniziare il lavoro fisico associato alla containerizzazione. Il primo passaggio consiste nello scrivere Dockerfiles per i componenti della tua applicazione. Questi definiscono la sequenza di comandi e azioni che creano un filesystem contenente tutto ciò di cui il componente ha bisogno per essere eseguito.

I Dockerfile iniziano con un'immagine di base appropriata a cui fa riferimento un'istruzione FROM. Questo è comunemente un sistema operativo (ubuntu:20.04, alpine:3) o un ambiente di linguaggio di programmazione predefinito (php:8, node:16). Puoi scegliere l'immagine che meglio si adatta all'ambiente esistente della tua applicazione. L'avvio da un filesystem vuoto è possibile, ma di solito non è necessario, a meno che non sia necessario un controllo estremamente granulare.

Il contenuto aggiuntivo è sovrapposto all'immagine di base da istruzioni come COPY ed RUN. Questi ti consentono di copiare i file dal tuo host ed eseguire comandi sul filesystem temporaneo della build. Dopo aver scritto il tuo Dockerfile, puoi compilarlo con la finestra mobile build -t my-image:latest . comando.

5. Imposta l'orchestrazione

Supponendo che tu abbia componentizzato il tuo sistema, ti ritroverai con un'immagine contenitore per ogni pezzo. Ora hai bisogno di un modo per richiamare tutti i contenitori contemporaneamente in modo da poter avviare comodamente un'istanza dell'applicazione funzionante.

Le installazioni di produzione più grandi utilizzano comunemente Kubernetes per questo scopo. È un sistema di orchestrazione dedicato che aggiunge i propri concetti di livello superiore per la creazione di distribuzioni containerizzate replicate. Sistemi e ambienti di sviluppo più piccoli sono spesso ben serviti da Docker Compose, uno strumento che si basa su file YAML più semplici per avviare uno “stack” di più contenitori:

versione: "3" app: image: my-web-app:latest ports: – 80:80 database: image: mysql:8.0 ports: – 3306:3306

Un file docker-compose.yml ti consente di avviare tutti i suoi servizi usando il docker- componi binario:

docker-componi su -d

L'impostazione di una qualche forma di orchestrazione rende il parco contenitori più gestibile e facilita il ridimensionamento tramite la replica. Sia Kubernetes che Docker Compose sono in grado di avviare più istanze dei tuoi servizi, una funzionalità che non può essere raggiunta con applicazioni legacy formate da componenti strettamente accoppiati.

6. After The Move: monitoraggio ed espansione della flotta di container

La containerizzazione non termina con l'avvio di un'istanza della tua applicazione. Per ottenere il massimo dalla tecnologia, devi monitorare adeguatamente i tuoi container per rimanere informato sugli errori e sull'utilizzo delle risorse.

I sistemi più grandi sono serviti al meglio da una piattaforma di osservabilità dedicata in grado di aggregare registri e metriche da tutta la tua flotta. Potresti già utilizzare una soluzione simile con le distribuzioni di app legacy, ma è ancora più importante per i container. Una buona osservabilità ti consentirà di risalire ai problemi fino all'istanza del contenitore da cui hanno avuto origine, facendo emergere le informazioni che contano quando hai centinaia o migliaia di repliche.

Per continuare a espandere la tua flotta, raddoppia la documentazione e la standardizzazione. Abbiamo già visto come la suddivisione dei sistemi in componenti aiuti il ​​riutilizzo futuro. Tuttavia, questo funziona in modo efficace solo se hai documentato ciò che hai e come ogni pezzo si adatta insieme. Prendersi del tempo per scrivere del tuo sistema e del processo che hai seguito semplificherà il lavoro futuro. Aiuterà anche i nuovi membri del team a capire le decisioni che hai preso.

Ne vale la pena?

La containerizzazione è utile quando si sente che lo sviluppo di un sistema è frenato dai suoi processi attuali. La possibilità di distribuirlo come set di contenitori semplifica l'esperienza di sviluppo e offre maggiore versatilità nella distribuzione. Ora puoi avviare il servizio ovunque sia disponibile un runtime del contenitore, sia che si tratti di un'istanza sul tuo laptop o di 1.000 su un provider di cloud pubblico.

Puntare tutto sui container rende più facile sfruttare la potenza del cloud, consolidare le implementazioni e ridurre i costi dell'infrastruttura in locale. Tuttavia, queste vittorie apparenti possono essere controbilanciate dalla necessità di riqualificare ingegneri, assumere nuovi talenti specializzati e mantenere i tuoi container nel tempo.

La decisione di containerizzare un sistema legacy deve considerare il valore di quel sistema per l'azienda, il tempo attualmente impiegato per mantenerlo e la probabile riduzione derivante dall'utilizzo di container. Potrebbe essere meglio lasciar perdere i servizi a bassa priorità se i processi ad essi associati non causano problemi immediati.

Va riconosciuto che non tutte le app legacy avranno bisogno o saranno in grado di utilizzare tutti i vantaggi pubblicizzati della containerizzazione. L'adozione è uno spettro, dall'esecuzione del sistema in un unico contenitore monolitico, fino alla completa componentizzazione, orchestrazione e integrazione con suite di osservabilità. Quest'ultimo modello è il target ideale per le applicazioni business-critical che gli ingegneri evolvono ogni giorno; al contrario, il primo può essere adeguato per servizi raramente toccati in cui l'ostacolo principale è il tempo dedicato al provisioning di nuovi ambienti di sviluppo basati su VM.

Conclusione

La migrazione di applicazioni legacy a flussi di lavoro containerizzati può sembrare difficile in superficie. Suddividere il processo in fasi distinte di solito aiuta a definire dove ti trovi e dove vuoi essere. In questo articolo, abbiamo esaminato sei fasi granulari che puoi utilizzare per avvicinarti alla containerizzazione dei sistemi esistenti. Abbiamo anche discusso alcune delle considerazioni da fare quando si decide se procedere.

Da un punto di vista concettuale, la containerizzazione di un'applicazione legacy è leggermente diversa dal lavorare con una nuova. Stai applicando gli stessi principi di componentizzazione, servizi collegati e configurazione iniettati dall'ambiente esterno. La maggior parte dei sistemi sono relativamente semplici da containerizzare se visti da questa prospettiva. Concentrarsi su questi aspetti ti aiuterà a disaccoppiare le tue applicazioni, creare componenti scalabili e ideare una metodologia di containerizzazione efficace.

LEGGI SUCCESSIVO

  • › Quanto lontano può arrivare un'auto elettrica con una sola carica?
  • › Quanto costa ricaricare una batteria?
  • › Questi gadget scacciano le zanzare
  • › 4 modi in cui stai danneggiando la batteria del tuo laptop
  • › Recensione PrivadoVPN: sconvolgere il mercato?
  • › “Atari era molto, molto difficile” Nolan Bushnell su Atari, 50 anni dopo