Cosa fa#
File di testo con istruzioni per costruire un'immagine Docker passo per passo. Ogni istruzione aggiunge un layer immutabile.
Struttura base#
# Da quale immagine parti (il "sistema operativo base")
FROM ubuntu:22.04
# Chi mantiene questa immagine
LABEL maintainer="barno@example.com"
# Esegui comandi durante la costruzione (installa software)
RUN apt-get update && apt-get install -y nodejs npm
# Imposta la directory di lavoro dentro il container
WORKDIR /app
# Copia file dall'host dentro l'immagine
COPY package.json .
COPY src/ ./src/
# Esegui comando durante build (installa dipendenze)
RUN npm install
# Espone una porta (documentazione — non apre nulla da sola)
EXPOSE 3000
# Variabili d'ambiente
ENV NODE_ENV=production
# Utente con cui girare (sicurezza — evita root)
USER node
# Cosa esegue il container quando parte
ENTRYPOINT ["node"]
CMD ["src/app.js"]ENTRYPOINT vs CMD — la differenza che confonde#
Questa e' la parte piu' confusa di Docker. Analogia:
ENTRYPOINT = funge da costruttore (viene eseguito sempre all'avvio e definisce il comportamento fisso), CMD = rappresenta gli argomenti di default del costruttore, che l'utente può decidere di cambiare al momento del lancio
graph LR
E[ENTRYPOINT\nnode] --> CMD[CMD\nsrc/app.js]
CMD --> Final["Esegue:\nnode src/app.js"]
ENTRYPOINT ["docker-entrypoint.sh"] ← sempre eseguito
CMD ["node", "server.js"] ← argomento di default
# l'utente può fare:
docker run myimage bash ← sovrascrive CMD, entrypoint resta# Dockerfile:
ENTRYPOINT ["node"]
CMD ["src/app.js"]
# docker run myimage
# → esegue: node src/app.js (default)
# docker run myimage src/altro.js
# → esegue: node src/altro.js (CMD sovrascritto)
# docker run --entrypoint bash myimage
# → esegue: bash (ENTRYPOINT sovrascritto — raro)Caso reale nel docker-compose di Chatwoot:
# rails e sidekiq usano la stessa immagine (<<: *base)
# ma CMD diverso:
rails:
command: ["bundle", "exec", "rails", "s", "-p", "3000"]
# → esegue il server web
sidekiq:
command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
# → esegue il worker backgroundStessa immagine, comportamento diverso — solo CMD cambia.
Le istruzioni da ricordare — ordine di importanza#
Imprescindibili:
| Istruzione | Cosa fa | Quando |
|---|---|---|
FROM | Immagine base di partenza | Sempre prima riga |
RUN | Esegue comandi durante il build | Installare software |
COPY | Copia file dall'host nell'immagine | Aggiungere codice e config |
ENTRYPOINT | Il mestiere del container — non cambia | Definire il processo principale |
CMD | Argomenti di default — sovrascrivibili | Configurazione di default |
Importanti:
| Istruzione | Cosa fa |
|---|---|
WORKDIR | Directory di lavoro dentro il container |
ENV | Variabili d'ambiente disponibili a runtime |
EXPOSE | Documenta quale porta usa il container |
USER | Utente con cui gira il processo — fondamentale per security |
EXPOSE e' solo documentazione — non apre nessuna porta reale. La porta viene esposta solo con -p 8080:3000 in docker run o con ports: in docker-compose. E' una fonte comune di confusione.
Aggiungi sempre USER con un utente non-root. Un container compromesso che gira come root ha accesso root anche all'host se docker.sock e' montato — vedi docker-security.
COPY vs ADD#
# COPY — semplice, copia file/directory
COPY src/ /app/src/
COPY config.yml /app/
# ADD — fa tutto COPY + estrae tar + scarica URL
ADD archive.tar.gz /app/ # estrae automaticamente
ADD https://example.com/file /app/ # scarica da URL
# Regola: usa sempre COPY a meno che non ti serva l'estrazione
# ADD nasconde cosa sta facendo — COPY e' esplicitoLayer caching — perche' l'ordine conta#
Docker riusa i layer gia' costruiti se non sono cambiati. Metti le istruzioni che cambiano meno all'inizio:
# SBAGLIATO — ogni modifica al codice invalida anche npm install
FROM node:18
COPY . /app # copia tutto — se cambia un file, rifai npm install
RUN npm install
# CORRETTO — npm install viene rifatto solo se package.json cambia
FROM node:18
COPY package.json /app/ # raramente cambia
RUN npm install # usa la cache se package.json non cambia
COPY . /app # cambia spesso — ma npm install e' gia' cachedBuild e uso#
# Costruisce l'immagine dalla directory corrente
docker build -t mia-app:1.0 .
# -t = tag (nome:versione)
# . = context (directory con Dockerfile e file)
# Costruisce specificando il Dockerfile
docker build -f Dockerfile.prod -t mia-app:prod .
# Mostra i layer e la cache usata
docker build --no-cache -t mia-app:1.0 .
# --no-cache = ignora la cache, ricostruisce tuttoRUN apt-get update && apt-get install -y pacchetto deve stare su una sola riga — se le separi in due RUN, la cache potrebbe usare un apt-get update vecchio con pacchetti obsoleti.
Non mettere mai password, token o chiavi private nel Dockerfile — anche se le cancelli in un layer successivo, restano nella storia dei layer e sono visibili con docker history.
Collegato a#
- docker-image — il risultato del build
- docker-compose — come usare l'immagine in un servizio
- docker-security — USER, secrets, superficie di attacco
- system — categoria


