Kubernetes · 26 min read · Nov 03, 2025
Componenti principali di un Cluster Kubernetes

Kubernetes è una piattaforma open source per la gestione di carichi di lavoro e servizi containerizzati che facilita la configurazione dichiarativa e l’automazione. Il nome Kubernetes ha origine dal greco, significando timoniere o pilota. È portabile ed estensibile e ha un ecosistema in rapida crescita. I servizi e gli strumenti di Kubernetes sono ampiamente disponibili.
In questo articolo, daremo un’occhiata a una panoramica dei principali componenti di Kubernetes, da cosa è composto ogni container, a come un container in un pod viene distribuito e programmato tra ciascuno dei lavoratori. È cruciale comprendere i dettagli completi del cluster Kubernetes per poter distribuire e progettare una soluzione basata su Kubernetes come orchestratore per applicazioni containerizzate.
Ecco un breve riepilogo delle cose che tratteremo in questo articolo:
- Componenti del pannello di controllo
- Componenti dei lavoratori di Kubernetes
- Pods come blocchi di base
- Servizi Kubernetes, bilanciatori di carico e controller Ingress
- Distribuzioni Kubernetes e Daemon Sets
- Archiviazione persistente in Kubernetes
Il Piano di Controllo di Kubernetes
I nodi master di Kubernetes sono dove risiedono i servizi principali del piano di controllo; non tutti i servizi devono risiedere sullo stesso nodo; tuttavia, per centralizzazione e praticità, spesso vengono distribuiti in questo modo. Questo solleva ovviamente domande sulla disponibilità dei servizi; tuttavia, possono essere facilmente superate avendo diversi nodi e fornendo richieste di bilanciamento del carico per ottenere un insieme di nodi master altamente disponibili.
I nodi master sono composti da quattro servizi di base:
- Il kube-apiserver
- Il kube-scheduler
- Il kube-controller-manager
- Il database etcd
I nodi master possono essere eseguiti su server bare metal, macchine virtuali o un cloud privato o pubblico, ma non è consigliato eseguire carichi di lavoro containerizzati su di essi. Vedremo di più su questo più avanti.
Il seguente diagramma mostra i componenti dei nodi master di Kubernetes:

Il kube-apiserver
Il server API è ciò che collega tutto insieme. È l’API REST frontend del cluster che riceve manifesti per creare, aggiornare e eliminare oggetti API come servizi, pod, Ingress e altri.
Il kube-apiserver è l’unico servizio con cui dovremmo comunicare; è anche l’unico che scrive e parla con il database etcd per registrare lo stato del cluster. Con il comando kubectl, invieremo comandi per interagire con esso. Questo sarà il nostro coltellino svizzero quando si tratta di Kubernetes.
Il kube-controller-manager
Il demone kube-controller-manager, in breve, è un insieme di loop di controllo infiniti che vengono forniti per semplicità in un unico binario. Osserva lo stato desiderato definito del cluster e si assicura che venga raggiunto e soddisfatto muovendo tutti i pezzi necessari per ottenerlo. Il kube-controller-manager non è solo un controller; contiene diversi loop che osservano diversi componenti nel cluster. Alcuni di essi sono il controller dei servizi, il controller dei namespace, il controller degli account di servizio e molti altri. Puoi trovare ogni controller e la sua definizione nel repository GitHub di Kubernetes: https://github.com/kubernetes/kubernetes/tree/master/pkg/controller.
Il kube-scheduler
Il kube-scheduler programma i tuoi pod appena creati su nodi con spazio sufficiente per soddisfare le esigenze di risorse dei pod. Fondamentalmente, ascolta il kube-apiserver e il kube-controller-manager per i nuovi pod creati che vengono messi in una coda e poi programmati su un nodo disponibile dal scheduler. La definizione del kube-scheduler può essere trovata qui: https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler.
Oltre alle risorse di calcolo, il kube-scheduler legge anche le regole di affinità e anti-affinità dei nodi per scoprire se un nodo può o non può eseguire quel pod.
Il database etcd
Il database etcd è un archivio chiave-valore molto affidabile e consistente utilizzato per memorizzare lo stato del cluster Kubernetes. Contiene lo stato attuale dei pod su cui il nodo è in esecuzione, quanti nodi ha attualmente il cluster, qual è lo stato di quei nodi, quanti replica di distribuzione sono in esecuzione, nomi dei servizi e altri.
Come abbiamo accennato prima, solo il kube-apiserver parla con il database etcd. Se il kube-controller-manager ha bisogno di controllare lo stato del cluster, passerà attraverso il server API per ottenere lo stato dal database etcd, invece di interrogare direttamente l’archivio etcd. Lo stesso vale per il kube-scheduler se il scheduler deve far sapere che un pod è stato fermato o allocato a un altro nodo; informerà il server API, e il server API memorizzerà lo stato attuale nel database etcd.
Con etcd, abbiamo coperto tutti i principali componenti per i nostri nodi master di Kubernetes in modo da essere pronti a gestire il nostro cluster. Ma un cluster non è composto solo da master; abbiamo ancora bisogno dei nodi che eseguiranno il lavoro pesante eseguendo le nostre applicazioni.
Nodi Lavoratori di Kubernetes
I nodi lavoratori che eseguono questo compito in Kubernetes sono semplicemente chiamati nodi. In precedenza, intorno al 2014, erano chiamati minions, ma questo termine è stato successivamente sostituito con semplicemente nodi, poiché il nome era confuso con le terminologie di Salt e faceva pensare alla gente che Salt stesse giocando un ruolo importante in Kubernetes.
Questi nodi sono l’unico posto in cui eseguirai carichi di lavoro, poiché non è consigliato avere container o carichi sui nodi master, poiché devono essere disponibili per gestire l’intero cluster. I nodi sono molto semplici in termini di componenti; richiedono solo tre servizi per svolgere il loro compito:
- Kubelet
- Kube-proxy
- Runtime del container
Esploriamo questi tre componenti in modo un po’ più approfondito.
Il kubelet
Il kubelet è un componente Kubernetes a basso livello ed uno dei più importanti dopo il kube-apiserver; entrambi questi componenti sono essenziali per il provisioning di pod/container nel cluster. Il kubelet è un servizio che gira sui nodi Kubernetes e ascolta il server API per la creazione di pod. Il kubelet è responsabile solo dell’avvio/arresto e dell’assicurarsi che i container nei pod siano sani; il kubelet non sarà in grado di gestire alcun container che non è stato creato da esso.
Il kubelet raggiunge gli obiettivi parlando con il runtime del container tramite container runtime interface (CRI). Il CRI fornisce la possibilità di collegare il kubelet tramite un client gRPC, che è in grado di comunicare con diversi runtime di container. Come abbiamo accennato in precedenza, Kubernetes supporta più runtime di container per distribuire container, e questo è il modo in cui raggiunge un supporto così diversificato per diversi motori.
Puoi controllare il codice sorgente del kubelet tramite https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet.
Il kube-proxy
Il kube-proxy è un servizio che risiede su ogni nodo del cluster ed è quello che rende possibili le comunicazioni tra pod, container e nodi. Questo servizio osserva il kube-apiserver per le modifiche ai servizi definiti (il servizio è una sorta di bilanciatore di carico logico in Kubernetes; approfondiremo i servizi più avanti in questo articolo) e mantiene la rete aggiornata tramite regole iptables che inoltrano il traffico ai corretti endpoint. Il kube-proxy imposta anche regole in iptables che fanno bilanciamento del carico casuale tra i pod dietro un servizio.
Ecco un esempio di una regola iptables creata dal kube-proxy:
-A KUBE-SERVICES -d 10.0.162.61/32 -p tcp -m comment –comment “default/example: has no endpoints” -m tcp –dport 80 -j REJECT –reject-with icmp-port-unreachable
Nota che questo è un servizio senza endpoint (nessun pod dietro di esso).
Runtime del container
Per poter avviare container, abbiamo bisogno di un runtime del container. Questo è il motore di base che creerà i container nel kernel dei nodi affinché i nostri pod possano essere eseguiti. Il kubelet parlerà con questo runtime e avvierà o fermerà i nostri container su richiesta.
Attualmente, Kubernetes supporta qualsiasi runtime di container conforme a OCI, come Docker, rkt, runc, runsc, e così via.
Puoi fare riferimento a questo https://github.com/opencontainers/runtime-spec per saperne di più su tutte le specifiche dalla pagina Git-Hub di OCI.
Ora che abbiamo esplorato tutti i componenti principali che formano un cluster, diamo un’occhiata a cosa può essere fatto con essi e come Kubernetes ci aiuterà a orchestrare e gestire le nostre applicazioni containerizzate.
Oggetti Kubernetes
Gli oggetti Kubernetes sono esattamente questo: sono oggetti logici persistenti o astrazioni che rappresenteranno lo stato del tuo cluster. Sei tu a dover dire a Kubernetes qual è il tuo stato desiderato di quell’oggetto affinché possa lavorare per mantenerlo e assicurarsi che l’oggetto esista.
Per creare un oggetto, ci sono due cose che deve avere: uno stato e la sua spec. Lo stato è fornito da Kubernetes, ed è lo stato attuale dell’oggetto. Kubernetes gestirà e aggiornerà quello stato secondo necessità per essere in conformità con il tuo stato desiderato. Il campo spec, d’altra parte, è ciò che fornisci a Kubernetes, ed è ciò che gli dici di descrivere l’oggetto che desideri. Ad esempio, l’immagine che vuoi che il container stia eseguendo, il numero di container di quell’immagine che vuoi eseguire, e così via.
Ogni oggetto ha campi spec specifici per il tipo di compito che svolgono, e fornirai queste specifiche in un file YAML che viene inviato al kube-apiserver con kubectl, che lo trasforma in JSON e lo invia come richiesta API. Approfondiremo ciascun oggetto e i suoi campi spec più avanti in questo articolo.
Ecco un esempio di un YAML che è stato inviato a kubectl:
cat << EOF | kubectl create -f -kind: ServiceapiVersion: v1metadata: Name: frontend-servicespec: selector: web: frontend ports: - protocol: TCP port: 80 targetPort: 9256EOF
I campi di base della definizione dell’oggetto sono i primissimi, e questi non varieranno da oggetto a oggetto e sono molto autoesplicativi. Diamo un’occhiata veloce a loro:
- kind: Il campo kind dice a Kubernetes che tipo di oggetto stai definendo: un pod, un servizio, una distribuzione, e così via
- apiVersion: Poiché Kubernetes supporta più versioni API, dobbiamo specificare un percorso API REST a cui vogliamo inviare la nostra definizione
- metadata: Questo è un campo annidato, il che significa che hai diversi altri sotto-campi per i metadati, dove scriverai definizioni di base come il nome del tuo oggetto, assegnandolo a uno specifico namespace, e anche etichettandolo per relazionare il tuo oggetto ad altri oggetti Kubernetes
Quindi, abbiamo ora esaminato i campi più utilizzati e i loro contenuti; puoi saperne di più sulle convenzioni API di Kubernetes su https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md
Alcuni dei campi dell’oggetto possono essere successivamente modificati dopo che l’oggetto è stato creato, ma ciò dipenderà dall’oggetto e dal campo che desideri modificare.
Di seguito è riportato un breve elenco dei vari oggetti Kubernetes che puoi creare:
- Pod
- Volume
- Servizio
- Distribuzione
- Ingress
- Segreto
- ConfigMap
E ce ne sono molti altri.
Diamo un’occhiata più da vicino a ciascuno di questi elementi.
Pods – la base di Kubernetes
I pod sono gli oggetti più basilari in Kubernetes e anche i più importanti. Tutto ruota attorno a loro; possiamo dire che Kubernetes è per i pod! Tutti gli altri oggetti sono qui per servirli, e tutti i compiti che svolgono sono per far sì che i pod raggiungano il tuo stato desiderato.
Quindi, cos’è un pod e perché i pod sono così importanti?
Un pod è un oggetto logico che esegue uno o più container insieme nello stesso namespace di rete, la stessa comunicazione inter-processo (IPC) e, a volte, a seconda della versione di Kubernetes, lo stesso namespace di ID processo (PID). Questo perché sono quelli che eseguiranno i nostri container e quindi saranno al centro dell’attenzione. L’intero scopo di Kubernetes è essere un orchestratore di container, e con i pod rendiamo possibile l’orchestrazione.
Come abbiamo accennato prima, i container nello stesso pod vivono in una “bolla” dove possono parlare tra loro tramite localhost, poiché sono locali l’uno all’altro. Un container in un pod ha lo stesso indirizzo IP dell’altro container perché condividono un namespace di rete, ma nella maggior parte dei casi, eseguirai su base uno a uno, cioè un singolo container per pod. Più container per pod vengono utilizzati solo in scenari molto specifici, come quando un’applicazione richiede un aiuto come un data pusher o un proxy che deve comunicare in modo rapido e resiliente con l’applicazione principale.
Il modo in cui definisci un pod è lo stesso modo in cui lo faresti per qualsiasi altro oggetto Kubernetes: tramite un YAML che contiene tutte le specifiche e le definizioni del pod:
kind: PodapiVersion: v1metadata:name: hello-podlabels: hello: podspec: containers: - name: hello-container image: alpine args: - echo - “Hello World”
Esaminiamo le definizioni di base del pod necessarie sotto il campo spec per creare il nostro pod:
- Containers: Un container è un array; quindi, abbiamo un insieme di diversi sotto-campi sotto di esso. Fondamentalmente, è ciò che definisce i container che verranno eseguiti nel pod. Possiamo specificare un nome per il container, l’immagine da cui verrà generato e gli argomenti o il comando che abbiamo bisogno che esegua. La differenza tra argomenti e comandi è la stessa differenza tra CMD e ENTRYPOINT. Tieni presente che tutti i campi che abbiamo appena esaminato sono per l’array dei container. Non fanno parte direttamente della spec del pod.
- restartPolicy: Questo campo è esattamente questo: dice a Kubernetes cosa fare con un container, e si applica a tutti i container nel pod nel caso di un codice di uscita zero o non zero. Puoi scegliere tra le due opzioni, Never, OnFailure o Always. Always sarà il valore predefinito nel caso in cui non venga definita una restartPolicy.
Queste sono le specifiche più basilari che dichiarerai su un pod; altre specifiche richiederanno che tu abbia un po’ più di conoscenza su come usarle e come interagiscono con vari altri oggetti Kubernetes. Le rivedremo più avanti in questo articolo; alcune di esse sono le seguenti:
- Volume
- Env
- Ports
- dnsPolicy
- initContainers
- nodeSelector
- Limiti e richieste delle risorse
Per visualizzare i pod attualmente in esecuzione nel tuo cluster, puoi eseguire kubectl get pods:
dsala@MININT-IB3HUA8:~$ kubectl get podsNAME READY STATUS RESTARTS AGEbusybox 1/1 Running 120 5d
In alternativa, puoi eseguire kubectl describe pods senza specificare alcun pod. Questo stamperà una descrizione di ogni pod in esecuzione nel cluster. In questo caso, sarà solo il pod busybox, poiché è l’unico attualmente in esecuzione:
dsala@MININT-IB3HUA8:~$ kubectl describe podsName: busyboxNamespace: defaultPriority: 0PriorityClassName:
I pod sono mortali. Una volta che muoiono o vengono eliminati, non possono essere recuperati. Il loro IP e i container che erano in esecuzione su di essi saranno scomparsi; sono totalmente effimeri. I dati sui pod che sono montati come volume possono o meno sopravvivere, a seconda di come li hai impostati. Se i nostri pod muoiono e li perdiamo, come possiamo garantire che tutti i nostri microservizi siano in esecuzione? Bene, le distribuzioni sono la risposta.
Distribuzioni
I pod da soli non sono molto utili poiché non è molto efficiente avere più di una singola istanza della nostra applicazione in esecuzione in un singolo pod. Provisionare centinaia di copie della nostra applicazione su diversi pod senza avere un metodo per cercarli tutti diventerà rapidamente ingestibile.
È qui che entrano in gioco le distribuzioni. Con le distribuzioni, possiamo gestire i nostri pod con un controller. Questo ci consente non solo di decidere quanti vogliamo eseguire, ma possiamo anche gestire aggiornamenti cambiando la versione dell’immagine o l’immagine stessa che i nostri container stanno eseguendo. Le distribuzioni sono ciò con cui lavorerai la maggior parte del tempo. Con le distribuzioni, così come con i pod e qualsiasi altro oggetto che abbiamo menzionato prima, hanno la loro definizione all’interno di un file YAML:
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: deployment: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
Iniziamo a esplorare la loro definizione.
All’inizio del YAML, abbiamo campi più generali, come apiVersion, kind e metadata. Ma sotto spec è dove troveremo le opzioni specifiche per questo oggetto API.
Sotto spec, possiamo aggiungere i seguenti campi:
Selector: Con il campo Selector, la distribuzione saprà quali pod mirare quando vengono applicate modifiche. Ci sono due campi che utilizzerai sotto il selettore: matchLabels e matchExpressions. Con matchLabels, il selettore utilizzerà le etichette dei pod (coppie chiave/valore). È importante notare che tutte le etichette che specifichi qui saranno ANDed. Questo significa che il pod richiederà di avere tutte le etichette che specifichi sotto matchLabels.
Replicas: Questo indicherà il numero di pod che la distribuzione deve mantenere in esecuzione tramite il controller di replicazione; ad esempio, se specifichi tre repliche, e uno dei pod muore, il controller di replicazione osserverà la spec delle repliche come stato desiderato e informerà il scheduler di programmare un nuovo pod, poiché lo stato attuale è ora 2 poiché il pod è morto.
RevisionHistoryLimit: Ogni volta che apporti una modifica alla distribuzione, questa modifica viene salvata come una revisione della distribuzione, che puoi successivamente ripristinare a quello stato precedente o mantenere un record di ciò che è stato cambiato. Puoi consultare la tua cronologia con kubectl rollout history deployment/
Strategy: Questo ti permetterà di decidere come vuoi gestire qualsiasi aggiornamento o scalabilità orizzontale dei pod. Per sovrascrivere il predefinito, che è rollingUpdate, devi scrivere la chiave type, dove puoi scegliere tra due valori: recreate o rollingUpdate.
Mentre recreate è un modo veloce per aggiornare la tua distribuzione, eliminerà tutti i pod e li sostituirà con nuovi, ma implica che dovrai tenere in considerazione che ci sarà un’interruzione del sistema per questo tipo di strategia. Il rollingUpdate, d’altra parte, è più fluido e lento ed è ideale per applicazioni stateful che possono riequilibrare i loro dati. Il rollingUpdate apre la porta a due ulteriori campi, che sono maxSurge e maxUnavailable.
Il primo sarà quanti pod sopra il numero totale desideri quando esegui un aggiornamento; ad esempio, una distribuzione con 100 pod e un 20% maxSurge crescerà fino a un massimo di 120 pod durante l’aggiornamento. L’opzione successiva ti permetterà di selezionare quanti pod in percentuale sei disposto a uccidere per sostituirli con nuovi in uno scenario di 100 pod. Nei casi in cui ci sia un 20% maxUnavailable, solo 20 pod saranno uccisi e sostituiti con nuovi prima di continuare a sostituire il resto della distribuzione.
Template: Questo è solo un campo spec di pod annidato dove includerai tutte le specifiche e i metadati dei pod che la distribuzione andrà a gestire.
Abbiamo visto che, con le distribuzioni, gestiamo i nostri pod, e ci aiutano a mantenerli in uno stato che desideriamo. Tutti questi pod sono ancora in qualcosa chiamato rete del cluster, che è una rete chiusa in cui solo i componenti del cluster Kubernetes possono parlare tra loro, avendo anche il proprio insieme di intervalli IP. Come parliamo con i nostri pod dall’esterno? Come raggiungiamo la nostra applicazione? È qui che entrano in gioco i servizi.
Servizi:
Il nome servizio non descrive completamente cosa fanno effettivamente i servizi in Kubernetes. I servizi Kubernetes sono ciò che instrada il traffico ai nostri pod. Possiamo dire che i servizi sono ciò che lega i pod insieme.
Immaginiamo di avere un’applicazione tipica di tipo frontend/backend in cui i nostri pod frontend parlano con quelli backend tramite gli indirizzi IP dei pod. Se un pod nel backend muore, perdiamo comunicazione con il nostro backend. Questo non è solo perché il nuovo pod non avrà lo stesso indirizzo IP del pod che è morto, ma ora dobbiamo anche riconfigurare la nostra app per utilizzare il nuovo indirizzo IP. Questo problema e problemi simili sono risolti con i servizi.
Un servizio è un oggetto logico che dice al kube-proxy di creare regole iptables basate su quali pod sono dietro il servizio. I servizi configurano i loro endpoint, che è il modo in cui i pod dietro un servizio vengono chiamati, allo stesso modo in cui le distribuzioni sanno quali pod controllare, il campo selettore e le etichette dei pod.
Questo diagramma ti mostra come i servizi utilizzano le etichette per gestire il traffico:

I servizi non solo faranno sì che kube-proxy crei regole per instradare il traffico; attiveranno anche qualcosa chiamato kube-dns.
Kube-dns è un insieme di pod con contenitori SkyDNS che girano nel cluster che forniscono un server DNS e un forwarder, che creerà record per servizi e talvolta pod per facilità d’uso. Ogni volta che crei un servizio, verrà creato un record DNS che punta all’indirizzo IP interno del cluster del servizio con la forma service-name.namespace.svc.cluster.local. Puoi saperne di più sulle specifiche DNS di Kubernetes qui: https://github.com/kubernetes/dns/blob/master/docs/specification.md.
Tornando al nostro esempio, ora dovremo solo configurare la nostra applicazione per parlare con il nome di dominio completamente qualificato (FQDN) del servizio per parlare con i nostri pod backend. In questo modo, non importerà quale indirizzo IP hanno i pod e i servizi. Se un pod dietro il servizio muore, il servizio si occuperà di tutto utilizzando il record A, poiché saremo in grado di dire al nostro frontend di instradare tutto il traffico verso my-svc. La logica del servizio si occuperà di tutto il resto.
Ci sono diversi tipi di servizio che puoi creare ogni volta che dichiari l’oggetto da creare in Kubernetes. Esaminiamoli per vedere quale sarà il più adatto per il tipo di lavoro di cui abbiamo bisogno:
ClusterIP: Questo è il servizio predefinito. Ogni volta che crei un servizio ClusterIP, creerà un servizio con un indirizzo IP interno al cluster che sarà instradabile solo all’interno del cluster Kubernetes. Questo tipo è ideale per i pod che devono solo parlare tra loro e non uscire dal cluster.
NodePort: Quando crei questo tipo di servizio, per impostazione predefinita verrà allocata una porta casuale da 30000 a 32767 per inoltrare il traffico agli endpoint dei pod del servizio. Puoi sovrascrivere questo comportamento specificando una porta nodo nell’array delle porte. Una volta definito, sarai in grado di accedere ai tuoi pod tramite
LoadBalancer: La maggior parte delle volte, eseguirai Kubernetes su un fornitore di cloud. Il tipo LoadBalancer è ideale per queste situazioni, poiché sarai in grado di allocare indirizzi IP pubblici al tuo servizio tramite l’API del tuo fornitore di cloud. Questo è il servizio ideale quando vuoi comunicare con i tuoi pod dall’esterno del tuo cluster. Con LoadBalancer, sarai in grado non solo di allocare un indirizzo IP pubblico ma anche, utilizzando Azure, allocare un indirizzo IP privato dalla tua rete privata virtuale. Quindi, puoi parlare con i tuoi pod da Internet o internamente sulla tua subnet privata.
Rivediamo la definizione YAML di un servizio:
apiVersion: v1kind: Servicemetadata: name: my-servicespec: selector: app: front-end type: NodePort ports: - name: http port: 80 targetPort: 8080 nodePort: 30024 protocol: TCP
Il YAML di un servizio è molto semplice, e le specifiche varieranno, a seconda del tipo di servizio che stai creando. Ma la cosa più importante da tenere in considerazione sono le definizioni delle porte. Diamo un’occhiata a queste:
- port: Questa è la porta del servizio che è esposta
- targetPort: Questa è la porta sui pod a cui il servizio sta inviando traffico
- nodePort: Questa è la porta che sarà esposta
Sebbene ora comprendiamo come possiamo comunicare con i pod nel nostro cluster, dobbiamo ancora capire come gestiremo il problema di perdere i nostri dati ogni volta che un pod viene terminato. È qui che entrano in gioco i Volumi Persistenti (PV).
Kubernetes e archiviazione persistente
L’archiviazione persistente nel mondo dei container è un problema serio. L’unico storage che è persistente attraverso le esecuzioni dei container sono gli strati dell’immagine, e sono di sola lettura. Lo strato in cui il container gira è leggibile/scrivibile, ma tutti i dati in questo strato vengono eliminati una volta che il container si ferma. Con i pod, è lo stesso. Quando un container muore, i dati scritti su di esso sono andati.
Kubernetes ha un insieme di oggetti per gestire l’archiviazione attraverso i pod. Il primo di cui discuteremo sono i volumi.
Volumi
I volumi risolvono uno dei più grandi problemi quando si tratta di archiviazione persistente. Prima di tutto, i volumi non sono effettivamente oggetti, ma una definizione della spec di un pod. Quando crei un pod, puoi definire un volume sotto il campo spec del pod. I container in questo pod saranno in grado di montare il volume sul loro namespace di montaggio, e il volume sarà disponibile attraverso riavvii o crash dei container. I volumi sono legati ai pod, però, e se il pod viene eliminato, anche il volume scomparirà. La persistenza dei dati sul volume è un’altra storia; la persistenza dei dati dipenderà dal backend di quel volume.
Kubernetes supporta diversi tipi di volumi o fonti di volume e come vengono chiamati nelle specifiche API, che vanno da mappe di filesystem dal nodo locale, dischi virtuali dei fornitori di cloud, e volumi supportati da storage definito dal software. I mount di filesystem locali sono i più comuni che vedrai quando si tratta di volumi regolari. È importante notare che lo svantaggio dell’utilizzo del filesystem locale del nodo è che i dati non saranno disponibili su tutti i nodi del cluster, ma solo su quel nodo dove il pod è stato programmato.
Esaminiamo come viene definito un pod con un volume in YAML:
apiVersion: v1kind: Podmetadata: name: test-pdspec: containers: - image: k8s.gcr.io/test-webserver name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume hostPath: path: /data type: Directory
Nota come ci sia un campo chiamato volumes sotto spec e poi ce n’è un altro chiamato volumeMounts.
Il primo campo (volumes) è dove definisci il volume che vuoi creare per quel pod. Questo campo richiederà sempre un nome e poi una fonte di volume. A seconda della fonte, i requisiti saranno diversi. In questo esempio, la fonte sarebbe hostPath, che è il filesystem locale di un nodo. hostPath supporta diversi tipi di mapping, che vanno da directory, file, dispositivi a blocchi e persino socket Unix.
Sotto il secondo campo, volumeMounts, abbiamo mountPath, che è dove definisci il percorso all’interno del container dove vuoi montare il tuo volume. Il parametro name è come specifichi al pod quale volume utilizzare. Questo è importante perché puoi avere diversi tipi di volumi definiti sotto volumes, e il nome sarà l’unico modo per il pod di sapere quale
Puoi saperne di più sui diversi tipi di volumi qui https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes e nel documento di riferimento API di Kubernetes ( https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#volume-v1-core).
Avere volumi che muoiono con i pod non è ideale. Abbiamo bisogno di archiviazione che persista, ed è così che è nata la necessità dei PV.
Volumi Persistenti, Richieste di Volumi Persistenti e Classi di Archiviazione
La principale differenza tra volumi e PV è che, a differenza dei volumi, i PV sono effettivamente oggetti API di Kubernetes, quindi puoi gestirli individualmente come entità separate, e quindi persistono anche dopo che un pod è stato eliminato.
Potresti chiederti perché questa sottosezione ha PV, richieste di volume persistente (PVC), e classi di archiviazione tutte mescolate. Questo perché tutti dipendono l’uno dall’altro, ed è cruciale comprendere come interagiscono tra loro per fornire archiviazione per i nostri pod.
Iniziamo con PV e PVC. Come i volumi, i PV hanno una fonte di archiviazione, quindi lo stesso meccanismo che hanno i volumi si applica qui. Avrai o un cluster di archiviazione definito dal software che fornisce un numero logico di unità (LUN), un fornitore di cloud che fornisce dischi virtuali, o persino un filesystem locale per il nodo Kubernetes, ma qui, invece di essere chiamati fonti di volume, vengono chiamati tipi di volume persistente.
I PV sono praticamente come i LUN in un array di archiviazione: li crei, ma senza un mapping; sono solo un insieme di archiviazione allocata in attesa di essere utilizzata. I PVC sono come i mapping LUN: sono supportati o legati a un PV e sono anche ciò che definisci effettivamente, relazioni e rendi disponibile al pod che può quindi utilizzarli per i suoi container.
Il modo in cui utilizzi i PVC sui pod è esattamente lo stesso che con i normali volumi. Hai due campi: uno per specificare quale PVC vuoi utilizzare, e l’altro per dire al pod su quale container utilizzare quel PVC.
Il YAML per una definizione di oggetto API PVC dovrebbe avere il seguente codice:
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: gluster-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi
Il YAML per il pod dovrebbe avere il seguente codice:
kind: PodapiVersion: v1metadata: name: mypodspec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: “/mnt/gluster” name: volume volumes: - name: volume persistentVolumeClaim: claimName: gluster-pvc
Quando un amministratore Kubernetes crea un PVC, ci sono due modi in cui questa richiesta viene soddisfatta:
- Statico: Diversi PV sono già stati creati, e poi quando un utente crea un PVC, qualsiasi PV disponibile che può soddisfare i requisiti sarà legato a quel PVC.
- Dinamico: Alcuni tipi di PV possono creare PV basati sulle definizioni PVC. Quando viene creato un PVC, il tipo di PV creerà dinamicamente un oggetto PV e allocherebbe l’archiviazione nel backend; questo è il provisioning dinamico. Il problema con il provisioning dinamico è che richiedi un terzo tipo di oggetto di archiviazione Kubernetes, chiamato classe di archiviazione.
Le classi di archiviazione sono come un modo di livellare la tua archiviazione. Puoi creare una classe che fornisce volumi di archiviazione lenti, o un’altra con dischi SSD iper-veloci. Tuttavia, le classi di archiviazione sono un po’ più complesse rispetto a un semplice livellamento. Come abbiamo accennato nei due modi di creare PVC, le classi di archiviazione sono ciò che rende possibile il provisioning dinamico. Quando lavori in un ambiente cloud, non vuoi creare manualmente ogni disco backend per ogni PV. Le classi di archiviazione imposteranno qualcosa chiamato provisioner, che invocherà il plug-in del volume necessario per parlare con l’API del tuo fornitore di cloud. Ogni provisioner ha le proprie impostazioni in modo da poter parlare con il fornitore di cloud o di archiviazione specificato.
Puoi fornire classi di archiviazione nel seguente modo; questo è un esempio di una classe di archiviazione che utilizza Azure-disk come provisioner di disco:
kind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: my-storage-classprovisioner: kubernetes.io/azure-diskparameters: storageaccounttype: Standard_LRS kind: Shared
Ogni provisioner di classe di archiviazione e tipo di PV avrà requisiti e parametri diversi, così come i volumi, e abbiamo già avuto una panoramica generale di come funzionano e per cosa possiamo usarli. Imparare a conoscere classi di archiviazione specifiche e tipi di PV dipenderà dal tuo ambiente; puoi saperne di più su ciascuno di essi cliccando sui seguenti link:
- https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
In questo articolo, abbiamo appreso cos’è Kubernetes, i suoi componenti e quali sono i vantaggi dell’utilizzo dell’orchestrazione. Con questo, identificare ciascuno degli oggetti API di Kubernetes, il loro scopo e i loro casi d’uso dovrebbe essere facile. Dovresti ora essere in grado di comprendere come i nodi master controllano il cluster e la programmazione dei container nei nodi lavoratori.
Se hai trovato utile questo articolo, ‘ Hands-On Linux for Architects ’ dovrebbe esserti utile. Con questo libro, coprirai tutto, dai componenti e funzionalità di Linux al supporto hardware e software, che ti aiuterà a implementare e ottimizzare soluzioni Linux efficaci. Ti verrà fornita una panoramica della metodologia di design di Linux e dei concetti fondamentali per progettare una soluzione. Se sei un amministratore di sistema Linux, un ingegnere di supporto Linux, un ingegnere DevOps, un consulente Linux o chiunque desideri imparare o espandere le proprie conoscenze nell’architettura, questo libro è per te.
Ricevi i nuovi post nella tua casella di posta.
Nessuno spam. Disiscriviti in qualsiasi momento.