Salta al contenuto principale

FAQ

Qual è la differenza tra un container e una macchina virtuale?

Una macchina virtuale virtualizza l'hardware ed esegue un intero sistema operativo guest con un proprio kernel sopra un hypervisor, mentre un container virtualizza il sistema operativo e condivide il kernel dell'host, isolando solo il processo userspace. Questo rende i container molto più leggeri: si avviano in millisecondi, usano una frazione della memoria e si impacchettano più densamente su un host. Il compromesso è un isolamento più debole rispetto a una VM, poiché una vulnerabilità del kernel è un confine condiviso; per un isolamento più forte si possono combinare i container con le VM (ad esempio con gVisor o un runtime microVM come Kata Containers).

Come rendo più piccole le mie immagini Docker?

Parti da un'immagine base minimale (una variante distroless o slim, o costruisci da scratch per binari statici), e usa una build multi-stage così che compilatori e SDK non finiscano mai nell'immagine finale. Ordina le istruzioni del Dockerfile dal meno al più frequentemente modificato per massimizzare il riuso della cache dei layer, copia solo ciò che ti serve (usa un .dockerignore) e combina gli step RUN correlati per evitare file intermedi residui. Immagini più piccole si scaricano più in fretta, si avviano più rapidamente e riducono la superficie d'attacco.

Quando dovrei usare Docker Compose invece di Kubernetes?

Usa Docker Compose per lo sviluppo locale e per semplici deployment su singolo host dove ti basta avviare insieme alcuni servizi con un solo comando. Passa a Kubernetes quando ti serve scheduling multi-nodo, auto-guarigione, autoscaling orizzontale, rolling update, riconciliazione dichiarativa e ricche astrazioni di rete e storage su un cluster. Compose e Kubernetes risolvono scale di problema diverse; molti team sviluppano con Compose e rilasciano su Kubernetes.

Perché Docker è stato "rimosso" da Kubernetes e la mia immagine funziona ancora?

Kubernetes ha rimosso l'adattatore "dockershim" in-tree nella versione 1.24, quindi il kubelet non parla più direttamente con Docker Engine; parla con runtime conformi alla CRI come containerd o CRI-O. Le tue immagini non sono interessate perché sono immagini OCI, che containerd esegue nativamente, e Docker stesso usa containerd sotto il cofano. Il cambiamento riguarda il runtime del nodo, non il formato dell'immagine, quindi continui a costruire immagini con Docker come prima.

Cos'è un Pod e perché non eseguire semplicemente un singolo container?

Un Pod è la più piccola unità schedulabile in Kubernetes e racchiude uno o più container che condividono un namespace di rete e possono condividere volumi, sempre co-locati su un nodo. La maggior parte dei Pod esegue un singolo container applicativo, ma il modello esiste affinché ausiliari strettamente accoppiati (un proxy sidecar, un raccoglitore di log) possano condividere la stessa rete e lo stesso storage del container principale. Kubernetes schedula, scala e mette in rete i Pod anziché i container nudi, ed è per questo che anche un singolo container gira dentro un Pod.

Come espongo la mia applicazione in esecuzione su Kubernetes verso l'esterno?

All'interno del cluster, un Service ClusterIP dà ai Pod un IP virtuale stabile e un nome DNS. Per raggiungerlo dall'esterno puoi usare un NodePort (apre una porta su ogni nodo), un Service LoadBalancer (effettua il provisioning di un bilanciatore esterno, tipicamente in un cloud) o, per HTTP/HTTPS, un Ingress con un Ingress controller che fornisce routing per host e per path e terminazione TLS. Per un routing L4/L7 più ricco, la più recente Gateway API è il successore in evoluzione di Ingress.

Qual è la differenza tra una probe di liveness e una di readiness?

Una probe di liveness dice a Kubernetes se un container è ancora in salute; quando fallisce, il kubelet riavvia il container, recuperandolo da deadlock o stati bloccati. Una probe di readiness dice a Kubernetes se il container è pronto a servire traffico; quando fallisce, il Pod viene rimosso dagli endpoint del Service ma non riavviato, quindi smette di ricevere richieste finché non si riprende. Usa la readiness per "non inviare ancora traffico" e la liveness per "questo è rotto, riavvialo"; configurare erroneamente la liveness come readiness può causare cicli di riavvio inutili.

Come influenzano davvero i miei Pod le richieste e i limiti di risorse?

Una richiesta è ciò che lo scheduler riserva quando piazza il Pod, quindi determina dove il Pod può entrare e contribuisce alla sua classe Quality of Service. Un limite è il tetto rigido a run time: superare il limite di memoria fa terminare il container per OOM, e superare il limite di CPU lo fa sottoporre a throttling anziché terminarlo. Impostare le richieste uguali ai limiti dà la classe QoS Guaranteed e il comportamento più prevedibile; omettere le richieste lascia che i Pod siano schedulati su nodi in overcommit e sfrattati per primi sotto pressione.

Come dovrei archiviare configurazione e segreti in Kubernetes?

Metti la configurazione non sensibile nelle ConfigMap e iniettala come variabili d'ambiente o file montati, tenendo la configurazione fuori dall'immagine così che la stessa immagine giri in ogni ambiente. Metti i valori sensibili nei Secret, ma sii consapevole che per impostazione predefinita i Secret sono solo codificati in base64 in etcd, non cifrati, quindi abilita la cifratura a riposo, limita l'accesso con RBAC e considera un gestore di segreti esterno. Non incorporare mai credenziali nell'immagine né committarle su Git.

Qual è la differenza tra un Deployment e uno StatefulSet?

Un Deployment gestisce repliche stateless e intercambiabili ed è il default per app web e API; i Pod sono fungibili e sostituibili in qualsiasi ordine. Uno StatefulSet dà a ciascun Pod un'identità stabile e ordinata e il proprio storage persistente che lo segue attraverso il rescheduling, che è ciò di cui hanno bisogno database e sistemi clusterizzati. Scegli un Deployment a meno che il tuo carico non richieda identità di rete stabile, avvio ordinato o volumi persistenti per replica.

Come fanno i rolling update a ottenere zero downtime?

Il rolling update di un Deployment crea un nuovo ReplicaSet e sposta i Pod dalla vecchia alla nuova versione gradualmente, governato da maxSurge (quanti Pod extra possono essere creati) e maxUnavailable (quanti possono essere indisponibili contemporaneamente). Le probe di readiness sono essenziali: i nuovi Pod ricevono traffico solo quando si dichiarano pronti, e i vecchi Pod vengono rimossi solo man mano che i nuovi diventano disponibili. Combinato con un PodDisruptionBudget, questo permette di rilasciare e tollerare la manutenzione dei nodi senza perdere richieste, e puoi fare rollback a un ReplicaSet precedente se la nuova versione si comporta male.

Come persisto i dati per un container o un Pod?

In Docker, usa un volume con nome anziché scrivere nel layer scrivibile del container, poiché il layer scrivibile viene scartato quando il container è rimosso; i bind mount sono comodi per lo sviluppo ma legano i dati a un percorso host. In Kubernetes, un Pod richiede storage con un PersistentVolumeClaim, che si lega a un PersistentVolume; una StorageClass può fornire il disco sottostante dinamicamente. Per carichi che necessitano di storage durevole per replica con identità stabile, usa uno StatefulSet con un volumeClaimTemplate.

Perché il mio Pod è bloccato in Pending, CrashLoopBackOff o ImagePullBackOff?

Pending di solito significa che lo scheduler non riesce a piazzare il Pod: CPU/memoria insufficienti su qualsiasi nodo, una regola di affinità o taint non soddisfacibile, o un PersistentVolumeClaim non legato. CrashLoopBackOff significa che il container parte ed esce ripetutamente, quindi controlla i log e l'exit code (137 indica un OOM kill) e rivedi le impostazioni della probe di liveness. ImagePullBackOff significa che il nodo non riesce a recuperare l'immagine, tipicamente un nome o tag errato, un imagePullSecret mancante o connettività al registry; kubectl describe pod mostra l'evento preciso in ciascun caso.

Come comunicano in modo sicuro i container in un cluster?

Kubernetes dà a ogni Pod il proprio IP su una rete piatta così che qualsiasi Pod possa raggiungere qualsiasi altro per impostazione predefinita, con il DNS interno che risolve i nomi dei Service. Per limitarlo, applica le NetworkPolicy (fatte rispettare da una CNI capace come Calico o Cilium) che consentono solo l'ingress e l'egress che intendi, seguendo il minimo privilegio. Per traffico servizio-a-servizio autenticato e cifrato e per policy a grana fine, una service mesh (Istio, Linkerd) aggiunge mutual TLS e controlli L7.

Cos'è Helm e quando mi serve?

Helm è il package manager di fatto per Kubernetes: raggruppa un insieme di manifest templatizzati in un chart versionato, parametrizzato da un file di values, così che un chart faccia il deploy su molti ambienti e possa essere aggiornato o sottoposto a rollback come un rilascio. Ti serve quando installi applicazioni di terze parti (la maggior parte fornisce un chart) o quando vuoi templatizzare e versionare i tuoi manifest tra dev, staging e produzione. Tra le alternative di templating c'è Kustomize, che applica patch a YAML puro senza un linguaggio di templating.

Quali sono alcune pratiche essenziali di sicurezza delle immagini Docker?

Esegui il container come utente non-root, fissa le immagini base per digest anziché per un tag mutabile, e mantieni le immagini minimali così che ci sia meno da sfruttare e da aggiornare. Scansiona le immagini per vulnerabilità note in CI, non incorporare mai segreti nei layer (usa i secret mount di BuildKit o l'iniezione a run time) e imposta un filesystem di root in sola lettura con le capability Linux rimosse dove possibile. In Kubernetes, applica questo con un securityContext (runAsNonRoot, readOnlyRootFilesystem, drop ALL delle capability) e policy di admission come i Pod Security Standards.