Applicazioni a micro-servizi e cloud-native, quali utilizzare e come

I micro-servizi vanno nella direzione dell’agilità e del continuous delivery (modello di produzione a flusso ininterrotto), primo passo del cloud journey che vede come step successivo l’automazione grazie a strumenti come Puppet, Chef, Ansible, Kubernetes e prodotti come Red Hat Openshift

Pubblicato il 17 Apr 2020

Alessandro Grossi

senior project manager

micro applicazioni

Si parla da anni di architetture a micro-servizi e cloud-native, ma quali sono i concetti alla base dei nuovi paradigmi e quali gli strumenti utili e quali i prodotti necessari a quello che in gergo si chiama“cloud journey”?

Applicazioni cloud-ready

Lo sviluppo cloud-native è importante perché assicura la riduzione del cosiddetto “time to market” (il tempo che intercorre fra la progettazione e la commercializzazione del prodotto sul mercato). Un’applicazione cloud-ready a micro-servizi è ottimizzata e consente di soddisfare le richieste dei clienti perché supporta la scalabilità dinamica.

I micro-servizi vanno nella direzione dell’agilità e del “continuous delivery” (modello di produzione a flusso ininterrotto) ma sono solo il primo passo del cloud journey che vede come step successivo l’automazione grazie a strumenti come Puppet, Chef, Ansible, Kubernetes e prodotti come Red Hat Openshift.

Nel modello di gestione del codice sorgente detto a trunk esiste un solo branch di riferimento nel repository (chiamato master) il che rende questo processo più semplice rispetto al classico modello git-flow. Il software presente sul master deve poter essere sempre rilasciabile, quindi deve avere requisiti di qualità. Questo consente, fra l’altro, l’applicazione di suite di test automatici (uno dei capisaldi del DevOps).

Cos’è Waterfall Scrum e perché non andrebbe utilizzato

Un esempio poco virtuoso ma molto diffuso è chiamato da alcuni Water (-Scrum-) Fall per mettere in risalto l’incoerenza dell’approccio usato in taluni contesti dove all’uso degli Sprint e delle ceremonies Scrum si accompagna il classico delivery model del Waterfall, poco efficace se devo aspettare ad esempio tre sprint (dodici settimane?) per avere il mio codice in ambiente di QA e magari altrettanto per passare attraverso i gate del team di Integration, UAT , Staging e finalmente  Produzione.

Usiamo un team più piccolo riduciamo l’effort dello sviluppo e le ceremonies, automatizziamo i test, implementiamo i Container e arriviamo in metà del tempo in Produzione, magari applicando strategie di zero-downtime deployment (quindi metodi di deployment che non contemplano “fermi” del servizio).

Uno dei testi più citati in questo contesto è “The Phoenix Project” con i suoi (al tempo, straordinari) dieci deploy al giorno, ma le cose da allora vanno veloci: oggi siamo a cinquanta deploy al giorno. Come si gestiscono?

Pensiamo a come sono progettate ancora oggi le applicazioni di molte grandi aziende, banche o pubbliche amministrazioni. Il software non può più essere costruito come un “monolite”, ma invece come un insieme di applicazioni che possano essere deployate in maniera coordinata, ma indipendente.

Microservizi containerizzati

Con i microservizi la musica cambia: intanto ci sono team separati per micro-servizio. Ci si organizza in base alle capability di business, con deployment separati e indipendenti, il focus è sulle Api e non sul progetto. Governance e gestione del dato sono necessariamente decentralizzati e chiaramente è critico avere zero-downtime. Strumenti come Kubernetes, o meglio Openshift, sono utili per implementare questo tipo di approccio. E naturalmente occorre ripensare i database, il layer di persistenza.

Microservizi quindi, ma con quale tecnologia? Spring Boot, Vert.x, Node.js o magari Go? Lo scrivo in PHP, Python o Ruby? Ogni endpoint ha le sue caratteristiche peculiari, tuttavia sviluppare un Rest endpoint (che espone il nostro semplice servizio tramite un Ip pubblico ad esempio) è piuttosto banale. Un micro-servizio API è poi invocabile in modo diverso a seconda della tecnologia usata: Java EE per esempio è invocabile su Http/Https. Spring offre Rest Template (MVC), Vert.X offre Web Router., Node.js per esempio Express.

Mettiamo quindi di aver sviluppato il nostro microservizio, cosa succede dopo? Ci occorrono i container, in grado di disaccoppiare le applicazioni dal layer di infrastruttura. Una container image è un software pronto all’uso completo di codice e runtime necessario all’esecuzione. I container sono immutabili: se sta girando, non possiamo modificarne il codice ma possiamo fare modifiche all’applicazione containerizzata, fare di nuovo build del container ri-creandolo a partire dall’immagine aggiornata.

Un semplice micro-servizio può girare in un Pod (unità basilare di esecuzione che può essere immaginata come una virtual machine). Un semplice docker container può essere gestito da Kubernetes, che svolge il ruolo di orchestratore.

Quindi abbiamo un pod e abbiamo il nostro servizio esposto. Non serve sapere in quale parte del nostro server sta “girando”. Grazie a Kubernetes, scheduliamo il run dei container sull’intero cluster e possiamo, all’ occorrenza, far scalare il nostro micro-servizio. Se ho tre pod, ad esempio, posso bilanciare facilmente il servizio. Quindi per esempio, tre JVM, tre differenti componenti vertex.

Immaginiamo di aggiornare il codice sorgente, ora. Modifichiamo il codice, rilanciamo il Docker Build e andiamo a sostituire il codice senza “downtime”, grazie a Kubernetes. Lato DevOps è possibile implementare pipeline automatizzate grazie a un Jenkinsfile, che interagisce con le Api Kubernetes. Dallo Sviluppo all’ambiente di QA, allo Staging, fino alla produzione. Si tratta di un workflow che parte dal checkout sull’ SCM e attraverso una build Maven dell’immagine arriva ai test automatici. L’immagine è poi promossa in QA ed eventualmente approvata in Produzione. Occorrono per far questo una toolchain CI/CD e tecniche avanzate di deployment e rollout delle applicazioni (Canary o Blue/Green Deployment e strategie di rollout basate sull’AB Testing).

Cos’è Red Hat Openshift e come si utilizza

Lo step successivo è gestire i container attraverso una toolchain di CI/CD che li coinvolga in un workflow come si fa col software delle applicazioni. Usare Jenkins e Jenkinsfile da circa un anno non è più l’unica strada: si sta infatti diffondendo l’uso di Tekton, un framework open source per la creazione di pipeline CI/CD meno oneroso per i cluster che usa il concetto di custom resource definition. In Tekton, in pratica le funzioni vemgono buildate come container, nella pipeline Tekton c’è un insieme di oggetti chiamati “task” che sono di fatto Pod (contenenti uno o più container).

Red Hat Openshift, platform as a service per applicazioni cloud, rende semplice lo sviluppo, il deploy e la scalabilità delle applicazioni grazie all’uso di tutti i concetti visti finora. Red Hat Openshift ha proprio il vantaggio di definire un workflow di CI/CD completo, che parte dal codice sorgente dell’applicazione e dalle immagini per giungere al deploy delle applicazioni containerizzate.

Per chi viene da Kubernetes, l’approccio naturale sarebbe avviare il container Jenkins con la Docker dell’host montata all’interno, ma così facendo esporremmo il container e il Docker socket a rischi inutili solo per buildare un’immagine.

Con Openshift usiamo un approccio più sicuro. L’approccio diventa dichiarativo (grazie ad una risorsa chiamata BuildConfig e un layer di astrazione per le immagini dei container (chiamata appunto ImageStream). Aggiungiamo un minimo di automazione con un semplice file yaml (lo stesso linguaggio in cui sono scritti i playbook Ansible) e abbiamo un workflow completamente automatizzato. Vediamo un workflow di esempio ma tratto dal mondo reale:

  1. La nuova immagine del contenitore viene importata dal registro esterno (ad esempio come importazione jdk8 su ImageStream)
  2. ImageStream avvia una nuova build di un’app definita nel nostro file”.yaml”
  3. Build recupera il codice dell’app dal repository git, crea una nuova immagine del contenitore e la pubblica nell’ ImageStream dell’app
  4. La nuova immagine del contenitore viene inserita nel registro interno e ImageStreamTag fa riferimento alle modifiche fatte e punta a quella nuova immagine
  5. Questa azione avvia una nuova distribuzione su un oggetto DeploymentConfig

Un’installazione Openshift di default suggerita consta di tre nodi master e dai due ai tre nodi worker. Una volta installato Openshift 4, è possibile definire nuovi nodi worker su cui agganciare, per esempio, la parte di Storage.

In Red Hat Openshift 4 abbiamo un operatore per fare ogni cosa. La custom resource è un oggetto API molto utilizzato anche qui. Grazie ad un operator posso installare 3Scale (API Management), Red Hat  Openshift Service Mesh (che offre un metodo unificato per la connessione, la gestione e il monitoraggio delle applicazioni basate su micro-servizi), Istio (piattaforma open source che consente di controllare il modo in cui i micro-servizi condividono tra loro i dati) o Red Hat® Quay, un registro di immagini di container che  oltre a offrire capacità di storage, consente di creare, distribuire ed eseguire il deployment di container.

Valuta la qualità di questo articolo

La tua opinione è importante per noi!

Articoli correlati

Articolo 1 di 2