Perché vogliamo trasformare Drupal in un’applicazione Cloud Native? Per rispondere dobbiamo partire dal principio affrontando la domanda appena precedente: perché il Cloud e quali sono le sue promesse.
Le infrastrutture Cloud oggi ci permettono di superare una serie di problematiche vive fino a poco tempo fa (siti che crollavano per picchi di traffico, tempi da definire per il fermo macchine da dedicare a nuovi deployment, disallineamenti tra le versioni di software in ambiente di sviluppo e produzione, per nominare alcuni tra i tanti esempi che ogni sviluppatore ha vissuto nella propria vita).
POTREBBE INTERESSARTI ANCHE: Perché scegliere Drupal per siti aziendali complessi
Le promesse che ci fanno il Cloud e l’approccio cloud native sono di vario tipo:
Il cloud native semplifica. Quindi, tornando a monte, perché non un Drupal Cloud Native?
Due sono i livelli di azioni da intraprendere, strettamente interconnessi, lungo i quali si dovrà operare: l'architettura dell'applicazione Drupal e l’adozione buone pratiche DevOps, senza le quali in realtà molti dei vantaggi del Cloud Computing verrebbero vanificati - e questo perché andare in Cloud non è semplicemente prendere un’applicazione e installarla su una VM di un vendor cloud, è molto di più.
Ma com’è fatta un’app cloud native? Qualcuno ha già pensato a formalizzarne i tratti distintivi e sul sito della Twelve Factor App si trova un elenco di fattori agnostici, requisiti base per poter considerare cloud native un’applicazione web generica. In questo talk (e articolo) non abbiamo il tempo di esplorarli tutti, ci soffermeremo su quelli più rilevanti per il nostro caso. Una cosa dobbiamo mettere in evidenza: nella lista indicata non vengono citati i container, perché questi non sono un requisito, bensì la soluzione ad oggi disponibile per poter far sì che un'applicazione sia cloud native.
POTREBBE INTERESSARTI ANCHE: Headless Drupal - Modern Approach to (Micro)Services and APIs
I container, e nello specifico Docker, sono il primo step del journey verso il cloud native, perché permettono di impacchettare l’applicazione con tutto quello che le serve per girare e per poterla portare dove vogliamo, compreso l’ambiente locale (ogni volta che parliamo di deploy, sottintendiamo anche deploy in locale). Quindi, di fatto, sulla nostra macchina potremmo avere installato soltanto Docker e pochi altri tool (ci arriviamo tra poco) e avremmo tutto quello che ci serve per partire.
Come costruire un'immagine Docker che servirà a dar vita ai container? Tutte le istruzioni risiedono nella codebase, che deve essere una, unica e versionata - al di là di tutti i vantaggi che ci dà il versionamento del codice di per sé: il nostro repository è la fonte di verità per la nostra immagine Docker. Dal repository possiamo buildare tutta l’applicazione, comprese le dipendenze necessarie. Nella nostra codebase avremo quindi: un Dockerfile, tutti gli script, compresi quelli per le automazioni, il nostro codice custom e la configurazione di Drupal. Questo è un punto importante, perché nel repository non verrà portato tutto quello che è una dipendenza, che invece verrà gestito con un package manager (nel mondo PHP è Composer) - e questo include non solo moduli e temi contrib, ma anche il core di Drupal, perché noi non vogliamo versionare quanto non è nostra diretta responsabilità. Quindi tutte le dipendenze saranno elencate nel composer.json del nostro progetto e il processo di build si occuperà di recuperarle.
Inoltre nel composer.json è consigliabile indicare come dev-dependency tutto quello che serve unicamente per lo sviluppo, perché vogliamo avere delle immagini il più possibile piccole e che contengano solo quello che serve.
A questo punto, un’unica codebase potrebbe rappresentare un problema, perché le configurazioni nei vari ambienti saranno diverse. L'esempio più classico è il database: abbiamo configurazioni diverse per connetterci al database locale, al database in produzione o a qualunque altro ambiente che abbiamo. Possiamo però gestirlo con delle variabili d'ambiente, che possiamo iniettare nel nostro container Docker. Gli passeremo runtime tutto quanto necessario per poter avere una configurazione dipendente dall'ambiente in cui ci troviamo sfruttando svariati modi: se in locale useremo probabilmente Docker Compose, su CI sfrutteremo la possibilità di registrare delle variabili d'ambiente direttamente sulla nostra piattaforma, e così via. Tornando all'esempio del database, nel settings.php utilizziamo un banale getenv(), per prendere dall’ambiente qualunque variabile necessaria. Un procedimento comodo non solo per settare diverse configurazioni, ma anche per abilitare o meno alcuni servizi a seconda del bisogno. Un esempio classico è Google Tag Manager: è probabile che in locale non vorremmo attivarlo, come è probabile che non vorremmo inquinare i dati di produzione con quelli per esempio di uno stage. Quindi possiamo decidere o meno di passare questa variabile a Drupal oppure passare variabili diverse. In questo modo noi isoliamo il comportamento dei nostri servizi puntualmente in base alle necessità di un ambiente specifico.
Procediamo nel nostro viaggio. Dobbiamo tenere presente che il container per sua natura è effimero, non è persistente. Ha un suo ciclo di vita che lo porta a morire per essere sostituito da un altro container, buildato a partire dalla stessa immagine. Noi, però su Drupal, abbiamo delle informazioni che devono essere persistite: i dati degli utenti. Database e file storage sono servizi di supporto che possiamo gestire collegandoli al nostro container. I dati non saranno quindi salvati nel container, ma risiederanno in un volume persistente, montato sul container stesso.
Quando ci troviamo in cloud, la cosa più comoda da fare è di appoggiarci a uno dei servizi messi a disposizione dai vendor. Una modifica che è fortemente consigliata per quanto riguarda lo storage è passare ad un object storage, qualcosa di diverso dal file storage standard di Drupal. E in locale? Utilissimo è l’utilizzo di MinIO: grazie alle già menzionate variabili d'ambiente, avremo un’identica configurazione di Drupal, indipendente dall'ambiente in cui si trova. Ma il file storage standard lo buttiamo via del tutto? Non è detto. Potrebbe servire perché magari abbiamo un'applicazione legacy che ha bisogno di questo supporto, quindi per quanto gli object storage siano una soluzione consigliata quando se ne ha la possibilità, non è per forza l'unica.
Con i log, possiamo sfruttare a nostro vantaggio una caratteristica dei container. Se già prima era buona pratica non salvare i log su database, ora non dobbiamo proprio più preoccuparcene perché Drupal sarà configurato in modo tale che vengano scritti direttamente sullo standard output del container. Decideremo poi in base all’ambiente in cui ci troviamo, come accedere a questi log e come gestirli (es. aggregarli e filtrarli in base alle nostre necessità).
Siamo a un ottimo punto del nostro viaggio perché la nostra applicazione è di fatto pronta - è cloud native! - ma non è ancora in cloud. E questo lo facciamo usando le pipeline, ovvero degli script di automazione per la continuous integration e la continuous delivery, che ad eventi specifici del nostro repository eseguono task automatici. Scelto il provider che preferiamo, il funzionamento è sostanzialmente lo stesso: chiediamo alla nostra pipeline di eseguire determinati task in un determinato ordine. Sicuramente chiederemo alla pipeline due operazioni basilari: buildare le immagini secondo le istruzioni che si trovano sul repository ed eseguire il deploy, cioè l'aggiornamento sull'ambiente designato della nostra applicazione, che nel caso di Drupal è ovviamente l'aggiornamento della codebase, l’update del db, l’import della configurazione e così via. Ma sarà tutto automatico, non dovremo più farlo noi a mano e saremo liberi di aggiungere tutta una serie di altre attività come il controllo della qualità del codice, test automatici di vario tipo (end-2-end, di regressione visuale, ecc). Più saremo bravi in queste operazioni, ovvero a coprire di test la nostra applicazione e a far girare i test nei momenti più adeguati, più potremo stare tranquilli, dato che la pipeline, quando si imbatterà in un errore, si bloccherà, evitandoci di andare in produzione con qualcosa che non è come vorremmo (ed evitandoci quindi un rollback). Una volta configurate le nostre pipeline dobbiamo infine definire il nostro provider cloud e quali servizi utilizzare. Come concetto generale, possiamo dire che avremo uno o più container che dovremo orchestrare, e possiamo indirizzarci sia verso soluzioni custom, sia soluzioni managed che offrono già molto out of the box.
POTREBBE INTERESSARTI ANCHE: Qual è il miglior Headless CMS? I vantaggi di Drupal
Kubernetes è oggi lo standard de-facto, e non a torto dato che offre una potenza di fuoco enorme e permette di controllare tutti i servizi con estrema precisione e tantissima flessibilità. Inoltre, è open source, e possiamo installarlo dove vogliamo (sì, anche in locale). Per queste sue caratteristiche, è però uno strumento molto complesso, che richiede competenze specifiche.
Possiamo prendere in considerazione soluzioni intermedie managed offerte dai vendor, come AWS ECS, che ovviamente implicano un grado di lock-in maggiore, ma sono più semplici e più vicine a strumenti che già conosciamo.
Troviamo infine soluzioni estremamente semplici che si possono adattare a casistiche di siti che non richiedono particolari interventi (Cloud Run su GCP è una di queste).
E se servisse andare su più vendor? Per esempio, potremmo volere istanze su AWS per Europa e Stati Uniti, e un'istanza in Cina. Possiamo senza alcun problema deployare contemporaneamente su più vendor perché l’architettura di base, Drupal, è sempre la medesima.
Ultimo step, imprescindibile, è il monitoraggio. Sappiamo bene che per uno sviluppatore il lavoro non finisce quando un sito o un prodotto digitale più in generale vanno online: il monitoring è importante, i dati da raccogliere sono numerosissimi. Oltre i log ai quali è stato accennato precedentemente, dobbiamo tenere sotto controllo l’utilizzo delle risorse, perché è attivo l’autoscaling, ma è necessario anche capire quanto scalino effettivamente, e dobbiamo raccogliere lo status report di Drupal, senza entrare nell’istanza di Drupal. A fronte di una tale pletora di dati, si avrà bisogno di strumenti per gestirli, organizzarli e filtrarli. Ogni vendor ne mette a disposizione alcuni, senza contare servizi esterni che possono essere configurati previa identificazione delle metriche giuste: senza le idee chiare in questo senso, si rischia di essere sommersi di log e dati inutilmente.
In tutto questo scenario, quanto Drupal risulta “collaborativo”? Diciamo che da Drupal 8 in poi, portarsi in Cloud in ottica Cloud Native è piuttosto facile. La configurazione è esportabile su file, quindi può essere versionata e far parte della build, D8 utilizza Composer per gestire le dipendenze (non conviene utilizzare Drupal senza Composer, questo il nostro accorato consiglio). Ad oggi Drupal rispetta la maggior parte degli standard PHP e può essere considerato a tutti gli effetti un framework moderno, basato in gran parte su componenti di Symfony.
Ciò detto, che non ci si disperi davanti a un sito Drupal 7. Richiederà sicuramente uno sforzo maggiore, perché sarà necessario sopperire a tutte quelle funzionalità che soltando dall’8 abbiamo a disposizione, ma rimane comunque una strada percorribile. Non dobbiamo rinunciare per forza a un D7 cloud native, soltanto mettere in conto un effort maggiore.
Non hai voglia di leggere tutto il testo? Il video qui sotto è la valida alternativa all'articolo.