Kubernetes : la piattaforma di Google per la gestione dei container

Transcript

Kubernetes : la piattaforma di Google per la gestione dei container
Scuola Politecnica e delle Scienze di Base
Corso di Laurea in Ingegneria Informatica
Elaborato finale in Sistemi Operativi
Kubernetes : la piattaforma di Google per
la gestione dei container
Anno Accademico 2015/2016
Candidato:
Mario Brescia
matr. N46001647
Indice
Indice..................................................................................................................................................III
Introduzione..........................................................................................................................................4
Capitolo 1: I Container.........................................................................................................................5
1.1 Vantaggi nell’uso dei container..................................................................................................6
1.2 Utilizzo dei container nel cloud computing................................................................................7
1.3 Strumenti per la gestione dei container......................................................................................8
Capitolo 2: Kubernetes.......................................................................................................................10
2.1 Vantaggi....................................................................................................................................11
2.2 Architettura...............................................................................................................................12
2.2.1 Worker Node....................................................................................................................13
2.2.2 Master Node....................................................................................................................15
2.3 Funzionalità Principali..............................................................................................................17
2.3.1 Networking......................................................................................................................17
2.3.2 Creazione e scalabilità dei pod........................................................................................18
2.3.3 Health Checking..............................................................................................................19
2.3.4 Namespace.......................................................................................................................19
2.3.5 Scalabilità del cluster.......................................................................................................20
Capitolo 3: Progettazione di un’applicazione con Kubernetes...........................................................23
Conclusioni.........................................................................................................................................29
Bibliografia.........................................................................................................................................30
Introduzione
In informatica, con il termine virtualizzazione si fa riferimento a tutte quelle tecnologie
che permettono l’astrazione delle componenti hardware (CPU,RAM e storage) degli
elaboratori al fine di renderle disponibili al software sotto forma di risorsa virtuale.
Un approccio alternativo alla virtualizzazione è la cosiddetta virtualizzazione basata su
container, nota anche come virtualizzazione a livello di sistema operativo. Il concetto
chiave è quello di container, ovvero un’ istanza isolata in grado di incapsulare al suo
interno sia l’applicazione, sia le relative librerie.
Scopo di questo elaborato è fornire una panoramica generale su questa tecnologia
presentandone le caratteristiche e i vantaggi che ne hanno favorito l’utilizzo nel mondo del
cloud computing. Verranno quindi messi in evidenza i motivi per i quali nasce la necessità
di avere strumenti che permettano di gestire i container ad alto livello.
Ci si concentrerà con maggiore attenzione su uno di questi strumenti , Kubernetes, che è
divenuto negli ultimi anni uno dei più utilizzati tool di orchestrazione dei container.
Verranno presentate quindi le sue caratteristiche e la sua architettura , mettendone in
risalto le principali funzionalità offerte mostrando infine nell’ultima parte come questo
strumento possa essere utilizzato per progettare una semplice applicazione multi-tier.
4
Capitolo 1: I Container
I container rappresentano spazi utente multipli e isolati direttamente in esecuzione sul
livello di sistema operativo. Un container incapsula l’applicazione e tutte le sue
dipendenze risultando indipendente dall’architettura sottostante.
Sono utilizzati in
alternativa alle macchine virtuali attraverso una tecnica di virtualizzazione nota come
virtualizzazione basata su container. La differenza fondamentale rispetto all’approccio
classico basato sull’utilizzo dell’hypervisor sta nella condivisione del medesimo kernel fra
tutti i container in esecuzione. Quindi come mostrato in figura 1 [21] , non è possibile
avere in esecuzione sullo stesso hardware ambienti virtualizzati con sistemi operativi
diversi, cosa che è invece possibile utilizzando le macchine virtuali.
Figura 1 : Differenze tra virtualizzazione classica e virtualizzazione basata su container
5
1.1 Vantaggi nell’uso dei Container
Analizziamo nel dettaglio i vantaggi offerti da questa tecnologia :
•
isolamento : al fine di garantire l’isolamento delle risorse tra il sistema host e i container in
esecuzione su di esso, viene implementato un meccanismo del kernel noto come namespace
per fare in modo che ogni processo abbia una propria visione del sistema , differente da
quella degli altri processi. Le risorse sono quindi effettivamente condivise, ma ogni
container vede le risorse (filesystem,memoria,processi e dispositivi) come se fossero
interamente dedicate ad esso
•
migliore gestione delle risorse : al fine di gestire l’accesso alle risorse , i container
utilizzano un altro modulo kernel noto come cgroups, che permette sia di limitare l’accesso
a CPU, memoria e I/O per alcuni container, sia di fare in modo che essi possano accedervi
con maggiore priorità rispetto ad altri
•
sviluppo semplificato : un container impacchetta l’applicazione in un singolo componente
che può essere distribuito e configurato con una sola linea di comando, non bisogna quindi
preoccuparsi dell’eventuale configurazione dell’ambiente di esecuzione
•
maggiore disponibilità : uno sviluppatore può ospitare sul proprio computer miriadi di
container. Un container è infatti molto più leggero di una macchina virtuale che può arrivare
anche a pesare alcuni Gb. L’esecuzione di più macchine virtuali contemporaneamente è
comunque possibile ma andrebbe a impattare pesantemente con le prestazioni del sistema,
cosa che non accade invece con i container grazie alla loro dimensione ridotta
•
tempi di avvio più rapidi : dal momento che si virtualizza solo il sistema operativo e non
l’intera macchina, il container può essere avviato in un tempo che è molto più breve di
quello necessario per avviare una macchina virtuale
•
portabilità e consistenza : è probabilmente il vantaggio più importante che questa
tecnologia è in grado di offrire grazie al suo formato che consente l’esecuzione applicativa
su diversi host. Grazie alla standardizzazione è poi facile spostare velocemente i carichi di
lavoro lì dove sono eseguiti in maniera più economica e rapida, evitando i problemi di
compatibilità legati alle particolari caratteristiche delle singole piattaforme dei provider
6
1.2 Utilizzo dei container nel cloud computing
Nonostante i numerosi vantaggi, i container hanno sofferto nei primi anni di vita, la
mancanza di supporto che ne stimolasse l’evoluzione. Con il passare del tempo però, come
affermato dal CRO di Rackspace (azienda da sempre attiva nella gestione del cloud)
“sempre più casi d’uso si sono rivelati calzanti per l’utilizzo dei container, come ad
esempio la distribuzione in modo rapido e il porting delle applicazioni tra diversi tipi di
infrastrutture, la creazione e la gestione di servizi di cloud più accurati ed efficienti, lo
sviluppo di metodi di trasporto e così via”[16].
Questi sono fondamentalmente i motivi per cui numerose aziende hanno iniziato poi a
supportare lo sviluppo di questa tecnologia. Oltre LXC infatti abbiamo diverse soluzioni
che implementano i container, da Core OS, a Docker, passando per Mesos
fino a
Kubernetes, il cuore di questo elaborato.
Il vero punto di forza dei container sta proprio nella minor potenza di calcolo richiesta,
nella leggerezza, nella portabilità, nell’isolamento e soprattutto nella capacità di fare a
meno dell’hypervisor. Essendo poi
basati su tecnologie open-source rappresentano
un’ottima soluzione alle richieste di maggiore agilità, risparmio e flessibilità nel contesto
delle risorse informatiche che vengono utilizzate per il cloud pubblico,privato o ibrido. Il
cloud può essere visto come una galassia di server molto eterogenei, ognuno con delle
proprie caratteristiche e risulta quindi chiaro perché molte aziende, tra cui Google in
primis, usano i container per far girare in maniera efficiente i workload su questi server.
Ogni applicazione nell’ecosistema Google viene infatti eseguita all’interno di container, da
Gmail a Maps, fino alla ricerca Web e sono circa 2 miliardi i container avviati ogni
settimana da Google.
Il container rappresenta l’elemento perfetto per gestire le complessità soprattutto perché,
oltre a possedere una forte componente di automatizzazione dei suoi processi di
creazione,avvio e gestione, consente anche in modo molto semplice la riorganizzazione
tramite crescenti livelli di astrazione.
L’utilizzo di questa tecnologia permette poi di allontanarsi ancora di più dai vincoli
7
hardware permettendo di avere un sistema che presenta una maggiore flessibilità,
compattezza e funzionalità sia per le macchina host, sia per i fornitori di servizi, sia per gli
utilizzatori finali del sistema stesso.
1.3 Strumenti per la gestione dei container
Al crescere del numero dei container in esecuzione su vari host, diventa fondamentale
avere degli strumenti appositi per gestirli in maniera semplice, diretta e con un livello di
astrazione anche abbastanza elevato. Tra le varie soluzioni presenti nel mercato odierno
abbiamo Docker e Kubernetes che operano a differenti livelli di astrazione.
Docker è un progetto open-source che estende la tecnologia LXC (Linux Container),
introducendo una API di alto livello che permette di automatizzare la distribuzione del
software in ambiente sicuro e riproducibile. Fornisce quindi tutte le funzionalità necessarie
per costruire,caricare,scaricare,avviare e arrestare un container. È pensato per la gestione
di questi processi soprattutto in ambienti single-host con un numero abbastanza piccolo di
container.
Quando le applicazioni sono scalate attraverso più host, diventa fondamentale gestire ogni
host e astrarne la sua piattaforma sottostante in maniera tale da eliminare eventuali
complessità. Con il termine orchestration intendiamo proprio la schedulazione dei
container, la gestione del cluster e il concetto di approvvigionamento. È in questo contesto
che andremo ad introdurre Kubernetes.
La schedulazione si riferisce alla capacità dell’amministratore di caricare su un host un
servizio che stabilisce come eseguire un dato container.
Per gestione del cluster si intende invece il processo di controllo di gruppi di host. Questo
può includere l’aggiunta o la rimozione di host dal cluster, l’acquisizione di informazioni
sullo stato corrente di host e container , l’avvio e l’interruzione di processi.
Una delle maggiori responsabilità dello schedulatore è la selezione dell’host : se un
amministratore decide di eseguire un servizio (un container) sul cluster, solitamente lo
schedulatore seleziona l’host in modo automatico. L’amministratore può però
8
opzionalmente imporre dei vincoli sulla schedulazione in accordo con i suoi bisogni e
desideri, ma alla fine è sempre lo schedulatore a decidere se rispettarli o meno.
Gli schedulatori più avanzati mettono a disposizione una funzionalità che permette la
gestione di gruppi di container per consentire all’amministratore di trattare un insieme di
container come una singola applicazione, mantenendo i vantaggi derivanti dall’uso dei
container e riducendo l’overhead addizionale di gestione.
Un concetto legato alla gestione del cluster è quello di approvvigionamento, ovvero quel
processo mediante il quale un amministratore di sistema può inserire nuovi host nella rete
e configurarli in maniera semplice, così che essi possano essere usati per eseguire delle
operazioni.
Nonostante il risultato dell’approvvigionamento sia sempre la comparsa di un nuovo host
online disponibile per eseguire nuove operazioni, la metodologia con cui ciò viene fatto
dipende dal tool e dal tipo di host usati. L’approvvigionamento può infatti essere eseguito
dall’amministratore, oppure essere inglobato nei tool di gestione del cluster per lo scaling
automatico. Questo secondo metodo comporta la definizione di un processo per richiedere
host addizionali così come la definizione delle condizioni che devono verificarsi affinché
questa richiesta venga inoltrata. Ad esempio, se la nostra applicazione soffre di un
sovraccarico del server, sarebbe desiderabile che il nostro sistema avviasse nuovi host e
scalasse i container attraverso l’infrastruttura al fine di alleviare la congestione.
Alcuni progetti che offrono gestione del cluster e schedulazione basilari sono :
•
fleet , marathon (componente di Mesosphere) e Swarm
Tra i progetti che invece offrono funzionalità di schedulazione avanzate e gestione di
gruppi di container come una singola unità abbiamo :
•
kubernetes e docker’s compose
9
Capitolo 2: Kubernetes
Kubernetes è un progetto open-source rilasciato da Google nel Giugno del 2014 volto a
incrementare lo sforzo dell’azienda nel voler condividere i vantaggi della sua infrastruttura
e tecnologia con tutta la comunità su grande scala. Il progetto nasce fondamentalmente
dalle perplessità di Google circa i limiti mostrati da Docker nel coordinare, gestire e
distribuire i container e i
carichi di lavoro man mano che le risorse disponibili
nell’infrastruttura sottostante erano consumate e soprattutto al crescere del numero di host
e container . Google asserisce con fermezza che tutti questi problemi possono essere
superati con l’utilizzo di Kubernetes che sin dalla sua prima versione ha subito un rapido
sviluppo dovuto soprattutto all’enorme contributo di tutta la comunità open-source, da Red
Hat a Vmware. La piattaforma è utilizzata per automatizzare lo sviluppo , la scalabilità e
le operazioni di applicazioni containerizzate all’interno di gruppi di host, fornendo
un’infrastruttura basata sui container. In una rete di computer Kubernetes è in grado di
gestire lo scheduling sui nodi e i carichi di lavoro in modo attivo per assicurare che
vengano soddisfatte le esigenze degli utenti. Per garantire una più semplice gestione dei
container, Kubernetes utilizza i concetti di label e pod. I pod sono insiemi di container
co-locati, i label sono invece usati per organizzare e selezionare gruppi di oggetti. Il
funzionamento di Kubernetes è basato sul ciclo di controllo mostrato in figura 2 [19] :
Figura 2 : Ciclo di controllo
10
esso si basa sui concetti di stato desiderato e stato reale che rappresentano la chiave di
gestione dell’intero cluster e dei suoi carichi di lavoro. Tutti i componenti in Kubernetes
lavorano infatti in modo continuo per monitorare lo stato reale e sincronizzarlo con lo
stato desiderato definito dall’amministratore.
2.1 Vantaggi
Kubernetes si presenta come un tool molto utile nella gestione di più container in
esecuzione su host diversi all’interno di un cluster. Partendo dalle funzionalità base di
Docker, le estende fornendo un livello di astrazione ancora più elevato e grazie
all’automatizzazione dello sviluppo e della replicazione dei container, ottenibili lanciando
semplici istruzione da riga di comando, è possibile rispondere alle esigenze sempre
crescenti di scalabilità delle nostre applicazioni. L’attenzione dello sviluppatore grazie
all’utilizzo di questo tool, è completamente rivolta all’applicazione e non più alla
piattaforma su cui essa verrà eseguita. I vantaggi sono evidenti anche per gli
amministratori del cluster : nel momento in cui un’ applicazione richiede più risorse, è
possibile in maniera semplice e intuitiva redistribuire i vari container (raggruppati in pod)
in modo da ripartire i carichi di lavoro tra i nodi correntemente attivi del nostro cluster.
Anche l’aggiornamento di un’applicazione diventa un’operazione rapida e invisibile
all’utente effettivo del servizio che la nostra applicazione fornisce. Lo stesso accade
quando un container viene eliminato : l’operazione di rimpiazzamento viene eseguita in
tempi rapidissimi grazie all’implementazione del ciclo di controllo e nel momento in cui lo
stato reale del sistema non rispecchia quello desiderato dall’amministratore, tutti i
componenti si attivano per far si che la situazione torni alla normalità. Il tool è utilizzato
inoltre per gestire il networking dei servizi containerizzati e realizzare dei metodi di selfhealing del cluster. Le potenzialità sono talmente elevate che la stessa Google afferma che
Kubernetes può gestire cluster contenenti fino a 100 nodi con 30 pod per nodo e con 1-2
container per pod. Tutto questo garantendo un controllo più accurato sull’utilizzo delle
risorse come CPU, memoria e spazio su disco .
11
2.2 Architettura
Kubernetes è un vero e proprio ecosistema in cui coesistono numerosi componenti che
interagiscono tra di loro per orchestrare i container presenti in un cluster . I componenti
possono essere classificati in due macro gruppi , quelli appartenenti al Master che
rappresenta il “cervello” dell’intero ecosistema, e quelli appartenenti ai nodi worker che
rappresentano le unità elaborative su cui vengono distribuiti i vari container . I componenti
principali sono mostrati in figura 3 e saranno analizzati uno alla volta nei paragrafi
successivi.
Figura 3 : Architettura interna di Kubernetes
12
2.2.1 Worker Node
Il nodo worker (precedentemente conosciuto come Minion)
rappresenta una
macchina fisica o virtuale che esegue una serie di operazioni. Ogni nodo è
caratterizzato da uno stato (che può essere pronto o non raggiungibile) , un
indirizzo IP esterno per essere visibile al di fuori del cluster e un indirizzo IP
interno per essere raggiungibile all’interno del cluster stesso. Il nodo è poi
caratterizzato da una certa capacità che definisce il numero di risorse disponibili su
quel nodo, ovvero CPU, memoria e il numero massimo di pod che possono essere
schedulati su di esso. Normalmente la capacità è impostata in automatico dallo
scheduler, uno dei componenti più importanti del Master, in maniera tale che la
somma delle risorse richieste dai vari container su un nodo non ecceda la capacità
del nodo stesso. A differenza dei pod e dei servizi un nodo non è direttamente
creato da Kubernetes ma è fornito da un cloud provider , ad esempio il Google
Compute Engine, oppure è una macchine fisica o virtuale. Questo significa che
quando Kubernetes crea il nodo , in realtà sta solo creando un oggetto che
rappresenta lo stato interno del nodo. Creato il nodo vengono effettuati poi dei
controlli di validità per verificare che esso funzioni nel modo corretto. Ogni nodo
worker possiede i servizi necessari per eseguire i pod ed è gestito dal nodo Master. I
servizi posseduti dal nodo includono Docker (che si occupa ovviamente di eseguire
i container), kubelet e kube-proxy. Li analizzeremo ora nel dettaglio.
•
Kubelet : uno dei servizi di base che gestisce i pod e i loro container, le loro
immagini , i loro volumi etc. Rappresenta una sorta di supervisore che viene
eseguito all’interno di ogni nodo. Kubelet lavora seguendo le direttive definite nel
file di configurazione del pod, un oggetto in formato YAML o JSON, noto anche
come manifesto. Quindi kubelet riceve un insieme di file di configurazione , ad
esempio attraverso l’API server, e assicura che i container descritti in questi oggetti
siano in esecuzione e funzionino correttamente. Interagisce poi con l’API server
per aggiornare lo stato dei nodi e avviare nuovi carichi di lavoro assegnati allo
13
scheduler.
•
Kube-proxy : un servizio di proxy che opera anche come load balancer e redirige
il traffico destinato a specifici servizi sul pod appropriato nel cluster.
•
Pod : è la più piccola unità che può essere creata e gestita in Kubernetes.
Formalmente è un insieme di uno o più container che cooperano e quindi sono
raggruppati logicamente. I pod sono sempre co-locati e schedulati insieme, e
vengono eseguiti in un contesto condiviso che è un insieme di namespace,cgroups e
altri strumenti in grado di garantire l’isolamento. I container che si trovano nello
stesso pod condividono un indirizzo IP e un numero di porta e possono localizzarsi
l’uno con l’altro tramite localhost. Inoltre possono comunicare usando i
meccanismi standard di comunicazione tra processi. Le applicazioni all’interno di
un pod hanno anche accesso a volumi condivisi, che sono quindi parte del pod e
sono pronti per essere montati all’interno del filesystem di ogni applicazione.
Figura 4 : Architettura di un pod
I pod hanno un ciclo di vita abbastanza breve: sono creati, viene assegnato loro un
ID univoco e sono poi schedulati sui nodi dove rimangono fino alla terminazione
(in accordo con determinate politiche) o alla cancellazione. Se un nodo muore, i
pod schedulati da quel nodo vengono eliminati dopo la scadenza di un certo
timeout. Dato un pod con un certo ID , esso non può essere rischedulato da un
14
nuovo nodo, piuttosto esso può essere replicato dando vita ad un nuovo pod che
può avere anche lo stesso nome ma un nuovo ID. Questo è ciò che fa il controller di
replicazione che vedremo successivamente. Naturalmente se un pod viene
eliminato per qualche motivo anche i volumi a esso collegati saranno distrutti.
•
cAdvisor : il suo compito è monitorare le performance e le risorse utilizzate dai
container. A questo proposito esplora tutti i container nella macchina e colleziona le
statistiche di utilizzo di memoria, filesystem, rete e CPU.
2.2.2 Master Node
Essenzialmente il master è il cervello del nostro cluster. Esso ospita tutti quei componenti
che cooperano per fornire una visione unificata della rete e formano nel loro insieme il
cosiddetto pannello di controllo di Kubernetes. In particolare abbiamo :
•
Scheduler : in generale uno schedulatore di container ha lo scopo principale di far
partire l’esecuzione dei container sull’host appropriato e di connetterli tra loro.
Deve inoltre gestire i fallimenti in modo automatico e deve essere in grado di
scalare i container quando ci sono troppi dati da processare ed elaborare su una
singola istanza. Nel caso di Kubernetes quindi lo scheduler ha l’obiettivo principale
di assegnare i pod non schedulati ai nodi. Lo scheduler utilizza predicati e priorità
per stabilire su quale nodo un pod dovrebbe essere eseguito. I predicati sono regole
obbligatorie per schedulare un nuovo pod sul cluster. Se nessuna macchina
corrisponde ai predicati richiesti dal pod, allora esso rimarrà in uno stato di attesa
finché non ci sarà una macchina che possa soddisfarli. Se poi lo scheduler trova più
macchine che soddisfano i predicati richiesti, allora verranno utilizzate le priorità
per capire quale macchina è più adatta ad eseguire quel determinato pod.
•
API server : rappresenta la application programming interface di Kubernetes. É
pensato per fornire le funzionalità CRUD (Create,Read,Update,Delete). Processa
poi per lo più le cosiddette operazioni REST (delete,get,head,post,put), le convalida
e aggiorna gli oggetti riferiti da queste operazioni che sono presenti in etcd. È bene
15
notare che le richieste di modifiche ad un nodo non vengono inviate direttamente al
nodo stesso , ma sempre al nodo master sotto forma di query
•
Controller manager : è responsabile del monitoraggio dei controller di
replicazione e della creazione dei pod corrispondenti. Utilizza la API per rilevare
nuovi controller e per creare/eliminare i pod
•
Controller di replicazione : coopera con l’API server per assicurare che in ogni
istante di tempo un pod o un insieme di pod siano sempre attivi e disponibili. Ogni
controller di replicazione mantiene uno stato desiderato che è gestito dallo
sviluppatore dell’applicazione e quando questo stato cambia, il controller tenta di
modificare lo stato corrente affinché si riconcili con quello desiderato. Per esempio
se incrementiamo il numero di istanze desiderate da tre a quattro, il controller di
replicazione rileverà la necessità di una nuova istanza, la creerà e la lancerà da
qualche parte nel cluster. Il controller di replicazione mantiene il template di un pod
per creare nuovi pod se necessario. Fa poi uso dei label per gestire solo i pod di cui
è responsabile. Ad esempio il controller di replicazione di una webapp frontend è
responsabile di tutti i pod che hanno il campo app=webapp e il campo role =
frontend. Il rilascio di aggiornamenti e modifiche può essere eseguito utilizzando i
controller di replicazione e usando il comando kubectl rolling-update.
•
Etcd : rappresenta un database basato su chiave distribuita che fornisce un metodo
affidabile per memorizzare dati attraverso un cluster di macchine. Tutte le
elaborazioni del nodo master che richiedono persistenza sono memorizzate in
un’istanza di etcd.
16
2.3 Funzionalità Principali
2.3.2 Networking
Kubernetes permette di gestire quattro tipi di comunicazione :
1. Comunicazione tra container : ogni pod possiede un proprio indirizzo IP, ma
poiché il container esiste nell’ambito del pod stesso, condividerà con esso
l’indirizzo IP. Quindi i container all’interno di un pod possono comunicare con gli
altri container tramite localhost.
2. Comunicazione tra pod : come detto ogni pod in Kubernetes possiede un proprio
indirizzo IP reale che si suppone essere raggiungibile da tutti gli altri host e pod
presenti nel cluster. Questa comunicazione può essere implementata attraverso
strumenti ausiliari, tra cui Google Compute Engine, Calico e Flannel.
3. Comunicazione tra pod e servizio : un servizio è un’astrazione che definisce un
insieme logico di pod e una politica con cui accedervi ( ad esempio di
bilanciamento del carico ). I servizi sono fondamentali per la gestione di un cluster
Kubernetes : dal momento che i pod possono essere creati, distrutti e rischedulati
dinamicamente (ad esempio scalando l’applicazione o rilasciando modifiche)
potrebbe accadere che l’indirizzo IP di un pod mantenuto dal relativo controller di
replicazione che lo gestisce, non sia più lo stesso. Occorre quindi un meccanismo
in grado di identificare in ogni istante il gruppo di pod con cui si sta comunicando
Ciò viene realizzato attraverso l’uso dei servizi che assegnano a un insieme di pod
un indirizzo IP che rimane stabile e fisso durante tutto il ciclo di vita del servizio. Il
gruppo di pod coperti dal servizio è specificato usando un selettore di label.
4. Comunicazione tra servizio e mondo esterno : fino ad ora si è parlato di come
accedere ad un pod o ad un servizio all’interno del cluster stesso. Se si vuole
accedere a un pod dall’esterno del cluster la situazione diventa leggermente più
complicata. Questa comunicazione è in genere implementata attraverso meccanismi
di bilanciamento del carico esterni che permettono di raggiungere tutti i nodi del
cluster. Quando ad un nodo giunge una richiesta, essa viene riconosciuta come
17
parte di un particolare servizio e instradata al pod appropriato
2.3.1 Creazione e scalabilità dei pod
Per creare i pod abbiamo due possibilità : creare un oggetto di tipo Deployment se
abbiamo un solo container all’interno del pod oppure creare direttamente il pod se
abbiamo più container al suo interno.
Il comando run crea un Deployment che va a monitorare i pod, avviandone di nuovi se
qualcuno di essi fallisce mantenendo sempre coerente il numero di pod con quelli definiti
nello stato desiderato del sistema.
Quando creiamo il pod tramite Deployment va
specificata l’immagine Docker da usare per il container, il numero di porta da esporre, il
numero di repliche del pod da creare (se non specificato verrà creata una replica) ed
eventuali label da agganciare al pod per identificarlo. Si noti che se i pod sono gestiti con i
Deployment,
per
eliminarli
definitivamente
bisogna
eliminare
il
Deployment
corrispondente che li gestisce.
Nel caso in cui non volessimo usare i Deployment (ad esempio se il pod non produce dati
persistenti che devono sopravvivere a un riavvio, o il pod è pensato per avere vita breve) è
possibile creare il pod direttamente tramite il comando create passandogli un file di
configurazione in formato YAML o JSON che descrive le caratteristiche del pod. Nel file
di configurazione oltre a specificare il nome del container e dell’immagine Docker, è
possibile specificare le politiche di riavvio dei container all’interno del pod e una lista di
volumi che possono essere utilizzati dai container appartenenti allo stesso pod.
Se creiamo i pod direttamente diventa obbligatorio creare i controller di replicazione per
gestirli al meglio e poter effettuare lo scaling dei pod attraverso il cluster. Questa è
fondamentalmente la differenza tra i due approcci : dichiarativo se usiamo i Deployment,
imperativo se usiamo i controller di replicazione.
Indipendentemente dall’utilizzo di un controller di replicazione o di un Deployment, è
possibile incrementare o decrementare automaticamente il numero di pod in base ad
alcune metriche, ad esempio la percentuale di utilizzo della CPU. L’autoscaling è
18
orizzontale se si scala il numero di istanze, verticale se si scala il numero di risorse
utilizzate da un’istanza. In particolare l’autoscaler orizzontale viene implementato tramite
un controller che periodicamente modifica il numero di repliche in un controller di
replicazione o in un Deployment per far si che la percentuale media di utilizzo della CPU
sia uguale a quella specificata dall’utente. La percentuale di utilizzo della CPU viene
calcolata come rapporto tra la frazione di CPU utilizzata da un pod e la somma delle
richieste di CPU da parte dei container che si trovano nel pod.
2.3.3 Health checking
Piuttosto che provare a scrivere codice privo di errori, un approccio migliore è usare un
sistema di gestione degli errori che esegua periodicamente un controllo sullo stato
dell’applicazione e che eventualmente la ripari. In questo modo è un sistema esterno alla
nostra applicazione a essere responsabile del monitoraggio dell’applicazione stessa e di
eseguire operazione per risolvere eventuali problemi. É importante che il sistema sia
esterno, perché se fosse interno, qualora l’applicazione fallisse, fallirebbe anche il sistema
di monitoraggio. In kubernetes il componente responsabile del monitoraggio è kubelet che
interroga costantemente il Docker daemon per verificare se un certo container è in
esecuzione e se così non è viene riavviato.
2.3.4 Namespace
Per separare utenti, gruppi o applicazioni all’interno del cluster si utilizzano i namespace.
Il namespace è un meccanismo utilizzato per partizionare le risorse create dagli utenti in
gruppi. Un singolo cluster infatti potrebbe essere utilizzato da più utenti o gruppi di utenti.
Ogni utente però, avendo le proprie risorse (pod,servizi,rcs) e politiche ( chi può o non può
eseguire operazioni nel suo ambiente) vorrebbe avere la possibilità di lavorare in un
ambiente isolato non accessibile agli altri utenti . Il namespace permette proprio di
realizzare ciò fornendo un meccanismo di naming delle risorse (per evitare collisioni) e la
possibilità di limitare il consumo di risorse per un certo gruppo di utenti. Questo
19
meccanismo è molto utile per gli operatori del cluster perché si possono ospitare più
community di utenti su un singolo cluster. Altro vantaggio per gli operatori del cluster è la
possibilità di limitare il numero di risorse che ogni community può utilizzare in modo da
evitare che il loro consumo eccessivo possa danneggiare o limitare l’utilizzo del cluster
per altre community. D’altro canto ovviamente, lo stesso utente del cluster trae vantaggi
dall’utilizzo di questo meccanismo avendo la possibilità di interagire con risorse che sono
attinenti alla sua community garantendo al contempo il loro isolamento.
Kubernetes prevede due namespace iniziali , default (per oggetti che non hanno altri
namespace) e kube-system (per oggetti creati da Kubernetes). Ogni namespace può poi
avere due stati : active se il namespace è in uso, o terminating se il namespace è in fase di
cancellazione.
2.3.5 Scalabilità del cluster
Una delle più importanti funzionalità offerta da Kubernetes è la possibilità di gestire e
scalare facilmente verso l’alto o verso il basso il numero di pod.
Cosa succede se a un certo punto i nodi sono saturi e sono richieste più risorse per
schedulare nuovi pod per i nostri carichi di lavoro ? Al momento della creazione del
cluster possiamo definire il numero iniziale di nodi (minions) che per default è impostato a
quattro. Questo valore è mantenuto in una variabile di ambiente e ogni modifica a questa
variabile dopo l’avvio del cluster non avrà effetto.
Per scalare il cluster rapidamente è possibile usufruire delle potenzialità offerte dal Google
Cloud Engine che rappresenta un vero e proprio motore che supporta Kubernetes nelle sue
elaborazioni.
Il Google Compute Engine fornisce una semplice e intuitiva interfaccia grafica che
permette in modo rapido la scalabilità del cluster aggiungendo o rimuovendo dei nodi per
schedulare nuovi pod e workload. L’unica nota da tenere in considerazione è che nel
momento in cui effettuiamo un’operazione di scale down
il Google Cloud Engine
rimuove un nodo che non è però necessariamente l’ultimo aggiunto. In ogni caso
20
comunque i pod assegnati a quel nodo verranno rischedulati sui rimanenti nodi. Di seguito
è mostrato il funzionamento di questo meccanismo , in particolare di una operazione di
scaling verso il basso.
Supponiamo di avere inizialmente quattro nodi e che lo stato desiderato del sistema,
monitorato dal controller manager e mantenuto dal controller di replicazione, coincida con
quello attuale.
Figura 5 : stato iniziale del cluster e successiva eliminazione di un nodo
Supponiamo che in un certo istante uno dei nodi venga eliminato come mostrato in figura
5. In questo caso lo stato attuale sarà diverso da quello desiderato. Il controller manager
che esegue il ciclo di controllo in modo continuativo, rileva il cambiamento e invoca il
controller di replicazione che va a replicare il pod che era stato schedulato sul nodo
eliminato come mostrato in figura 6.
21
Figura 6 : Stato Intermedio del cluster e implementazione del ciclo di controllo
22
Capitolo 3: Progettazione di un’applicazione con Kubernetes
Verranno ora illustrati i passi chiave per la progettazione di una semplice e generica
applicazione multi-tier costituita da front-end web-server e back-end database.
In particolare si supponga di voler realizzare un’applicazione costituita da tre container
front-end e due container back-end. L’utente presumibilmente accederà tramite browser
all’applicazione web e richiederà un certo servizio . Partirà quindi una chiamata al webserver che manderà a sua volta una richiesta al servizio di back-end per erogare la
funzionalità richiesta.
Il primo passo è ovviamente scrivere i vari livelli dell’applicazione e successivamente
inserirli in dei container Docker. Per fare ciò dobbiamo creare per ogni livello un
Dockerfile, un vero e proprio file di testo che contiene tutti i comandi utili a Docker per
creare immagini in modo automatico a partire da un’immagine base. É bene quindi capire
subito cos’è un’immagine e qual è la differenza con un container.
Un’ immagine è costituita dal filesystem e dai parametri da usare a tempo di esecuzione,
non ha uno stato e non cambia mai. Un container invece è un’istanza di una certa
immagine che viene mandata in esecuzione.
Generalmente in un Dockerfile compaiono alcune keywords base che permettono di creare
un’immagine :
•
FROM : comunica a Docker su quale immagine è basata la nostra immagine. Se
l’immagine non viene trovata sull’host, Docker la cerca in un indice contenente
tutte le varie immagini e ne effettua il download.
•
RUN : prende un comando come suo argomento e lo esegue per costruire
l’immagine.
•
CMD : può essere usato per eseguire uno specifico comando
23
•
EXPOSE : è usato per associare una porta specifica in modo tale da abilitare la
connessione di rete tra il processo in esecuzione all’interno del container e il mondo
esterno (ad esempio l’host).
•
VOLUME : è usato per abilitare l’accesso del container a una directory sulla
macchina host.
Dopo l’esecuzione dei Dockerfile avremo sostanzialmente dei veri e propri container che
possono essere mandati in esecuzione o arrestati. Dati i container bisogna poi caricarli con
un’operazione di push sul Google Container Registry , un repository privato utilizzato per
memorizzare le nostre immagini di container Docker sulla piattaforma cloud di Google per
un recupero e uno sviluppo semplice e scalabile.
Dopo il push, se tutto va a buon fine, le diverse immagini saranno disponibili nel
Container Registry pronte per essere orchestrate da Kubernetes.
Una volta che i container possono essere acceduti e gestiti dalla nostra piattaforma,
bisogna creare un cluster Kubernetes, ovvero un Master e dei nodi Worker su cui poi
andare a distribuire i vari pod che incapsuleranno i vari container. Anche la creazione del
cluster, grazie alla semplicità di utilizzo di Kubernetes, può avvenire semplicemente
eseguendo un’apposita istruzione di creazione da riga di comando del tipo :
gcloud container clusters create NAME
In alternativa l’operazione può essere eseguita attraverso l’interfaccia web di Kubernetes.
Dopo la creazione dovremmo avere un cluster con tre nodi pronti a ricevere i nostri
container come mostrato in figura 7.
24
Figura 7 : Fase iniziale della costruzione di un cluster Kubernetes
Bisogna ora creare i controller di replicazione che, contenendo i template dei vari pod,
permettono di gestirli in modo rapido. Nello specifico occorrono due controller, uno per il
front-end che gestirà tre pod e uno per il back-end che gestirà due pod. Per creare un
controller di replicazione si può usare il seguente comando :
kubectl create -f <replication controller filename>
Per visualizzare invece i controller presenti nel cluster basta digitare :
kubectl get rc
Dopo la creazione dei due controller avremo la situazione mostrata in figura 8 con un
totale di cinque pod.
25
Figura 8 : Fase intermedia della creazione di un cluster Kubernetes
I container non sono pensati per memorizzare uno stato persistente, infatti quando un
container va in crash o viene riavviato, il suo filesystem locale viene cancellato. Se c’è la
necessità di mantenere questo stato , bisogna utilizzare dei volumi persistenti. Dal
momento che ogni cosa in Kubernetes è basata sui pod, i volumi devono essere definiti
all’interno dei pod stessi. L’uso di un volume è comunque limitato al nodo che contiene
quel determinato pod e sopravvive a crash e riavvii ma non ai fallimenti del nodo o
dell’host. É chiaro quindi che bisogna ancora effettuare la duplicazione o il back-up di dati
importanti.
Abbiamo quindi fatto in modo che i nostri container siano sotto il controllo di Kubernetes
ma dobbiamo ancora renderli accessibili al mondo esterno.
Di default, i pod sono accessibili solamente all’interno del cluster Kubernetes attraverso il
proprio IP interno. Per far si che essi siano invece accessibili anche all’esterno della nostra
rete virtuale, bisogna configurare i pod come dei servizi . In seguito a questa procedura di
“expose” i nostri pod , avranno oltre ad un indirizzo IP che li identifica all’interno del
26
cluster, anche un IP esterno affinché possano essere raggiunti da host esterni alla nostra
rete. Per creare un servizio :
kubectl create -f -myservice.yaml
Dopo l’esposizione saremo quindi in grado di raggiungere i nostri due servizi di front-end
e back-end semplicemente inserendo il loro IP esterno nella barra di ricerca.
Con l’introduzione dei servizi il nostro cluster è completo almeno nelle sue funzionalità di
base e si presenta come in figura 9 :
Figura 9 : Fase finale della creazione di un cluster Kubernetes
27
Se ci si accorga che l’applicazione necessita di più risorse, o magari che essa può essere
gestita anche con meno risorse di quelle impiegate , invece di rimuovere l’intero controller
di replicazione e i pod associati, Kubernetes offre la possibilità di scalare facilmente
l’applicazione. Supponendo di avere due repliche in esecuzione, se volessimo averne altre
due per bilanciare il carico di lavoro basterebbe semplicemente scrivere :
kubectl get pods -l name=node-js-scale
kubectl scale –replicas=2 rc/node-js-scale
Se lo scaling va a buon fine, semplicemente apparirà la parola scaled sul nostro terminale.
Ogni pod può poi utilizzare uno o più “segreti” per gestire informazioni sensibili come
password o credenziali per accedere alla API. Tutti i segreti possono essere elencati
tramite :
kubectl get secrets
Come già detto poi Kubernetes permette di monitorare in tempo reale modifiche alle
risorse. Tutte queste modifiche sono accessibili tramite gli eventi :
kubectl get events
Infine per separare utenti, gruppi o applicazioni si utilizzano i namespace. Per creare un
nuovo namespace diverso da quelli di default dopo aver creato un apposito file di
configurazione basta eseguire :
kubectl create -f ./my-namespace.yaml
28
Conclusioni
Kubernetes si rivela essere uno strumento molto valido per la gestione del cluster e la
schedulazione delle operazioni, due attività che costituiscono una parte chiave
dell’implementazione di servizi containerizzati su insiemi di host distribuiti. In particolare
utilizzando questi strumenti di gestione dei container numerosi sono i vantaggi sia per gli
amministratori di sistema, sia per gli utenti finali del servizio. Grazie poi al rapido
sviluppo che sta attraversando la tecnologia dei container a discapito delle macchine
virtuali, saranno sempre più numerosi i casi d’uso cui questa tecnologia si presterà
andando a sancire il definitivo salto in avanti di questi cosiddetti schedulatori di container.
Tutto questo grazie a numerose aziende , Google in primis, che da sempre hanno
supportato questo progetto e che stanno estendendo i propri servizi cloud affinché
supportino nativamente i container.
29
Bibliografia
[1]
Omer Dawelbeit http://omerio.com/2016/01/02/getting-started-with-kubernetes-on-
google-container-engine/
[2]
Jonathan Baier, Getting Started with Kubernetes, Packt Publishing, 2015.
[3]
Kamal Marhubi, http://kamalmarhubi.com/blog/2015/08/27/what-even-is-a-kubelet/
[4]
Kubernetes http://kubernetes.io/docs
[5]
CloudTalk http://www.cloudtalk.it/container-cosa-sono-come-funzionano
[6]
CWIpedia http://www.cwi.it/container-cosa-funzionano-virtualizzazione_86516,
[7]
Nune Isabekya http://x-team.com/2016/07/introduction-kubernetes-architecture
[8]
Antonio Dini http://www.corrierecomunicazioni.it/tlc/34884_il-futuro-del-cloud-e-
nei-container.htm
[9]
CloudTalk http://www.cloudtalk.it/container-docker-kubernetes/
[10] The
Docker
Ecosystem
:
Scheduling
and
Orchestration
https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-scheduling-andorchestration
[11] Armand
Grillet,
Comparison
of
container
scheduler
https://medium.com/@ArmandGrillet/comparison-of-container-schedulersc427f4f7421#.c62744hdo
[12]DigitalOcean
https://www.digitalocean.com/community/tutorials/docker-explained-
using-dockerfiles-to-automate-building-of-images
[13] Docker https://docs.docker.com/
[14] CoreOS https://coreos.com/kubernetes/docs/latest/services.html
[15] Kubernetes Namespace http://kubernetes.io/docs/admin/namespaces/
[16] CloudTalk http://www.cloudtalk.it/i-container-sono-maturi-per-il-cloud-a-sostenerlorackspace
[17]Github
https://github.com/kubernetes/kubernetes/blob/master/docs/design/networking.md
30
[18] Openshift https://docs.openshift.com/enterprise/3.1/dev_guide/pod_autoscaling.html
[19]http://www.slideshare.net/SatnamSingh67/2015-0605-cluster-management-withkubernetes
[20] Wikipedia https://it.wikipedia.org/wiki/Virtualizzazione
[21] Vineet Badola http://cloudacademy.com/blog/container-virtualization/
31