Uno degli obiettivi principali del k8s è quello di offrire la possibilità di aggiornare il servizio senza interruzioni dell’operatività.
Container from zero to hero: 1 - Orchestratori e k8s intro
Breve introduzione all’utilizzo degli orchestratori e k8s intro
Oltre i container
Questa è la seconda parte della serie Container from zero to hero.
Nella prima parte della serie < Container from zero to hero: 0 - FONDAMENTI > sono state introdotte le origini e le motivazioni della diffusione dei container.
Qui introduciamo gli orchestratori, i loro obiettivi e le funzionalità principali, fino alla descrizione dello standard attuale tra gli orchestratori: kubernetes.
Già nell’anno 2013, docker si era affermato come standard de-facto per la gestione dei container. Docker con i suoi componenti poteva essere sufficiente all’utilizzo in produzione su sistemi distribuiti con molti microservizi? No, mancavano alcuni elementi importanti.
Con la gestione di molti container si sviluppa anche la necessità di automatismi per:
il deploy
l’alta affidabilità
la scalabilità
…
Kubernetes: le origini
Kubernetes nasce nel 2015 come risposta alla necessità di automazione e orchestrazione dei container. Nasce internamente a Google dall’esperienza del sistema Borg, il sistema di gestione del cluster su cui si basano le loro tecnologie di punta:
Gmail, YouTube, Google Search, …
Google mantiene il tema Borg (di startrek) con il progetto Seven of Nine (poi Kubernetes).
Kubernetes: opensource community
Kubernetes è la piattaforma di orchestrazione dei container più utilizzata al mondo, spesso è descritta come “Linux of the cloud”. Fonte
Il primo commit del progetto Kubernetes risale al 6 giugno 2014. Da allora la diffusione di Kubernetes è sempre cresciuta e ha attratto molti contributori e finanziatori.
CNCF
Il 10 marzo 2016 il progetto Kubernetes entra a far parte della CNCF, la Cloud Native Computing Fondation.
La Cloud Native Container Foundation nasce nel 2015 e si occupa di mantenere molti progetti e standard aperti intorno al tema del cloud native e dell’orchestrazione dei servizi, per esempio:
Container Network Interface (CNI)
Prometheus - sistema di monitoraggio
Containerd - industry-standard container runtime
La CNCF conta attualmente oltre 450 membri, tra i quali si annoverano grandi fornitori di cloud pubblici, le più grandi aziende di sviluppo software, oltre a centinaia di startup innovative.
L’immagine seguente mostra solo alcuni dei molti membri della CNCF.
Che cos’è fornito col k8s?
Kubernetes (abbreviato spesso come k8s) fornisce queste funzionalità fondamentali per un sistema di orchestrazione:
Service discovery e load balancing
Storage orchestration
Automated rollouts e rollbacks
Automatic bin packing - distribuzione nel cluster del workload
Self-healing - gestione automatica dei fault
Secret e configuration management
I perché di Kubernetes
Gli sviluppatori della community del k8s hanno definito gli obiettivi principali del kubernetes:
velocità del deploy
permettere scalabilità del software e dei team
fornire un’astrazione sull’infrastruttura
migliorare l’efficienza
Velocità del deploy
Con molti (micro)servizi da aggiornare in breve tempo risulta molto importante avere una elevata velocità dei deploy.
Inoltre, con l’utilizzo di una progettazione del software Agile, è prevista una cadenza di rilascio molto frequente. In questo modo si riescono ad avere feedback immediati da parte degli utilizzatori senza le complicazioni dovute alla sovrapposizione di modifiche successive. Quindi l’utilizzo di una più elevata frequenza di rilascio si riducono le sovrapposizione di problematiche, visto che tipicamente le modifiche comprenderanno ben pochi cambiamenti.
La modalità tradizionale per l’aggiornamento dei componenti prevede tre fasi distinte:
stop del servizio
aggiornamento del servizio
riavvio del servizio.
Visto che i microservizi sono tendenzialmente molto collegati tra di loro, l’utilizzo di questa modalità per effettuare gli aggiornamenti porterebbe ad un disservizio dopo l’altro.
Quindi è necessario individuare un meccanismo diverso per effettuare queste operazioni a livello di cluster.
Come è ottenuta una maggiore velocità nel deploy?
immutability: i componenti creati non possono essere modificati e possono quindi essere re-instanziati altrove in caso di problemi, proprio perché non è mantenuto alcuno stato al proprio interno
declarative configuration: k8s si occupa di assicurare lo stato dichiarato come indicato, instanziando e ri-configurando i componenti ove necessario
self-healing system: k8s tenta di mantenere lo stato desiderato anche se qualche condizione cambiasse
Scalabilità del software
La scalabilità del software è uno degli altri obiettivi fondamentali del k8s ed è ottenuta:
incoraggiando il disaccoppiamento nelle applicazioni
componenti separati che comunicano tramite APIben definite per mezzo di servizi load-balanced
esecuzione in ambiente astratti condivisi e senza interferenze
utilizzo del formato standard dei container per poterlo avviare su qualsiasi macchina.
Scalabilità del team
Un altro aspetto della scalabilità è legato ai team di lavoro. È necessario separare gli aspetti critici legati alla consistenza delle applicazioni ed alla scalabilità della piattaforma su cui eseguirle. Questa suddivisione risulta particolarmente di aiuto specialmente per chi gestisce una grossa quantità di servizi o di server.
Perché?
gli application ops si affidano agli SLA forniti dalla piattaforma
gli orchestrator ops si occupano dello SLA
Le due tipologie di team, così suddivise, possono cambiare in numero in modo completamente indipendente. E anche se l’architettura a microservizi richiede molti container e molte interazioni tra questi, il numero delle persone incaricate del buon funzionamento del sistema sono potenzialmente più basse. In particolare l’orchestratore fornirà l’astrazione utile ad incalanare le evoluzioni del software.
Astrazione dell’architettura
L’astrazione della modalità di deploy delle applicazioni dall’hardware sottostante è particolarmente utile per poter ottenere l’elasticità nell’esecuzione delle nostre applicazioni. In particolare uno degli obiettivi è quello di poter aggiungere nuovi nodi al cluster senza la necessità che l’hardware sia uguale o simile a quello già presente.
L’astrazione dell’architettura è ottenuta disaccoppiando le immagini dei container dai server che li ospitano. Questa astrazione fornisce:
la possibilità di comporre i cluster con nodi eterogenei - con una potenziale riduzione dei costi.
la portabilità, avendo dei container che possono essere utilizzati su un altro cluster senza essere modificati.
Migliorare l’efficienza
Migliorando l’efficienza si possono ridurre notevolmente i costi di gestione dei server su cui far girare la nostre applicazioni.
L’ottimizzazione dell’utilizzo delle risorse dei server (worker node) è possibile grazie all’avvio di molti container sullo stesso server. I container utilizzando namespace separati possono lavorare senza alcuna interferenza reciproca.
Si ma quante risorse è possibile risparmiare?
Going from one service per VM to containers had saved the company 40% in AWS costs, and moving the containers to Kubernetes saved an additional 35%. Financial Times, KubeCon 2018
Architettura k8s
Effettuando il deploy di Kubernetes si ottiene un cluster. Il cluster è un insieme di server, chiamati nodi, che eseguono le applicazioni containerized gestite da Kubernetes. Un cluster ha inoltre almeno un nodo worker ed almeno un nodo master. In verità occorrono almeno tre nodi master per ragioni di failover ed alta affidabilità.
i nodi worker ospitano i pod che corrispondono ai componenti dell’applicazione.
i nodi master gestiscono i nodi worker ed i pod del cluster.
I componenti contenuti nei nodi master forniscono la control plane del cluster, alla quale sono assegnate le decisioni principali del cluster, come ad esempio lo scheduling: rilevando e rispondendo agli eventi del cluster, come per esempio l’avvio di un nuovo pod, se il campo deployment.replicas non è soddisfatto.
I componenti dei nodi master potrebbero essere eseguiti su uno qualsiasi dei nodi del cluster. Per semplicità vengono separati i compiti dei nodi worker da quelli dei master, evitando di avviare i container delle applicazioni sui nodi master.
I componenti dei nodi worker ospitano i pod avviati, fornendo l’ambiente di container runtime del cluster.
È possibile far comunicare i vari pod tramite una overlay network ottenuta tramite uno dei network provider disponibili per il k8s. È possibile ma non ci sono vincoli in merito.
L’immagine seguente mostra l’architettura generale di un cluster kubernetes.
Container image format e avvio dei container
Le immagini docker ci fornisco il filesystem di base per l’esecuzione dei container.
Le immagini si basano su un layered format che permette di ereditare i contenuti dai livelli più bassi e modificarli aggiungendo, cambiando o rimuovendo file. Può essere molto utile lavorare con delle immagini di container molto piccole, quindi senza dipendenze o layer inutili. In questo modo possono essere costruite, gestite e avviate più velocemente.
Oltre all’immagine già indicata, sono necessarie alcune altre informazioni per poter eseguire correttamente i container:
variabili d’ambiente, requisiti di CPU/RAM, indicazioni sul processo da eseguire e la sua command-line, le porte da esporre,…
Quindi è possibile fare il deploy di un container in Kubernetes? No, o almeno non direttamente.
Perchè no? Perché l’unità più piccola di calcolo di cui si può fare il deploy non è il container ma…
Pod
I pod sono la più piccole unità di computing in k8s. Permettono la co-locazione di molte app (container) in una singola unità atomica, schedulata su una singola macchina, e staticamente allocata su un certo nodo.
Ogni Pod viene eseguito nel proprio namespace e condivide:
file system, indirizzo IP e porta, lo stesso hostname, canali IPC per la comunicazione
Per esempio i container dentro un pod possono comunicare tra loro tramite localhost.
Perché Pod e non container direttamente
I Pod permettono un approccio di tipo “tutto o niente” per i container simbiotici (da mantenere sempre uniti), infatti un pod viene considerato avviato se tutti i suoi container sono running.
Si può effettuare il deploy di un container in k8s? Si, dentro un pod!
Quando sono presenti più container all’interno di un singolo Pod?
Ci sono alcuni casi dove è normale avere più container all’interno di un Pod:
quanto è impossibile per loro lavorare su macchine differenti (per esempio condivisione del filesystem o utilizzo di IPC)
quando uno di loro facilità la comunicazione con l’altro senza modificarlo (adapter)
quando uno di loro offre un supporto per l’altro (logging/monitoring)
quando uno di loro configura l’altro
Pod scheduling
Il pod scheduler è il componente presente nei nodi master che si occupa di garantire l’affidabilità dei servizi del cluster, distribuendo le repliche su più nodi.
Le repliche dei vari pod sono associate al nodo di avvio, quindi non sono mai spostate (immutability) e in caso in cui il nodo fisico non sia più disponibile i pod a lui associati, sono autmaticamente cancellati e rischedulati per l’avvio su uno degli altri nodi disponibili.
Il pod scheduler verifica lo stato dei pod e prende le proprie decisioni di scheduling attraverso due tipi di controlli:
- liveness probe
verifica che l’applicazione stia comportandosi come atteso, altrimenti lo riavvia
- readiness_probe
verifica che l’applicazione sia pronta per ricevere traffico - per esempio al primo avvio
Kubernetes Objects
I Kubernetes Objects sono entità persistenti all’interno del sistema k8s. Sono utilizzate per rappresentare lo stato del cluster ed in particolare possono descrivere:
quali applicazioni sono in esecuzione e su quali nodi
le risorse disponibili per queste applicazioni
le policy relative al comportamento delle applicazioni, come le restart policy, gli upgrade, la fault-tolerance
Gli oggetti rappresentano lo stato desiderato del cluster, quello che viene chiamato record of intent. Una volta creato un oggetto il k8s eseguirà costantemente le operazioni necessarie per assicurare che l’oggetto sia presente nel cluster e funzioni come specificato.
Gli oggetti possono essere creati/modificati/cancellati attraverso l’API k8s.
kubectl è la CLI che effettua le chiamate alla Kubernetes API.
Esempio Deployment
Nell’esempio sottostante viene utilizzato il kubectl in combinazione con un file yaml per definire e creare un oggetto di tipo deployment che indica al k8s di avviare due pod ognuno dei quali con all’interno un container _ nginx:1.17.5_ in ascolto sulla porta 80.
$ kubectl apply -f application.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # indica di eseguire 2 pod che corrispondono al template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.5
ports:
- containerPort: 80