Capire i container
Modulo 9: Docker e docker compose · Tempo di lettura: 10 minuti
Obiettivo della lezione: Dopo questa lezione saprà spiegare che cos'è un container, in che cosa si distingue da una macchina virtuale, dove restano i dati di un container e quando Docker ha senso sul Suo server.
Concetti chiave: image, container, livello, registry (Docker Hub), tag, digest, namespaces, cgroups, kernel condiviso, file system volatile, volume, bind mount, pubblicazione delle porte, image ufficiale
Perché i container?
Supponiamo che Lei voglia eseguire sul Suo VPS una pagina di stato che mostri se il Suo sito web funziona. Il programma è scritto in Node.js, richiede una determinata versione di Node.js e in più circa duecento librerie. Senza container installerebbe tutto questo sul Suo server, accanto al server web e al database. Un anno dopo vuole un secondo programma che richiede un'altra versione di Node.js. E lì cominciano i grattacapi.
Un container risolve questo problema. Chi sviluppa il programma lo fornisce insieme a tutto ciò di cui ha bisogno, in un unico pacchetto: un'image. Sul Suo server avvia quell'image come container. Il programma vede i propri file, il proprio Node.js, le proprie librerie, e non entra in conflitto con il resto del server. Non Le serve più? Rimuove il container e l'image, e non resta nulla in /usr o /etc.
Docker è lo strumento più noto per scaricare image ed eseguire container. Esistono alternative (Podman, containerd stesso), ma i concetti sono ovunque gli stessi.
Image, container e registry
Tre termini che incontrerà continuamente:
- Image: un modello di sola lettura con un file system (programma, librerie, impostazioni) e il comando da avviare. Un'image è composta da livelli: un livello di base (per esempio una Debian minimale), sopra un livello con Node.js, sopra ancora il programma. Due image con lo stesso livello di base condividono quel livello sul disco.
- Container: un'istanza in esecuzione (o arrestata) di un'image. Sopra i livelli di sola lettura il container riceve un proprio sottile livello di scrittura. Da una sola image può avviare dieci container.
- Registry: il luogo in cui si trovano le image, come Docker Hub (
docker.io) o il registry di GitHub (ghcr.io). Docker scarica un'image condocker pull.
Il nome di un'image ha questo aspetto:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestLa parte dopo i due punti è il tag: un'etichetta per una versione. Un tag può cambiare: caddy:2 oggi punta a una build diversa da quella di fra tre mesi, non appena esce una nuova 2.x. Se vuole stabilire con precisione quale image esegue, usi il digest: un'impronta digitale del contenuto, come caddy@sha256:.... Il digest non cambia mai. Il tag latest è semplicemente un nome scelto da chi sviluppa l'image; non significa automaticamente "l'ultima versione stabile" ed è quindi una cattiva scelta se vuole sapere che cosa è in esecuzione.
Non è una macchina virtuale
Un container somiglia a una piccola macchina virtuale, ma non lo è. Questa differenza è importante per la sicurezza.
| Macchina virtuale (come il Suo VPS) | Container | |
|---|---|---|
| Kernel | Kernel proprio | Condivide il kernel dell'host |
| Avvio | Da secondi a minuti, un intero sistema operativo | Di solito in un secondo, solo il programma |
| Separazione | Tramite l'hypervisor, a livello hardware | Tramite il kernel: namespaces e cgroups |
| Dimensioni | Gigabyte | Spesso da decine a centinaia di megabyte |
Un container è in pratica un normale processo sul Suo server, che il kernel colloca in un ambiente isolato:
- i namespaces fanno sì che il processo abbia una propria visione di file, processi, rete e utenti. Nel container il programma sembra essere il processo numero 1 e non vede il resto del server;
- i cgroups limitano quanta CPU e quanta memoria può usare.
Poiché tutti i container condividono lo stesso kernel, la separazione è meno rigorosa che tra due VPS. Una falla nel kernel o un container con troppi privilegi può colpire l'host. Da qui le regole di questo modulo: esegua solo image di cui si fida, non dia ai container più privilegi del necessario e non monti mai /var/run/docker.sock o / in un container (lezioni 9.3 e 10.2).
Dove restano i Suoi dati?
Questa è la classica trappola per i principianti. Il livello di scrittura di un container è volatile: se elimina il container (per esempio durante un aggiornamento, lezione 9.4), tutto ciò che il programma vi ha scritto va perso. I dati che devono restare vanno quindi tenuti fuori dal container:
- Volume: uno spazio di archiviazione gestito da Docker stesso (sotto
/var/lib/docker/volumes/). Gli assegna un nome, per esempiouptime-kuma, e lo collega a una cartella nel container:-v uptime-kuma:/app/data. - Bind mount: una normale cartella del Suo server che monta nel container:
-v /srv/vaultwarden:/data. È comodo perché vede direttamente i file e li include facilmente nel Suo backup (modulo 8).
Un container con volumi ben configurati si può eliminare e ricreare senza perdere nulla. È esattamente così che funziona un aggiornamento: scaricare la nuova image, eliminare il vecchio container, creare un nuovo container sugli stessi volumi. Inserisca quindi i volumi nel Suo piano di backup (lezione 8.1).
Pubblicare le porte
Un container ha una propria rete. Un programma web che nel container è in ascolto sulla porta 3001 non è raggiungibile dall'esterno del server finché Lei non pubblica quella porta: -p 3001:3001 (porta host:porta container). Attenzione: senza indirizzo Docker pubblica la porta su tutti gli indirizzi del Suo server, quindi 0.0.0.0 e [::]. Ciò significa: raggiungibile da tutta Internet, e Docker lo gestisce scavalcando ufw (lezione 9.3). L'abitudine sicura è pubblicare sul loopback, -p 127.0.0.1:3001:3001, e mettere davanti un reverse proxy con https (lezione 9.4).
Chi crea l'image?
Un'image è software di qualcun altro che può girare come root sul Suo server. Controlli quindi chi ne è l'autore:
- le Docker Official Images (come
caddy,nginx,postgres) sono mantenute da Docker insieme agli sviluppatori; - le image degli sviluppatori stessi (come
louislam/uptime-kumaevaultwarden/server), riconoscibili dal nome indicato sul sito web del progetto; - le image di sconosciuti con nomi simili: da non usare.
Usi sempre il nome riportato sul sito ufficiale del progetto, non il primo che compare in una ricerca.
Quando sì e quando no?
Docker è utile per i programmi che lo sviluppatore fornisce come image, per i servizi che vuole poter eliminare o spostare rapidamente e per eseguire fianco a fianco più programmi con requisiti diversi. Per la base del Suo server (SSH, firewall, aggiornamenti) non si usano container. E un singolo sito web con nginx e PHP dai repository dei pacchetti (lezione 7.2) funziona benissimo senza Docker. Un container aggiunge un livello che Lei deve capire e tenere aggiornato; lo usi quando porta un vantaggio.
Riepilogo
- Un'image è un modello di sola lettura a livelli; un container è un'istanza in esecuzione con un proprio livello di scrittura.
- I container condividono il kernel dell'host e sono isolati con namespaces e cgroups: più leggeri di una VM, ma separati in modo meno rigoroso.
- Il livello di scrittura è volatile: i dati permanenti vanno in un volume o in un bind mount, e questi vanno nel Suo backup.
- Un tag può cambiare, un digest no;
latestdice poco. - Pubblichi le porte su 127.0.0.1 e usi solo image dello sviluppatore o image ufficiali.
Quiz
Esercizio
Esercizio O9.1: Container o no? Scelga due programmi che vuole eseguire sul Suo server (oppure usi come esempio Uptime Kuma e un sito WordPress). Per ogni programma verifichi se lo sviluppatore fornisce un'image ufficiale e con quale nome, quale tag sceglierebbe, quale cartella contiene i dati permanenti e su quale porta è in ascolto. Spieghi poi se lo eseguirebbe in un container o dai repository dei pacchetti, e perché.
Esercizio O9.1: Container o no?
Questo esercizio lo svolge da sé; nessuno lo verifica. Spunti ciò che ha fatto e segni l'esercizio come completato.
Uptime Kuma: louislam/uptime-kuma con un tag di versione, dati in /app/data, porta 3001, pubblicazione su 127.0.0.1 dietro un reverse proxy. Scelga un'immagine dello sviluppatore o una Official Image, con un tag di versione e una cartella dati con nome.
Le Sue spunte e note restano solo in questo browser; non le inviamo da nessuna parte. Se ha effettuato l'accesso, conserviamo in I miei corsi solo il fatto che ha svolto l'esercizio.
Per approfondire
- Documentazione Docker, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Documentazione Docker, Volumes: https://docs.docker.com/engine/storage/volumes/
- Documentazione Docker, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
