Cosa fa#
Template immutabile da cui nascono i container. Contiene filesystem, dipendenze e istruzioni di avvio. L'immagine non cambia mai — ogni container che nasce da essa e' una copia fresca.
Analogia — la planimetria dell'appartamento#
Un'immagine e' come la planimetria di un appartamento:
- La planimetria (immagine) descrive com'e' fatto l'appartamento
- Puoi costruire 10 appartamenti identici dalla stessa planimetria
- Ogni appartamento (container) e' indipendente — se uno brucia, gli altri restano
- La planimetria non cambia quando ci abiti dentro
graph LR
Image[Immagine chatwoot:latest] -->|docker run| C1[Container 1 in esecuzione]
Image -->|docker run| C2[Container 2 in esecuzione]
Image -->|docker run| C3[Container 3 in esecuzione]
C1 -->|modifica filesystem| FS1[Layer R/W temporaneo]
C2 --> FS2[Layer R/W temporaneo]
C3 --> FS3[Layer R/W temporaneo]
Layer — come e' costruita un'immagine#
Un'immagine e' un stack di layer sovrapposti. Ogni istruzione nel Dockerfile aggiunge un layer. I layer sono condivisi tra immagini — se due immagini usano ubuntu:22.04 come base, quel layer esiste una volta sola su disco.
graph TD
L1[Layer 1: ubuntu:22.04 base]
L2[Layer 2: apt install nodejs]
L3[Layer 3: COPY package.json]
L4[Layer 4: npm install]
L5[Layer 5: COPY app/]
RW[Layer R/W: modifiche del container - temporaneo]
L1 --> L2 --> L3 --> L4 --> L5 --> RW
I layer sotto sono read-only — immutabili. Solo il layer in cima e' scrivibile, e appartiene al container, non all'immagine. Quando il container viene eliminato, quel layer sparisce.
Comandi essenziali#
docker images # lista immagini locali
docker pull chatwoot/chatwoot:latest # scarica immagine dal registry
docker rmi chatwoot/chatwoot:latest # rimuove immagine locale
docker image inspect chatwoot/chatwoot # dettagli completi
docker history chatwoot/chatwoot # mostra i layer dell'immagine
docker image prune # elimina immagini non usateTag — versioni dell'immagine#
# il tag e' la versione — dopo i due punti
chatwoot/chatwoot:latest # ultima versione stabile
chatwoot/chatwoot:v3.11.0 # versione specifica
postgres:16 # postgres versione 16
postgres:16-alpine # postgres 16 su Alpine Linux (piu' leggero)
# latest non e' sempre sicuro in produzione:
# oggi latest = v3.11, domani latest = v4.0 con breaking changes
# in produzione: usa sempre un tag specificoIn produzione non usare mai :latest — fissa sempre una versione specifica. Un docker compose pull su :latest potrebbe portare una versione incompatibile e rompere tutto.
Aggiornamenti disponibili#
docker ps mostra una U a fianco del nome container quando l'immagine ha un aggiornamento disponibile nel registry.
Per sapere quale immagine sta usando un container in esecuzione:
# dettaglio completo
docker inspect nome-container | grep Image
# leggibile: nome container → immagine corrente
docker ps --format "{{.Names}}: {{.Image}}"Per scaricare le versioni aggiornate e riavviare:
docker compose pull # aggiorna tutte le immagini del compose
docker compose up -d # riavvia i container con le nuove immaginiEsplorazione interattiva#
Prima di scrivere un Dockerfile, conviene esplorare l'immagine base in modo interattivo per capire cosa è già installato e quale configurazione serve:
# avvia un container temporaneo con shell interattiva
docker run -it --rm nome-immagine /bin/bashQuesto approccio riduce i tentativi nel Dockerfile: prima capisci cosa funziona in modo interattivo, poi lo trascrivi come istruzione RUN. Il container viene eliminato all'uscita (--rm).
Docker Entrypoint Override#
A volte il comando sopra fallisce o non apre una shell. Questo succede quando l'immagine ha un ENTRYPOINT definito (es: ENTRYPOINT ["/entrypoint.sh", "app"]). In questo caso, /bin/bash viene passato come argomento allo script, non eseguito come comando.
Per "zittire" lo script e forzare l'accesso al sistema:
# Sovrascrive l'entrypoint originale
docker run -it --rm --entrypoint /bin/bash nome-immagine
# Per immagini Alpine Linux (che spesso non hanno bash)
docker run -it --rm --entrypoint /bin/sh nome-immaginePerché è utile in ambito Security?#
- Ispezione del Filesystem: Verificare se sono rimasti file temporanei, log o segreti (
/tmp,/root/.npm). - Verifica Permessi: Controllare con
whoamiels -lse i processi girano comeroot. - Bypass delle Restrizioni: Se l'entrypoint esegue controlli di licenza o configurazione, l'override permette di analizzare il container "a cuore aperto".
Immagini orfane (dangling)#
Le immagini orfane sono layer senza tag, prodotti da build successive della stessa immagine. Occupano disco senza essere usate da nessun container.
# lista solo immagini orfane
docker images -f dangling=true
# elimina solo le orfane
docker image prune
# elimina tutte le immagini non usate da container attivi (piu aggressivo)
docker image prune -a
# quanto spazio occupano immagini, container, volumi
docker system dfdocker image prune -a elimina anche immagini valide non usate in questo momento — attenzione se hai container spenti che le usano.
Prima di fare qualsiasi prune, controlla cosa hai davvero in esecuzione e cosa e' fermo:
# mostra tutti i container (attivi e spenti) con la loro immagine
docker ps -a --format "{{.Names}}: {{.Status}}: {{.Image}}"Cosi' sai esattamente quali immagini sono ancora necessarie per container in stato Exited che vuoi riavviare, e quali invece sono davvero abbandonate.
Docker Layer Caching e Ispezione Immagini#
1. La Struttura a Layer (Livelli)#
Ogni immagine Docker è una pila di layer immutabili e read-only. Ogni istruzione nel Dockerfile (RUN, COPY, ADD) crea un nuovo layer.
- Layer di Contenuto (
RUN,COPY): Aggiungono dati fisici e aumentano la dimensione dell'immagine (es. installazione di pacchetti). - Layer di Metadati (
ENV,ARG,WORKDIR,ENTRYPOINT): Non aggiungono peso (0B), ma modificano il comportamento del runtime.
2. Il Comando docker history#
È lo strumento di "archeologia digitale" per analizzare come è stata costruita un'immagine.
- Utilizzo:
docker history <nome-immagine> - Analisi Security: Permette di vedere se sono state eseguite operazioni pericolose (es. installazione di tool di rete poi rimossi) o se layer pesanti stanno occupando spazio inutilmente.
- Interpretazione: Se vedi
<missing>, significa che Docker sta usando BuildKit: i layer intermedi sono gestiti come differenze logiche e non hanno un ID immagine individuale, rendendo l'immagine finale più efficiente.
3. La Logica della Cache (Determinismo)#
Docker è "pigro": prima di eseguire un comando, calcola un hash dell'istruzione e del contesto (file o variabili).
- Se l'hash corrisponde a un layer esistente, Docker usa la Cache (HIT) e non esegue il comando.
- Il problema del "Latest": Se usi
latesto comandi che scaricano dati da internet, Docker non sa se il contenuto remoto è cambiato. Se l'istruzione nel Dockerfile rimane identica, Docker userà la cache, ignorando eventuali aggiornamenti disponibili online.
4. Il Flag --no-cache#
Forza Docker ad ignorare completamente la cronologia dei layer locali.
- Quando usarlo: Quando vuoi essere certo di applicare le ultime patch di sicurezza (
apk upgrade) o scaricare l'ultima versione di un software CLI senza cambiare ilDockerfile. - Effetto: Invalida la cache per tutte le righe del Dockerfile.
5. Strategia: Cache Busting Mirato (Best Practice)#
Invece di usare sempre --no-cache (lento e inefficiente), si usa un "interruttore" (Cache Buster) tramite gli ARG.
Dockerfile
FROM alpine:3.23
# Layer precedenti (Cache HIT)
RUN apk add --no-cache bash
# Se cambi questo valore, Docker invalida la cache SOLO da qui in poi
ARG VERSION="1.0.1"
RUN npm install -g mio-tool@${VERSION}Considerazioni del Security Analyst#
Immutabilità: In produzione, preferire il Version Pinning (es.
VERSION=1.0.1) rispetto a--no-cacheconlatest. Questo garantisce che l'immagine sia riproducibile e che il comportamento del software non cambi inaspettatamente tra una build e l'altra.Pulizia: Ogni riga
RUNche aggiunge e poi rimuove file (es.apk add npm && apk del npm) deve essere un'unica catena di comandi (&&). Se lo facessi in due righe separate,npmrimarrebbe per sempre nel layer precedente, occupando spazio e aumentando la superficie d'attacco.
Collegato a#
- dockerfile — come si costruisce un'immagine
- docker-compose — come si usa un'immagine in un servizio
- system — categoria


