Skip to main content
  1. Concetti/

Dockerfile

·4 mins
Alessio Barnini
Author
Alessio Barnini
Table of Contents

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 background

Stessa immagine, comportamento diverso — solo CMD cambia.


Le istruzioni da ricordare — ordine di importanza
#

Imprescindibili:

IstruzioneCosa faQuando
FROMImmagine base di partenzaSempre prima riga
RUNEsegue comandi durante il buildInstallare software
COPYCopia file dall'host nell'immagineAggiungere codice e config
ENTRYPOINTIl mestiere del container — non cambiaDefinire il processo principale
CMDArgomenti di default — sovrascrivibiliConfigurazione di default

Importanti:

IstruzioneCosa fa
WORKDIRDirectory di lavoro dentro il container
ENVVariabili d'ambiente disponibili a runtime
EXPOSEDocumenta quale porta usa il container
USERUtente con cui gira il processo — fondamentale per security
Warning

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.

Important

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' esplicito

Layer 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' cached

Build 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 tutto
Tip

RUN 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.

Warning

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
#

Related