Kubernetes è un sistema molto articolato in cui i comandi vengono impartiti mediante API passando, per lo più, dal client kubectl
già presentato nella lezione precedente.
Una delle prime necessità che il neofita in Kubernetes vorrà soddisfare sarà quella di mettere al lavoro in questa piattaforma uno o più container Docker. Ciò viene portato a termine grazie ad un oggetto definito nelle API Kubernetes che prende il nome di Pod.
Se volessimo trovare una definizione più pratica e succinta possibile di questa componente potremmo dire che si tratta di un gruppo di container (ma anche uno solo) in esecuzione su Kubernetes.
Comprendere cosa sono i Pod e come lavorano è proprio quello che faremo in questa lezione ma prima dobbiamo aprire una parentesi su uno degli aspetti più importanti in assoluto nella loro "filosofia" ovvero la configurazione dichiarativa.
Configurazione dichiarativa
Parlando in generale, quando vogliamo attivare una funzionalità o eseguire un'operazione su una piattaforma agiamo spesso in modalità imperativa ovvero chiamiamo un certo comando (da riga di comando, via API etc.) e attendiamo fino a vedere la restituzione del risultato.
Ad esempio, abbiamo un’immagine Docker, vogliamo eseguirla, utilizziamo il comando docker run
per lanciare il container. Questo è un atteggiamento imperativo ed è qualcosa che facciamo spesso: un po' perché le piattaforme che utilizziamo funzionano proprio così, un po' perché da "tradizione" ci viene spontaneo.
In Kubernetes, si può utilizzare una modalità imperativa ma quella più in sintonia con le finalità di questa piattaforma è la configurazione dichiarativa.
In questo stile, non eseguiamo comandi per ottenere i risultati voluti ma scriviamo un file di configurazione che descrive lo stato del sistema che desideriamo. Tornando all'esempio di prima, se volessimo tre container in esecuzione potremmo eseguire tre volte il comando docker run
ma se ne fallisse uno, o noi decidessimo di chiuderlo, cosa succederebbe?
Semplicemente perderemmo un container che ripartirebbe solo ad un nostro nuovo comando imperativo. Nella configurazione dichiarativa di Kubernetes, invece, noi scriviamo un file di configurazione (impareremo a farlo più avanti) in cui dichiariamo che il nostro "stato desiderato" consiste in tre container running. Quando vorremo che tale configurazione sia applicata, Kubernetes non farà altro che metterla in pratica e per tutto il tempo continuerà a monitorare lo stato attuale del sistema per essere sicuro che coincida sempre con quello desiderato (tre container in esecuzione).
Qualora un container dovesse scomparire lo riattiverebbe ma viceversa non permetterebbe nemmeno la comparsa di un ulteriore elemento che porterebbe in totale il numero di container attivi a quattro.
Questa distinzione sarà sempre più chiara man mano che procederemo con i nostri studi, dove vedremo come ogni componente possa essere gestita mediante configurazione dichiarativa.
Il nostro primo Pod: avvio imperativo
Iniziamo a mettere il nostro primo container al lavoro su Kubernetes il che richiede, come detto, l'avvio di un Pod. L'applicazione attivata sarà un server web NGINX ma, al momento, non ci preoccuperemo di contattarlo, ci accontenteremo di vedere come i container possano essere lanciati in Kubernetes sia in modalità imperativa che dichiarativa.
Inizieremo in modalità imperativa, approccio estremamente veloce e pratico ma non la best practise su questa piattaforma. Utilizzeremo il comando kubectl run
e per farlo avremo bisogno di:
- un'installazione Kubernetes ma, per avere un ambiente di sperimentazione senza un reale cluster, ci basterà
minikube
, dall'allestimento sicuramente più immediato; - il client
kubectl
.
Tra i vari modi di avere un ambiente operativo a disposizione, noi scegliamo di usare la Cloud Shell della Google Cloud Platform e (dopo aver avviato il cluster di sperimentazione con minikube start
) digitiamo:
$ kubectl run server-web --image=nginx
Questo sarà sufficiente per avere avviato un container con il server Web NGINX all'interno di un Pod. Possiamo vedere se il tutto ha funzionato con:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
server-web 1/1 Running 0 14s
che, come vediamo, mostra un container Running
su uno richiesto (1/1
).
Si faccia attenzione perché se avessimo richiesto la lista dei Pod disponibili troppo presto avremmo potuto vedere il Pod in preparazione con ancora nessun container in esecuzione su uno richiesto (0/1
). Ad esempio, avremmo potuto vedere qualcosa del genere:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
server-web 0/1 ContainerCreating 0 8s
dove si sarebbe trovato lo stato del Pod impostato a ContainerCreating
.
Ci abitueremo con il tempo a notare lo stato delle componenti in Kubernetes e a non preoccuparci di situazioni simili. Possiamo cancellare il Pod ormai in esecuzione con:
$ kubectl delete pods/server-web
pod "server-web" deleted
Il nostro primo Pod: configurazione dichiarativa
Conosciamo ora la configurazione dichiarativa, l'approccio fondamentale in Kubernetes. Dovremmo preparare un file nel formato YAML di questo tipo:
apiVersion: v1
kind: Pod
metadata:
name: server-web-dichiarativo
spec:
containers:
- image: nginx
name: nginx-instance
Si tratta della versione più essenziale possibile di un file di configurazione YAML ma ne mostra la struttura di base: versione delle API, tipologia dell'oggetto che stiamo dichiarando (un Pod in questo caso), metadati e la sezione spec
in cui vengono strutturati i dettagli della componente che stiamo definendo.
Una volta che la configurazione è pronta, potremo lanciarla con il comando kubectl apply
:
$ kubectl apply -f server-web.yaml
pod/server-web-dichiarativo created
dando vita al Pod di nome server-web-dichiarativo
come specificato nei metadati del file YAML. Dopo di ciò, il Pod verrà avviato e potremo averne anche in questo caso la prova con kubectl get pods
. In pratica, avremo ottenuto un Pod in esecuzione ma questa volta sotto la gestione ed il monitoraggio di Kubernetes.
Nelle prossime lezioni, affronteremo nuove componenti e scopriremo come interagire con i container caricati nei Pod.