Dietro le quinte di Kubernetes

Chiunque abbia seguito un tutorial su Kubernetes ha lanciato il comando kubectl create deployment epsilon--bootcamp --image=nginx --replicas=3  e ha potuto ammirare soddisfatto il pod in esecuzione all’interno del cluster Kubernetes.
Con questo comando stiamo dicendo al cluster “Hey K8s, vorrei un deployment chiamato epsilon-bootcamp, al cui interno ci sia un pod con 3 repliche e che i container all’interno dei pod siano creati a partire dall’immagine ufficiale di nginx”.
A questo punto alcuni hanno cambiato la descrizione del profilo Linkedin in “Kubernetes Tech Lead Engineer”, altri hanno cominciato ad approfondire questo strumento. Probabilmente, chi non si è fermato in superficie, sta ancora scavando.
Cosa c’è dietro Kubernetes? Quale “magia” ha fatto arrivare quel pod su quel nodo? E perché proprio quel nodo? Ma chi stiamo contattando utilizzando i comandi di kubectl?

In questo articolo daremo una panoramica di quelle che sono gli attori coinvolti affinché la magia funzioni.

Saranno coinvolti i seguenti componenti:

  • Api Server: ci permette di interagire con il cluster tramite chiamate API. È l’unico componente che scrive su etcd e a cui gli altri componenti si rivolgono quando hanno svolto il loro compito.
  • Scheduler: Controlla i pod appena creati che non hanno un nodo assegnato e, dopo averlo identificati, assegna loro il nodo in base alla quantità di risorse di cui il pod ha bisogno. I fattori presi in considerazione nell’individuare un nodo a cui assegnare l’esecuzione di un pod includono la richiesta di risorse del pod stesso e degli altri workload presenti nel sistema, i vincoli dell’hardware/software/policy, le indicazioni di affinity e di anti-affinity, i requisiti relativi alla disponibilità di dati/volumi e le interferenze tra diversi workload.
  • Controller Manager: Esegue diversi control loops, uno per ogni tipo di risorsa che è possibile creare all’interno del cluster. Si occupa di mantenere allineato lo stato di etcd con quello delle risorse che si trovano all’interno del cluster. Nel caso in cui questi due stati non combacino, lo scheduler sarà responsabile di far convergere lo stato del cluster verso quello desiderato dall’utente
  • etcd: è un archivio dati di tipo chiave-valore. Serve a mantenere lo stato del cluster
  • Kubelet: un agent che è eseguito su ogni nodo del cluster. Si assicura che i container siano eseguiti correttamente all’interno di un pod e comunica direttamente con l’api-server
  • Kubectl: è il principale tool utilizzato per interagire con il cluster Kubernetes. Lo fa autenticandosi sul control plane ed effettuando chiamate API di vario tipo

Andremo a creare le seguenti risorse

  1. Pods: Il pod è l’unità atomica di Kubernetes. Possiamo vederlo come una raccolta di uno o più container. Si tratta di un’unità effimera che può essere distrutta e ricreata in base allo stato che viene dichiarato.
  2. Replica Set: Ha lo scopo di mantenere un set stabile di pod in esecuzione in qualsiasi momento. Viene utilizzato per garantire la disponibilità di un numero specifico di Pod identici.
  3. Deployment: oggetto che fornisce aggiornamenti dichiarativi alle applicazioni. Consente di descrivere il ciclo di vita di un’applicazione, ad esempio quali immagini utilizzare per l’app, il numero di pod presenti e il modo in cui devono essere aggiornati.

Architecture Overview

diagram

Chiariti quindi quali sono i giocatori in campo, proviamo a ripercorrere gli step che ci portano dall’esecuzione del nostro comando fino all’effettivo avvio del container all’interno del cluster.

1. Lanciamo il comando

kubectl create deployment epsilon-bootcamp –image=nginx –replicas=3

2. Kubectl si autentica sul cluster

Hai presente il file in .kube/config?
Ecco, quello è il file in cui si trova il **contesto (context)**.
In Kubernetes un contesto è l’insieme dei parametri di accesso che contiene le informazioni relative al cluster Kubernetes, utente e namespace. Possiamo vedere il context come la configurazione che utilizziamo per accedere ad un cluster.

3. Kubectl effettua le chiamate API all’Api-Server

In questa fase il tool kubectl tradurrà il nostro comando in un’API di Kubernetes. Un concetto fondamentale da capire quando si lavora con Kubernetes è che tutto è un’API. Anche quando applichiamo un manifest kubectl lo traduce in una chimata API e contatta l’api-server.
Per esempio, supponendo di voler avere una lista di tutti i namespace presenti all’interno del cluster, possiamo lanciare il comando kubectl get namespaces o interrogare direttamente l’api-server con la chiamata http://[control-plane-ip]:[PORT]/api/v1/namespaces (in realtà questa API ritorna informazioni più dettagliate rispetto a quelle che avremmo lanciando il solo comando kubectl per avere la lista dei namespace).
Trovi informazioni più dettagliate sulle API messe a disposizione da Kubernetes a questo link.

4. L’Api-Server valida il manifest

Dopo esserci autenticati sull’api server quest’ultimo validerà il manifest che gli abbiamo mandato. La risorsa che stiamo creando potrebbe essere già presente sul cluster e in questo caso il nostro YAML Guy riceverà un messaggio di errore, diversamente si passa allo step successivo.

5. L’Api-Server aggiorna lo stato di etcd

Validato il manifest, lo stato desiderato dall’utente viene scritto in etcd e questo mette in moto una serie di componenti all’interno del cluster.
A questo punto la connessione tra il nostro client e l’api-server termina, abbiamo fatto tutto quello che c’era da fare. Da qui in poi sarà Kubernetes a fare il resto del lavoro.

6. Controller, it’s show time!

Il controller manager ha una serie di loop (uno per ogni risorsa che è possibile creare nel cluster) e quello adibito al controllo dei deployments nota che lo stato desiderato dall’utente (che ha appena aggiunto un deployment) non combacia con lo stato attuale del cluster.
In questo caso specifico il control manager dei deployments andrà a creare un risorsa di tipo Replica Set.
Per farlo comunicherà con l’API server e quest’ultimo aggiornerà lo stato di etcd aggiungendo quanto chiesto dal controller manager.
Lo stato di ectd è stato nuovamente aggiornato e il controller dei Replica Set si accorge che lo stato di ectd non combacia con quello attuale del cluster. Comunicherà quindi all’API server di aggiungere i pod richiesti dal replica set e l’api-server aggiornerà nuovamente lo stato di etcd con i 3 pods.
Avete mai visto la scritta “Pending” nello stato quando lanciate un kubectl get pods? Ecco, quando un pod risulta pending è perché lo stato di ectd è stato aggiornato quindi il cluster sa di dover creare quel pod.

7. Scheduler

A questo punto lo scheduler nota che ci sono dei pod con status pending e, in base alle caratteristiche che hanno, li assegnerà a determinati nodi.
Nel nostro caso sappiamo per certo che quei nodi non potranno essere schedulati sul control plane. Quello che lo scheduler farà sarà cercare di tenere il carico dei nodi bilanciato

8. Kubelet

Una volta che un pod è assegnato ad un nodo, il compito di portarlo in esecuzione passa alla kubelet del nodo al quale è stato assegnato.
Kubelet, agente installato su ogni nodo, sa di dover creare i pod richiesti dallo scheduler. Comunicherà quindi all’api server che i pod stanno per essere creati.
In realtà la Kubelet fa molto più! Ma questo lo vedremo nei prossimi articoli 🙂

Se quest'articolo fosse una GIF...

Meme

k8s-meme