Docker per Sviluppatori: Guida Rapida 2025
Docker per sviluppatori: container, Dockerfile, Docker Compose. Guida pratica 2025 per containerizzare applicazioni e standardizzare ambienti di sviluppo.
Hai mai sentito "sulla mia macchina funziona"? Docker risolve esattamente questo problema. Invece di installare dipendenze diverse su ogni computer, impacchetti la tua applicazione con tutto ciò che serve in un container che gira identico ovunque: sul tuo laptop, sul server di staging, in produzione. Vediamo come iniziare con Docker da sviluppatore nel 2025.
Concetti fondamentali
Prima di scrivere codice, chiariamo i termini:
- Dockerfile: un file di testo con istruzioni per costruire un'immagine
- Immagine: il "template" immutabile che contiene app + dipendenze
- Container: un'istanza in esecuzione di un'immagine
- Registry: dove si archiviano le immagini (Docker Hub, GitHub Container Registry)
Pensa al Dockerfile come a una ricetta, all'immagine come al piatto preparato, e al container come al piatto servito al cliente.
Installazione e primi passi
Installare Docker
# macOS/Windows: scarica Docker Desktop
# https://www.docker.com/products/docker-desktop
# Linux (Ubuntu/Debian)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Verifica installazione
docker --version
docker run hello-world
Comandi essenziali
# Scaricare un'immagine
docker pull node:20-alpine
# Vedere immagini locali
docker images
# Eseguire un container
docker run -it node:20-alpine sh
# Vedere container in esecuzione
docker ps
# Vedere tutti i container (anche fermi)
docker ps -a
# Fermare un container
docker stop container_id
# Rimuovere un container
docker rm container_id
# Rimuovere un'immagine
docker rmi image_id
Il tuo primo Dockerfile
Creiamo un Dockerfile per un'applicazione Node.js:
# Usa un'immagine base leggera
FROM node:20-alpine
# Crea directory di lavoro
WORKDIR /app
# Copia prima package.json per sfruttare la cache
COPY package*.json ./
# Installa dipendenze
RUN npm ci --only=production
# Copia il resto del codice
COPY . .
# Esponi la porta
EXPOSE 3000
# Comando di avvio
CMD ["node", "server.js"]
Build e run
# Costruisci l'immagine
docker build -t myapp:1.0 .
# Esegui il container
docker run -p 3000:3000 myapp:1.0
# In background (detached)
docker run -d -p 3000:3000 myapp:1.0
Best practice 2025
1. Usa immagini base leggere
# Evita (900MB+)
FROM node:20
# Preferisci (150MB)
FROM node:20-alpine
# Ancora meglio per produzione (50MB)
FROM node:20-alpine AS builder
# ... build steps ...
FROM gcr.io/distroless/nodejs20
COPY --from=builder /app /app
CMD ["server.js"]
Le immagini alpine e distroless riducono la superficie di attacco e i tempi di deploy.
2. Multi-stage build
Separa build e runtime per immagini più piccole e sicure:
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
Risultato: immagini 50-85% più piccole rispetto a build single-stage.
3. Non eseguire come root
FROM node:20-alpine
# Crea utente non-root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
COPY --chown=nodejs:nodejs . .
# Passa all'utente non-root
USER nodejs
CMD ["node", "server.js"]
Il 58% dei container in produzione gira ancora come root: non fare questo errore.
4. Usa .dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.local
*.md
Dockerfile
.dockerignore
coverage
.nyc_output
tests
Riduce dimensione immagine ed evita di esporre file sensibili.
5. Ordine layer per cache
# Prima le istruzioni che cambiano meno
FROM node:20-alpine
WORKDIR /app
# Package.json cambia raramente
COPY package*.json ./
RUN npm ci
# Codice cambia spesso - mettilo per ultimo
COPY . .
Docker riusa i layer cachati se non sono cambiati. Ordine corretto = build 70% più veloci.
6. Health check
FROM node:20-alpine
WORKDIR /app
COPY . .
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
Senza healthcheck, Docker non sa se l'applicazione è davvero funzionante.
Docker Compose per sviluppo locale
Docker Compose orchestra più container con un solo file:
# docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://user:pass@db:5432/mydb
volumes:
- .:/app
- /app/node_modules
depends_on:
- db
- redis
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
postgres_data:
Comandi Compose
# Avvia tutti i servizi
docker compose up
# In background
docker compose up -d
# Rebuild e avvia
docker compose up --build
# Ferma tutto
docker compose down
# Ferma e rimuovi volumi
docker compose down -v
# Logs di un servizio
docker compose logs -f app
Pattern comuni per sviluppatori
Hot reload in sviluppo
# docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app # Monta codice sorgente
- /app/node_modules # Esclude node_modules
command: npm run dev
Dockerfile per sviluppo vs produzione
# Dockerfile.dev
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install # Include devDependencies
COPY . .
CMD ["npm", "run", "dev"]
# Dockerfile (produzione)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]
Database locale con persistenza
services:
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: localdev
volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Debugging container
# Entra in un container in esecuzione
docker exec -it container_name sh
# Vedi logs
docker logs container_name
docker logs -f container_name # follow
# Ispeziona container
docker inspect container_name
# Statistiche risorse
docker stats
# Vedi processi nel container
docker top container_name
Errori comuni da evitare
- Immagini enormi: usa alpine, multi-stage build, e .dockerignore
- Root in container: crea e usa un utente non-root
- Secrets nel Dockerfile: mai ENV con password, usa secrets o variabili a runtime
- Tag latest in produzione: usa sempre tag specifici (node:20.10.0-alpine)
- Un processo per container: non mettere app + database nello stesso container
- Ignorare healthcheck: aggiungi sempre controlli di salute
Conclusione
Docker ha rivoluzionato il modo in cui sviluppiamo e distribuiamo software. Nel 2025 non è più opzionale: è uno standard. I punti chiave per iniziare:
- Parti da immagini alpine o distroless
- Usa multi-stage build per produzione
- Non eseguire mai come root
- Sfrutta Docker Compose per sviluppo locale
- Aggiungi sempre .dockerignore e healthcheck
- Ordina le istruzioni Dockerfile per massimizzare la cache
Una volta che hai dockerizzato la tua app, il deploy diventa semplice: la stessa immagine gira identica su qualsiasi piattaforma che supporta container.