🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Best Practices per Dockerfile

Codegrind Team•Aug 28 2024

Il Dockerfile è il cuore della creazione di immagini Docker. Scrivere un Dockerfile ottimizzato è essenziale per garantire che le immagini siano leggere, sicure e costruite rapidamente. In questa guida, esploreremo le best practices per scrivere Dockerfile che producano immagini Docker efficienti, sicure e facili da mantenere.

1. Scegli una Base Image Appropriata

La scelta della base image è fondamentale. Le immagini ufficiali di Docker sono spesso la scelta migliore, in quanto sono mantenute e aggiornate regolarmente. Inoltre, scegliere una base image più piccola, come alpine, può ridurre significativamente le dimensioni dell’immagine.

Esempio di Base Image

# Utilizzo di un'immagine base leggera
FROM python:3.9-slim

Utilizzo di alpine

FROM node:14-alpine

Le immagini alpine sono versioni minimali delle distribuzioni, riducendo la dimensione dell’immagine finale.

2. Minimizza il Numero di Livelli

Ogni istruzione in un Dockerfile crea un nuovo livello nell’immagine Docker. Combinare più comandi in un singolo RUN può ridurre il numero di livelli e quindi la dimensione finale dell’immagine.

Esempio di Combinazione di Comandi

# Esegui tutte le operazioni in un solo RUN
RUN apt-get update && apt-get install -y \
    curl \
    git \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

Questo comando combina l’aggiornamento del pacchetto, l’installazione e la pulizia in un singolo livello.

3. Usa .dockerignore per Escludere File Non Necessari

Il file .dockerignore funziona come .gitignore, escludendo file e directory che non dovrebbero essere copiati nella build context. Questo riduce la dimensione della build context e accelera la costruzione dell’immagine.

Esempio di .dockerignore

node_modules
.git
Dockerfile
docker-compose.yml

4. Ordina le Istruzioni per Ottimizzare la Cache

Docker cache le immagini intermedie, il che può velocizzare le build successive. È importante ordinare le istruzioni Dockerfile in modo che le istruzioni meno soggette a cambiamento vengano eseguite per prime, riducendo il numero di cache invalidations.

Esempio di Ordine Ottimale

# Copia e installa le dipendenze per primo
COPY package.json /app/
RUN npm install

# Poi copia il resto del codice
COPY . /app/

5. Usa multi-stage builds per Ridurre le Dimensioni delle Immagini

Le multi-stage builds permettono di creare immagini più piccole rimuovendo strumenti di build e file temporanei non necessari dalla fase finale.

Esempio di Multi-Stage Build

# Fase di build
FROM maven:3.6.3-jdk-11 AS builder
WORKDIR /app
COPY . .
RUN mvn clean package

# Fase finale
FROM openjdk:11-jre-slim
COPY --from=builder /app/target/app.jar /app/app.jar
CMD ["java", "-jar", "/app/app.jar"]

In questo esempio, la prima fase compila il progetto, ma solo il risultato finale (app.jar) viene copiato nell’immagine finale, riducendo significativamente la dimensione.

6. Mantieni Aggiornate le Immagini e le Dipendenze

Mantieni aggiornate le tue immagini base e le dipendenze per garantire che la tua immagine Docker includa le ultime patch di sicurezza.

Esempio di Utilizzo di Versioni Aggiornate

# Utilizza sempre tag specifici, evita "latest"
FROM python:3.9.5-slim

7. Limita i Permessi degli Utenti

Per migliorare la sicurezza, esegui i processi nel container come un utente non root, riducendo il rischio di exploit.

Esempio di Esecuzione come Utente Non Root

# Creazione di un utente e passaggio all'utente non root
RUN useradd -m myuser
USER myuser

# Continua a eseguire il codice come utente non root
CMD ["python", "app.py"]

8. Pulisci i File Temporanei e le Cache

Rimuovi qualsiasi file temporaneo o cache che non è necessario nell’immagine finale per ridurre la dimensione dell’immagine.

Esempio di Pulizia

RUN apt-get update && apt-get install -y \
    build-essential \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

9. Imposta un Entry Point Robusto

Usa ENTRYPOINT insieme a CMD per definire un comportamento predefinito ma personalizzabile per i container.

Esempio di Utilizzo di ENTRYPOINT e CMD

ENTRYPOINT ["python"]
CMD ["app.py"]

Questo permette di eseguire docker run myimage myscript.py per eseguire un file diverso da app.py.

10. Documenta il Dockerfile

Aggiungi commenti e metadata che descrivano lo scopo delle varie istruzioni nel Dockerfile. Usa etichette (LABEL) per aggiungere informazioni utili come l’autore e la versione dell’immagine.

Esempio di Commenti e Metadata

# Set the base image
FROM python:3.9-slim

# Maintainer label
LABEL maintainer="yourname@example.com"

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . /app

# Define working directory
WORKDIR /app

# Run the application
CMD ["python", "app.py"]

11. Testa Localmente Prima di Pushare

Prima di pubblicare la tua immagine, testala localmente per assicurarti che funzioni correttamente. Utilizza docker build e docker run per testare ogni step del Dockerfile.

Esempio di Test Locale

docker build -t myapp .
docker run -it --rm myapp

12. Riduci l’Esposizione delle Porte

Esporre solo le porte necessarie e limitare l’accesso esterno alle porte non necessarie migliora la sicurezza del container.

Esempio di Esporre Porte Selezionate

EXPOSE 80

Conclusione

Seguire queste best practices nella scrittura di Dockerfile ti permetterà di creare immagini Docker che sono efficienti, sicure e facili da gestire. Dalla scelta della base image all’uso di multi-stage builds, ogni pratica contribuisce a migliorare le prestazioni e la sicurezza delle tue applicazioni containerizzate. Prendendo il tempo per ottimizzare i tuoi Dockerfile, puoi assicurarti che le tue immagini siano leggere, veloci da costruire e pronte per la produzione.