Contatta il reparto vendite 800 13.40.41 | Richiedi il Supporto Partner EN flag

KNOWLEDGE BASE

Knowledge Base

Vai al Video

Docker e Kubernetes per sistemisti e professionisti IT

Negli ambienti virtualizzati ed ancor più sul Cloud si ricorre da tempo alla tecnologia dei container, perché consente di isolare le risorse all’interno della macchina fisica semplificando nel contempo la gestione. I container (letteralmente, contenitori...) sono qualcosa di radicato nell’IT perché esistevano già con Linux e da qualche tempo vengono riproposti da gestori come Docker, di cui tratteremo in questo tutorial in sinergia con Kubernetes.

Docker è un progetto open-source nato per automatizzare il deployment di applicazioni all'interno di contenitori (che in Docker si chiamano container) software, fornendo un elevato livello di astrazione grazie alla virtualizzazione a livello di sistema operativo concesso da Linux.

La grande diffusione di Docker e le prerogative di tale soluzione hanno fatto sì che la relativa tecnologia venisse estesa anche all’ambiente Windows.

Docker utilizza le funzionalità di isolamento delle risorse del kernel Linux, come cgroup e namespace per consentire a container indipendenti di coesistere sulla stessa istanza di Linux, evitando l'installazione e la manutenzione di una macchina virtuale (VM): i namespace del kernel Linux isolano ciò che l'applicazione può vedere dell'ambiente operativo, incluso l'albero dei processi, la rete, gli ID utente e i file system montati, mentre i cgroup forniscono l'isolamento delle risorse, inclusa la CPU, la memoria, i dispositivi di I/O a blocchi e la rete.

Docker accede alle funzionalità di virtualizzazione del kernel Linux o direttamente utilizzando la libreria libcontainer, che è disponibile da Docker 0.9, o indirettamente attraverso libvirt, LXC o systemd-nspawn. I container condividono lo stesso kernel, ma ciascuno di essi può dover utilizzare una certa quantità di risorse, come la CPU, la memoria e l'I/O.

Dal supporto fisico alla virtualizzazione

Una volta, vale a dire 10-15 anni fa, per installare delle applicazioni si partiva da una macchina fisica e su di essa si installava il sistema operativo in base alla richiesta del cliente e all’applicativo, quindi si installava l'applicativo stesso. La situazione era quella schematizzata nell’immagine seguente.

Per comprendere cosa sono i container e quali vantaggi xcomportano occorre considerare che oggi siamo passati dalle applicazioni “monolitiche” nelle quali era difficile eseguire delle modifiche e per far “girare” le quali servivano server molto potenti e data-center, ad applicazioni che permettono di eseguire i servizi liberamente con facilità e rapidità di gestione delle modifiche e degli aggiornamenti, su piccoli server o dispositivi decentrati e portatili. Questo significa che oggi esistono applicazioni composte dall’esecuzione di micro-servizi poco legati tra loro. 

Rispetto alle applicazioni monolitiche, nelle quali anche piccole modifiche al codice richiedono la ricompilazione e riesecuzione del test, del debug e del deployment, le applicazioni possono andare in crash per il blocco di una delle loro parti e sono difficili da scalare, adottando la tecnica dei micro-servizi è possibile ricondurre le applicazioni ad operazioni separate e isolate tra loro, quindi il failure di una non influisce sulle altre e si può rendere l’applicazione scalabile.

Con la virtualizzazione siamo passati dall’avere un un server fisico per applicazione all’utilizzare lo stesso server fisico, probabilmente un po' più performante, sul quale si possono eseguire più applicazioni isolate tra loro e più sistemi operativi host gestiti da un hypervisor; virtualizzazione significa passare dalla macchina fisica alle macchine virtuali (VM) e quindi a poter eseguire più di queste su un’unica macchina fisica.

Banner

Esistono varie soluzioni per la virtualizzazione, ma tutte si riconducono allo schema strutturale proposto nell’immagine seguente, dove Infrastructure è l’hardware fisico (server locale o server Cloud) sul quale si va a installare l’hypervisor, che corrisponde all’ambiente di virtualizzazione (VMware, per esempio) il quale a sua volta ospita più sistemi operativi Guest.

A loro volta, questi sistemi operativi ospitano le applicazioni. Come vedete, in una macchina fisica possono andare in esecuzione più sistemi operativi e su ciascuno di essi più applicazioni.

La virtualizzazione è qualcosa che ha preso molto piede e rappresenta, per la gran parte delle applicazioni e delle infrastrutture, la tecnologia del futuro; si applica su molte piattaforme e a sistemi operativi di vario genere.

L’adozione delle macchine virtuali apporta benefici e migliora la gestione delle risorse, perché una macchina fisica può essere divisa in più macchine virtuali e il sistema nel complesso diventa pià scalabile.

Però l’adozione delle macchine virtuali non è sempre conveniente, perché ogni Virtual Machine richiede un’allocazione di CPU, una memoria di storage e una RAM dedicate, nonché un sistema operativo guest.

Questo implice che più macchine virtuali si mettono in esecuzione, più risorse sono richieste sulla macchina fisica; inoltre la portabilità dell'applicazione, sebbene sia facilitata, non è garantita.

I container vanno a mitigare queste limitazioni perché sono come delle piccole macchine virtuali isolate e dedicate,

Utilità dei container

Il container nasce dalla considerazione che non ha senso virtualizzare un’intera macchina, quando si può virtualizzare solamente una piccola parte di essa, quindi i container:

  • standardizzano il deployment del software;
  • consentono l’isolamento delle applicazioni;
  • condividono lo stesso kernel del sistema operativo;

Il container permette di impacchettare l’applicazione con tutto ciò di cui necessita: le librerie, le dipendenze, gli strumenti di sistema e tutto quello che si può installare in un server. L’impacchettamento dà allo sviluppatore la certezza che l’applicazione venga eseguita in qualsiasi server, giacché prescinde dai requisiti di sistema hardware e di sistema operativo, perché nel container si trova tutto l’occorrente all’esecuzione.

Il concetto è riassunto nell’immagine seguente.

Banner

Naturalmente un container non è una macchina virtuale e per rendere il concetto più chiaro diamo uno sguardo all’immagine seguente, la quale chematizza a sinistra le macchine virtuali e a destra i container.

La macchina virtuale utilizza uno stack dove alla base c’è l’hardware (Infrastructure) sopra di esso abbiamo l’Hypervisor (ipervisore) che serve a far eseguire le macchine virtuali. Sopra abbiamo il complesso della macchina virtuale, ossia il sistema operativo guest (quello della macchina virtuale), sopra i file binari e le librerie occorrenti all’esecuzione e in cima l’applicazione. Ciò implica che tutte le macchine virtuali in esecuzione fanno uso di un kernel separato e unico.

Guardiamo adesso lo stack del container, che ha i primi due livelli uguali ma nel terzo abbiamo il motore Docker che avvia i container; sopra abbiamo ancora librerie e binari necessari all’esecuzione delle applicazioni e le applicazioni stesse. La differenza sostanziale è che i container, a differenza delle VM, condividono il kernel.

Riassumendo, le VM virtualizzano l’hardware, occupano molto più spazio di storage e risorse e risultano meno portabili e più lente al boot.

Invece i container virtualizzano il sistema operativo, occupano meno spazio (un’immagine di un container solitamente occupa pocchi MB) e sono più portatili ed efficienti. L’efficienza è dovuta al fatto che i container vengono gestiti come processi isolati tra loro all’interno del sistema operativo host; altro vantaggio è che i container non sono vincolati ad alcuna infrastruttura hardware.  

Il discorso sullo spazio occupato e sulle risorse richieste non è rilevante tanto in sé, ma rapportato alle performance: se dobbiamo creare per esempio 10  macchine virtuali che occupano ognuna 5 GB è ovvio che per logica naturale queste macchine hanno un tempo di risposta per essere create e operative molto superiore rispetto a 10 container che pesano qualche decina di MB ciascuno. Far partire un container è molto più semplice e immediato che avviare ua macchina virtuale.

I container costituiscono un’alternativa alla virtualizzazione e presentano un comportamento analogo a quello delle VM relativamente all’isolamento delle risorse del sistema e ai benefici dell’assegnazione delle risorse; tuttavia, diversamente dalle VM, i container sfruttano un altro approccio che consente:

  • deployment semplificato, perché impacchettando un’applicazione in un singolo componente si può distribuire qualsiasi applicazione senza preoccuparsi della configurazione dell’ambiente dove verrà eseguita;
  • rapida disponibilità, perché virtualizzando ed astraendo solo il sistema operativo e le componenti necessarie all’esecuzione dell’applicazione, invece che l’intera macchina, l’intero package si avvia più rapidamente che una VM;
  • controllo più profondo, perché i container consentono di suddividere ulteriormente le risorse computazionali in microservizi, riuscendo a controllare meglio l’eseguibilità delle applicazioni.

È possibile far coesistere tantissimi container su un server per avere a portata di mano un ambiente di deployment o test adatto a ciascuna applicazione in sviluppo; inoltre le attività di testing in cloud con i container diventano meno costose, perché se si “testa” un’applicazione su un server cloud pubblico si paga in funzione del tempo di utilizzo delle risorse computazionali, quindi siccome con un container si utilizzano sempre le stesse risorse computazionali il costo scende.

Un importante vantaggio offerto dai container è la portabilità. Inoltre il formato consente l’esecuzione su diversi host perché con la standardizzazione dei container, i workload possono essere facilmente spostati dove vengono eseguiti, evitando anche i lock-in dovuti alle peculiarità delle piattaforme dei singoli provider.

Docker e i suoi container

Docker è una tecnologia basata sui container di Linux e può utilizzare diverse interfacce per accedere alle funzionalità di virtualizzazione del kernel Linux e implementa API di alto livello, allo scopo di gestire container che eseguono processi in ambienti isolati. Componente fondamentale per l’esistenza di Docker sono i cgroup, capaci di creare un contesto di esecuzione delle applicazioni isolato, con un alto livello di astrazione, tanto da creare una sorta di sistema operativo semplificato e virtualizzato.

Docker ha sviluppato un proprio formato di “conteinerizzazione” interoperabile, capace di pacchettizzare le applicazioni ed effettuarne il deploy in qualsiasi ambiente di esecuzione, senza doversi preoccupare delle condizioni di eseguibilità.

Docker è una tecnologia che ci permette di creare e distribuire, nonché testare ed eseguire applicazioni in modo facile e veloce.

Un container di Docker è un’unità standard di software che impacchetta il codice e tutte le sue dipendenze in modo che l’applicazione venga eseguita a prescindere dall’ambiente e in maniera rapida e affidabile.

Nato per le principali distribuzioni Linux, oggi Docker può essere eseguito in Windows Server (nella versione 2016 viene installato per impostazione predefinita) e in ambiente Mac; sul piano delle infrastrutture, trova impiego nei Data Center e nel Cloud. Ad esempio la maggior parte dei Cloud provider ha funzioni dedicate a microservizi e le stesse si implementano in molti Data Center.

Stabilito che cosa sono Docker e i container, è opportuno spiegare alcuni termini utili a comprendere come funziona Docker: partiamo dall’Immagine, che rappresenta la base di un container Docker e contiene tutte le istruzioni che faranno nascere il container (ad esempio da dove deve partire, le dipendenze e i pacchetti, le configurazioni ecc.). L'immagine può essere paragonata a un template di Vmware, dove creiamo una macchina, poi installiamo il sistema operativo e tutto quello che ci serve, quindi con questo template possiamo clonare altre macchine.

Il container è l'immagine Docker quando è in esecuzione, ossia l'unità standard dei servizi; ogni volta che lanciamo un container diciamo a Docker di prendere una data immagine e costruire un container partendo da essa. Praticamente un container docker parte da un file che viene chiamato Docker file, ossia l’immagine e dall'immagine poi facciamo nascere il container. Dall’immagine possiamo far partire uno, due o decine e centinaia di container, che poi condivideranno a questo punto il kernel e tutte le dipendenze del sistema operativo ecc. L'unica compatibilità che si richiede è che le versioni siano almeno conseguenti.

L’engine è il software che esegue i comandi per i container e può essere considerato come qualcosa di simile all’hypervisor delle macchine virtuali.

Infine il Registry è il registro che memorizza, distribuisce e gestisce le immagini di

Architettura e funzionamento di Docker

Passiamo adesso al funzionamento  di Docker, che possiamo schematizzare nell’immagine seguente dove è proposta l’architettura del sistema

Come vedete, a sinistra abbiamo la sorgente, ossia il codice in locale (o su client) collocato nel proprio repository o sulla stessa macchina locale. Dentro il codice abbiamo il Dockerfile, che è quello che contiene tutte le istruzioni su come deve funzionare il container una volta che sarà in esecuzione. Quindi la parte a sinistra è il client che contiene le direttive (Docker build, Docker Pull e Docker run) che mandiamo al demone di Docker (che opera nella parte cetrale dell’architettura, ossia nel Docker Host) il quale, attraverso l'utilizzo delle immagini chiamate, crea i container. L'immagine la possiamo creare noi (quindi possiamo definire noi che cosa vogliamo che il container faccia) o possiamo decidere di attingere al registry.

Quando si avvia la costruzione (Build) di un container, l’engine di Docker che gira sul sistema operativo host della macchina prende l’immagine e con essa costruisce il container corrispondente (per esempio il Container A viene costruito dall’engine a partire dal file immagine Dockerfile A).

Ma è anche possibile fare un push al Docker registry, che memorizza e immagazzina le immagini Docker. Da qui è possibile fare diverse cose, come ricercare (Search) le immagini contenute nel registro, ma anche fare il pull dell’immagine del container ottenuto dal Build su un altro nodo, che può essere un server un cluster su VMware o qualsiasi architettura che abbia accesso al Docker registry.

Impartendo il comando Docker Run il container verrà eseguito.

Riguardo al Registry, esistono oggi tante piattaforme che offrono servizi di Registry, il che ci permette, ovunque noi siamo e da qualsiasi piattaforma operiamo, di chiamare l'esecuzione di un container scaricarci l'immagine.

Le immagini cui si può attingere non sono necessariamente quelle depositate da noi nel Registry, ma anche immagini pubbliche, ufficiali ecc. Il consiglio è di cercare di utilizzare il più possibile le immagini ufficiali.

Demo – Web Server Up e Running

Vediamo a questo punto un esempio pratico ipotizzando uno scenario nel quale abbiamo bisogno di avere un Web Server funzionante, quindi Up and Running.

Se avessimo dovuto fare questo in modo tradizionale avremmo utilizzato un server fisico dove deployare una nuova applicazione, installato in esso il sistema operativo che più ci piaceva, installato anche l'aggiornamento del sistema operativo e delle eventuali patch di sicurezza, nonché le dipendenze, poi configurato il server (il Virtual Host) che risponde al nostro sito ecc.

Qualcosa di simile è il discorso se intendiamo utuilizzare una macchina virtuale: sicuramente ci risparmiamo tutta la parte di server fisico, però dobbiamo creare un template che ci “tiri su” il sistema operativo che vogliamo, dobbiamo aggiornare il sistema operativo e installare eventualmente delle patch di sicurezza, installare e configurare il virtual host e così via. Anche qui il tempo richiesto è qualche ora.

Con Docker tutto questo lavoro si riduce a impartire un comando:

docker run –d –p 80:80 nginx

che avvia il container, a partire dall’immagine creata in precedenza.

Banner

Andiamo a vedere come si realizza la cosa, imponendo di avere Docker installato nel proprio sistema; allo scopo suggeriamo di andare sulla documentazione ufficiale di Docker per ogni dettaglio. Inoltre per chi ha Mac e Windows esiste un client che si chiama Docker Destop da cui operare.

Comunque sia, supponiamo di aver già installato e aperto il client Docker e andiamo a “tirare su” il nostro Web Server; allo scopo impartiamo il comando:

docker run –d –p 80:80 nginx

Quindi impartiamo il comando run lato client che mandiamo al demone affinché dall’immagine crei il container; l’opzione -d manda il container in background, -p serve per esportare la porta 80 e poi ngnix che avvia il servizo. Infatti ngnix è un Web Server simile ad Apache.

In pratica con tale comando diciamo a Docker di andare a leggere il repository ufficiale di Docker Registry e se ngnix non c'è nella macchina locale lo scarica. Se non specifichiamo un prefisso indicando il repository da dove lo deve andare a scaricare, Docker automaticamente va a cercare sul repository ufficiale (DockerHub).

Come potete vedere impartendo il comando:

docker search ngnix

l’interfaccia utente (il nostro client) elenca tutti gli nginx che ci sono (immagine seguente).

Allora se a questo punto impartiamo il comando

docker ps

che mostra i processi, vediamo che il nostro container contraddistinto dal CONTAINER ID e costruito a partire dall’immagine (IMAGE) ngnix con il comando specificato nella riga corrispondente, è stato creato e messo Up da circa un minuto, associato alla porta 80 e con indirizzo IP 0.0.0.0.

Quindi se questo Web Server avesse un IP pubblico sarebbe già attivo perché sulla porta 80 risponderebbe.

Possiamo fare una cosa analoga a quella già vista con un Web Server httpd, che è la  versione ufficiale di Apache, impartendo il comando:

docker run –d –p 81:80 httpd

allo scopo di creare e avviare un server Apache, appunto, ma istanziando su una porta differente (81).

In questo caso il tempo impiegato è inferiore. Notate che il tempo si può verificare impartendo il comando:

time docker run –d –p 81:80 httpd

ovvero, se avete già creato il Web Server httpd sulla porta 81, creando un nuovo container sulla porta 82 per evitare conflitti e impartendo il comando:

time docker run –d –p 81:80 httpd

Come mostra l’immagine seguente, abbiamo un tempo di 1,217 secondi.

Potete utilizzare lo stesso comando per verificare i tempi di creazione dei Web Server di altro tipo, ma comunque quello che appare evidente è come si possa mettere Up un server del genere in pochissimo tempo con Docker.

Kubernetes e i suoi cluster 

Abbiamo quindi visto cosa sono i container di Docker e quali vantaggi portano, nonché com’è facile crearne un’infinità, però a questo punto viene spontaneo domandarsi come facciamo a gestire e orchestrare tantissimi container, magari in varie infrastrutture? E come si può scalare e distribuire un’applicazione o creare un sistema completo, affidabile, scalabile e distribuito?

La risposta a queste domande si trova in Kubernetes, perché tutto ciò può essere ottenuto realizzando un cluster Kubernetes, che contiene i container.

Partiamo da una considerazione: se un certo container lo creiamo su un singolo server,  potrebbe non essere adatto alla produzione; abbiamo bisogno che mi se un container va giù sia possibile deployare lo stesso container su un altro server che sia Up. Per fare tutto ciò ci serve un cluster Kubernetes.

Kubernetes è ormai lo standard a livello di cluster di container, seppure ci sono e ci siano state altre soluzioni paragonabili.

Kubernetes è un orchestratore open source per la gestione e distribuzione di applicazioni a container. È stato sviluppato originariamente da Google, che poi l'ha rilasciato open source e da lì è seguita una community enorme di contributor e di fatto è uno dei progetti open source più cresciuto negli ultimi anni.

L’immagine seguente propone i componenti di un generico cluster Kubernetes: A destra abbiamo la parte del Control plane e a sinistra quella dei Node; possiamo chiamare Master il Control Plane e Worker i nodi.

Banner

L’etcd visibile nella parte sinistra del disegno è un database distribuito basato sul File System e potrebbe utilizzare anche della RAM per velocizzare; il Kube-controller manager si incarica analizzare lo stato del Cluster e rispondere a eventuali cambiamenti.

A sinistra in ogni caso abbiamo la parte di gestione, che sono sempre container però sono sempre quelli, cioè non cambiano.

Diciamo che Kubernertes ha utilizzato la tecnologia a container ma avrebbe potuto sviluppare quella parte in maniera tradizionale.

Comunque il Control Plane serve per l’orchestrazione dei worker (dei nodi) ed è un ambiente che potrebbe essere il parallelo di VMware con vSphere, NSX e tutti gli altri sistemi che utilizza poi per far funzionare le VM.

Il kube scheduler ha una funzione puramente di check-in e il kube API server è la parte diciamo fondamentale di tutto, che si incarica di comunicare con i nodi.

Il kube controller manager e il Cloud controller manager sono le due entità che si occupa di gestire il cluster: il primo governa la parte locale e i nodi, mentre il secondo provvede al management e comunicazione con il Cloud se esistono delle risorte al di fuori del cluster.

Componenti del cluster Kubernetes per Produzione

Quando il cluster è in produzione è strutturato più o meno come mostrato nell’immagine seguente, cioè ha le stesse componenti appena descritte, con l'unica differenza che  la parte Master è replicata e ciò principalmente è legato al database.

Vediamo i soliti worker (nodi) dove facciamo girare i container che puntano o comunque sia che vengono orchestrati da più kube controller manager; notate che tale elemento può essere anche uno, tuttavia in un ambiente tipoco conviene averne almeno 2, anzi, per l’esattezza uno o tre, perché il cluster ha bisogno di avere sempre un leader.

 Nel disegno vedete un bilanciatore di carico che permette che i worker abbiamo un unico indirizzo cui fare riferimento; il bilanciatore di carico serve perché nel momento in cui abbiamo più di un nodo (quindi almeno tre) i worker che devono comunicare con l’API server o hanno tutti e tre l’IP dei control-plane o la prassi migliore è quella di mettere un balancer layer 4 al di sopra quindi che comunichi coi i worker node e l’API Server.

Vediamo ora alcuni concetti fondamentali di Kubernetes:

  • Pod; è l’entità più piccola, corrispondente a un gruppo di uno o più container che condividono la rete, lo storage e le direttive per eseguire i container;
  • Service; fornisce load balancing, naming e discovery e permette di esporre un'applicazione in esecuzione su un set di pod come servizio di rete;
  • Namespace; è un cluster virtuale all’interno del cluster fisico e fornisce isolamento tra i container e controllo degli accessi;
  • Deployment; fornisce aggiornamenti dichiarativi e controlla lo stato attuale dell’applicazione con quello desiderato ed esegue il deploy in base al risultato;
  • kubectl; è un tool da riga di comando che permette di controllare i cluster Kubernetes.

Kubectl è essenzialmente il client che utilizziamo (la command line interface) per interagire con l’API di Kubernetes.

Kubernetes on premise: versioni disponibili

Per quanto riguarda la versione on premise, abbiamo diverse soluzioni che abbiamo voluto dividere per destinazione, tra locale-sviluppo-piccoli cluster e produzione. Per quanto riguarda la categoria locale, sviluppo e realizzazione di piccoli cluster troviamo:

  • Minikube;
  • kind;
  • K3S;
  • Docker Desktop;
  • Microk8s;

Per applicazioni più consistenti come la realizzazione di cluster da produzione abbiamo:

  • Kubeadm;
  • kops;

Se utilizzate Mac o Windows consigliamo di utilizzare Docker Desktop perché semplicemente non dovete installare null’altro, in quanto esso ha la possibilità di abilitare Kubernetes con un clic in locale

Minikube è rilasciato direttamente da Kubernetes e anche questo “tira su” una macchina virtuale sulla nostra postazione e installa tutti i componenti. Vedremo tra breve come utilizzarlo.

Invece per quanto riguarda la produzione abbiamo che diverse soluzioni interessanti, tra le quali il consiglio è di approfondire l’utilizzo di Kubeadm, perché oltre ad essere molto versatile e ampiamente utilizzato, è la base di partenza per soluzioni utilizzate ad esempio dai maggiori Cloud Provider, come ad esempio Kops, che è una soluzione utilizzata per fare il deploy di cluster Kubernetes su Cloud Provider e che in questo momento supporta AWS e Google. Azure di Microsoft si appoggia ad AKS, IBM Cloud a IBM CKS, Digital Ocean a DOKS e recentemente Google Cloud a GKS. Restando in tema di cloud, Amazon ha un suo sistema chiamato EKS.

Rancher è a un livello di astrazione ancora più alto e semplifica alcune operazioni e di molto; Rancher aveva una sua implementazione come orchestratore di container Docker, nella versione 1.6, poi dalla 2.0, visto che Kubernetes ha preso il sopravvento, ha mantenuto la parte di orchestrazione che semplifica molto il lavoro ma si appoggia su Kubernetes. Si può definire un orchestratore dell’orchestratore.

Infine anche VMware sta esplorando il terreno degli orchestratori per cluster.

Cluster Kubernetes con Minikube

Allora, vediamo un esempio pratico di implementazione Web Server up and running ma fatto questa volta utilizzando cluster Kubernetes e premettendo che abbiamo due possibilità per farlo: la prima è utilizzare delle iterazioni, ovvero dei comandi imperativi, intendendo con ciò che indichiamo a Kubernetes  esattamente che cosa deve fare, passandogli una riga di comando. Questo è un metodo poco consigliabile e ostico, magari più utilizzato sui cluster, che come inconveniente presenta la dificoltà di avere il controllo di ciò che fa il cluster. Un esempio di costruzione di Web Server e messa in esercizio tramite riga di comando è quello proposto qui di seguito:

kubectl create deployment myApp –image=nginx:1.18.0

kubectl expose deployment myApp –type=NodePort –port=8080

dove il primo comando “tira su” il server e il secondo lo manda in running.

Banner

La seconda possibilità o metodologia è un po' più lunga da implementare ma più pratica, ed è quella dichiarativa: dichiarativa vuol dire che dichiariamo in un file che cosa vogliamo che Kubernetes faccia; nel momento in cui lavoriamo in un modo dichiarativo, quindi creiamo dei file contenenti quello che abbiamo deployato, operazioni come la migrazione diventano rapide e sicure, perché se succede qualcosa sul cluster possiamo correggere eventuali errori.

La modalità dichiarativa prevede la creazione di due file .yaml che sono uno di deployment (deployment.yaml) ed uno di definizione dei servizi (service.yaml). Questo è un esempio di listato di file deployment.yaml e definisce come creare e mettere up il Web Server:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 5
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. template:
  13. metadata:
  14. labels:
  15. app: nginx
  16. spec:
  17. containers:
  18. - name: nginx
  19. image: nginx:1.18.0
  20. ports:
  21. - containerPort: 80

Di seguito proponiamo invece il listato di un tipico file service.yaml, che manda in running il server:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: service-nginx
  5. spec:
  6. type: NodePort
  7. selector:
  8. app: nginx
  9. ports:
  10. - port: 80
  11. targetPort: 80
  12. nodePort: 30000

Entrambi realizzano il Web Server d’esempio, ovvero il primo file implementa un deployment con cinque repliche e specifica di utilizzare l’immagine ngnix versione 1.18.0  sulla porta 80; come visto prima, questo crea due port: una per definizione non permette di comunicare dall'esterno e anche all'interno del cluster, perché le due porte sono isolate tra di loro. Per poter comunicare con una port dall’esterno abbiamo bisogno di un service (servizio) e qui entra in gioco il file service.yaml: la porta 30.000 del nodo viene ridiretta sulla porta 80 del container che è la target port.

Vediamo dunque come realizzare la cosa in pratica con minikube, implementandol’esecuzione del deployment, la rimozione di un pod e utilizzando la Dashboard di minikube; procediamo con la spiegazione supponendo di avere un cluster già attivo è un’immagine delicata, utilizzando Apache e PHP.

Per prima cosa, impartiamo il comando:

minikube status

seguito da Invio; ciò sortisce l’effetto di riportare lo stato del cluster come mostrato nell’immagine seguente.

A questo punto possiamo impartire il comando, sempre seguito da Invio:

kubectl get nodes

vediamo il container esistente con il rispettivo stato e quindi un nodo con all’interno tutti i componenti del cluster:

Adesso impartiamo il comando (seguito da Invio):

kubectl get pods 

e a video vedremo la lista dei pod trovati nel cluster. Possiamo anche, con il comando seguente:

watch -n 1 kubectl get pods

ottenere un aggiornamento costante ogni secondo per vedere se si aggiungono pod.

Ora per comodità con l’apposito comando del menu contestuale che si apre cliccando nello schermo, splittiamo il video mettendo in alto la shell per la riga di comando (bash) e sotto quella contenente le informazioni sull’aggiornamento dello stato dei pod (watch), così da vedere l’effetto di alcuni comandi. Impartiamo quindi dalla riga di comando:

kubectl apply -f deployment.yaml

per eseguire il file che deployerà il nostro Web Server e dopo un po’ vedremo l’esito nella metà inferiore dello schermo (immagine seguente):

Nell’area watch vediamo quindi che vengono creati i cinque container previsti dalla replica (comando replicas: 5) nel file deployment.yaml, con il rispettivo stato (STATUS) e il tempo trascorso (AGE) dalla creazione. Vediamo quindi che il sistema sta creando 5 pod su quel cluster, ognuna corrispondente a un container.

Se lasciamo progredire lo strumento viene eseguito anche il file service.yaml e si attivano i servizi, quindi i container vanno uno dopo l’altro in running, salvo errori. Nellimmagine seguente riportiamo una particolare condizione che riguarda il fail sul pod 4, la cui esecuzione fallisce per un errore di caricamento dell’immagine del rispettivo container.

Ebbene, questo ci dà l’occasione per spiegare una caratteristica molto importante di Kubernetes, ossia che è auto-riparante, nel senso che se capisce che c'è stato un problema (in questo caso nel pod numero 4) esegue nuovamente la sequenza e quindi il file di deploy finché la creazione non è riuscita.

Quando tutto è a posto possiamo impartire dalla finestra bash il comando:

minikube IP

per ottenere l’indirizzo IP assegnato al cluster e, aprendo un browser web, puntare ad esso specificando la porta 30000 definita nel file service.yaml. Il riultato sarà la visualizzazione della pagina del nostro web server demo creato con i file yaml (immagine seguente). 

In basso nella pagina sono mostrati il Container ID e il Container IP corrispondenti al server, però è il caso di notare che nell’esempio abbiamo creato 5 repliche e quindi altrettanti container; ebbene, questo accade perché già nel nostro cluster avviene già il bilanciamento del carico fra i 5 container, infatti aprendo altre sessioni del browser o una finestra di un altro browser verosimilmente in pochi tentativi vedremo cambiare l’indirizzo IP del container e il relativo ID, perché il load balancer ci avrà dirottato su un altro pod.

Bene, finora abbiamo lavorato a riga di comando, ma con questa non tutto è facile da realizzare; allo scopo minikube rende disponibile una Dashboard cui si accede mediante il comando:

minikube dashboard

seguito da Invio. Questo apre la Dashboard, che è un’interfaccia utente sul web, connessa quindi tramite Internet, dove è possibile vedere tutto quello che abbiamo fatto (immagine seguente). Si tratta dell’interfaccia ufficiale di Kubernetes.

Quindi nel caso dell’esempio proposto vediamo il nostro deployment con 5 pod e accedendo alle varie sezioni possiamo vedere lo status anche a livello di monitoraggio, di l'utilizzo della CPU e della RAM e lo stato in generale.

Ripe Ncc Member
vmware
CloudLinux
Plesk
HP
Microsoft