Docker Compose nel 2026: Applicazioni Multi-Container, Networking e Domande per Colloqui DevOps

Tutorial Docker Compose per applicazioni multi-container con networking, volumi e deployment in produzione. Include domande frequenti nei colloqui DevOps.

Docker Compose nel 2026: Applicazioni Multi-Container, Networking e Domande per Colloqui DevOps

Docker Compose rimane lo strumento preferito per definire ed eseguire applicazioni Docker multi-container nel 2026. Che si tratti di orchestrare uno stack di sviluppo locale o di prepararsi per un colloquio DevOps, la comprensione del networking di Compose, delle dipendenze tra servizi e dei pattern di produzione distingue gli sviluppatori junior dai professionisti senior.

Concetto Chiave

Docker Compose utilizza un formato YAML dichiarativo per definire servizi, reti e volumi in un unico file. L'esecuzione di docker compose up avvia l'intero stack applicativo con networking isolato e storage persistente.

Comprendere l'Architettura di Docker Compose

Docker Compose opera secondo un principio semplice: definire i servizi dell'applicazione in un file compose.yaml (la convenzione moderna che sostituisce docker-compose.yml), e Compose gestisce la creazione dei container, il networking e la gestione del ciclo di vita.

La specifica Docker Compose definisce tre concetti fondamentali:

  • Services: Configurazioni dei container inclusi immagine, contesto di build, variabili d'ambiente e limiti di risorse
  • Networks: Canali di comunicazione isolati tra i servizi
  • Volumes: Storage persistente che sopravvive ai riavvii dei container
yaml
# compose.yaml
services:
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/app
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend

  db:
    image: postgres:16
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=app
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - backend

networks:
  backend:
    driver: bridge

volumes:
  postgres_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Questa configurazione dimostra diversi pattern pronti per la produzione: health check per l'ordinamento delle dipendenze, Docker secrets per dati sensibili, volumi nominati per la persistenza e definizioni di rete esplicite.

Approfondimento sul Networking di Docker Compose

Per impostazione predefinita, Compose crea una singola rete per l'applicazione. Tutti i servizi si uniscono a questa rete e possono raggiungersi a vicenda utilizzando il nome del servizio come hostname. Comprendere questo modello di networking è fondamentale per una successiva migrazione a Kubernetes.

yaml
# compose.yaml
services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    networks:
      - frontend-net
      - backend-net

  api:
    build: ./api
    networks:
      - backend-net

  cache:
    image: redis:7-alpine
    networks:
      - backend-net

  db:
    image: postgres:16
    networks:
      - backend-net

networks:
  frontend-net:
    driver: bridge
  backend-net:
    driver: bridge
    internal: true

Il flag internal: true impedisce alla rete backend di accedere a Internet. Il servizio frontend collega entrambe le reti, fungendo da unico punto di ingresso. Questa segmentazione della rete rispecchia le pratiche di sicurezza in produzione.

Risoluzione DNS

Il server DNS integrato di Docker risolve automaticamente i nomi dei servizi. Il servizio api raggiunge il database su db:5432 senza alcuna configurazione manuale degli IP.

Build Multi-Stage con Compose

Le immagini di produzione dovrebbero essere minimali. Le build multi-stage combinate con i profili di Compose permettono configurazioni diverse per sviluppo e produzione.

dockerfile
# api/Dockerfile
# Stage 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:22-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

# Stage 3: Development
FROM node:22-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
USER node
CMD ["npm", "run", "dev"]
yaml
# compose.yaml
services:
  api:
    build:
      context: ./api
      target: ${BUILD_TARGET:-production}
    volumes:
      - ${API_VOLUMES:-./api/dist:/app/dist:ro}
    profiles:
      - ${COMPOSE_PROFILES:-prod}

L'esecuzione di BUILD_TARGET=development COMPOSE_PROFILES=dev docker compose up avvia la configurazione di sviluppo con hot reload.

Dipendenze dei Servizi e Health Check

La direttiva depends_on controlla l'ordine di avvio, ma i container avviati non significano servizi pronti. Gli health check risolvono questo problema di timing, un pattern frequentemente richiesto nei colloqui DevOps.

yaml
# compose.yaml
services:
  api:
    build: ./api
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
      migrations:
        condition: service_completed_successfully

  migrations:
    build: ./api
    command: npm run migrate
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

  cache:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 3

Esistono tre condizioni di dipendenza:

  • service_started: Default, il container è stato avviato
  • service_healthy: L'health check è superato
  • service_completed_successfully: Il container termina con codice 0 (per container di inizializzazione)

Pronto a superare i tuoi colloqui su DevOps?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Docker Compose per lo Sviluppo Locale

Gli ambienti di sviluppo beneficiano di bind mount, override di configurazione e strumenti di debug. Il file compose.override.yaml viene automaticamente unito a compose.yaml.

yaml
# compose.yaml (configurazione base)
services:
  api:
    build: ./api
    environment:
      - NODE_ENV=production

  db:
    image: postgres:16
yaml
# compose.override.yaml (override di sviluppo)
services:
  api:
    build:
      target: development
    volumes:
      - ./api:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=app:*
    ports:
      - "9229:9229"

  db:
    ports:
      - "5432:5432"

Il volume anonimo /app/node_modules impedisce ai node_modules dell'host di sovrascrivere le dipendenze installate nel container.

Pattern di Deployment in Produzione

Docker Compose funziona per deployment in produzione su singolo host. Per l'orchestrazione multi-host, Kubernetes con Helm offre una migliore scalabilità, ma Compose rimane valido per applicazioni più piccole.

yaml
# compose.prod.yaml
services:
  api:
    image: registry.example.com/api:${VERSION:-latest}
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - api

La chiave deploy configura limiti di risorse, numero di repliche e politiche di riavvio. L'esecuzione di docker compose -f compose.prod.yaml up -d avvia lo stack di produzione in modalità detached.

Variabili d'Ambiente e Gestione dei Secrets

Le configurazioni sensibili richiedono una gestione appropriata. Docker Compose supporta diversi approcci, dai file .env ai Docker secrets.

bash
# .env
POSTGRES_PASSWORD=dev_password_only
API_SECRET_KEY=local_dev_key
yaml
# compose.yaml
services:
  api:
    environment:
      - API_SECRET_KEY  # Eredita dalla shell o da .env
      - DATABASE_URL=postgres://user:${POSTGRES_PASSWORD}@db:5432/app
    env_file:
      - ./config/api.env

Per la produzione, i Docker secrets offrono maggiore sicurezza montando i dati sensibili come file anziché variabili d'ambiente:

yaml
# compose.prod.yaml
services:
  api:
    secrets:
      - api_key
      - db_password
    environment:
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  api_key:
    external: true
  db_password:
    file: ./secrets/db_password.txt
Nota sulla Sicurezza

Non committare mai file .env contenenti secrets di produzione nel controllo versione. Per i deployment in produzione, utilizzare gestori di secrets esterni come HashiCorp Vault o soluzioni dei cloud provider.

Domande Frequenti nei Colloqui DevOps su Docker Compose

Gli intervistatori testano la comprensione dei concetti di Compose attraverso scenari pratici. Queste domande appaiono frequentemente nei colloqui DevOps e platform engineering.

D: Come comunicano i container in una rete Compose?

Docker crea una rete bridge dedicata per ogni progetto Compose. I servizi comunicano usando i nomi dei servizi come hostname. Il server DNS integrato risolve questi nomi agli indirizzi IP dei container. Il traffico esterno raggiunge i servizi solo attraverso le porte esplicitamente pubblicate.

D: Cosa succede quando si esegue docker compose up con container esistenti?

Compose confronta la configurazione attuale con i container in esecuzione. I servizi invariati continuano a funzionare. I servizi modificati vengono ricreati con le nuove impostazioni. I nuovi servizi vengono avviati da zero. I servizi rimossi vengono fermati ed eliminati.

D: Come si gestiscono le migrazioni del database in Compose?

Esistono due pattern. Primo: utilizzare un container di inizializzazione con dipendenza service_completed_successfully:

yaml
services:
  migrate:
    image: api:latest
    command: npm run migrate
    depends_on:
      db:
        condition: service_healthy

  api:
    depends_on:
      migrate:
        condition: service_completed_successfully

Secondo: includere la logica di migrazione nello script di avvio dell'applicazione, verificando e applicando le migrazioni in sospeso prima di accettare il traffico.

D: Qual è la differenza tra volumi e bind mount?

I volumi nominati sono gestiti da Docker, memorizzati in /var/lib/docker/volumes, e sono portabili tra host. I bind mount mappano direttamente le directory dell'host nei container, utili per lo sviluppo ma dipendenti dall'ambiente. I volumi supportano driver per storage remoto come NFS o block storage cloud.

D: Qual è la differenza tra docker-compose e docker compose?

Il comando con trattino docker-compose era lo strumento standalone V1 basato su Python, ora deprecato. Il comando con spazio docker compose è l'implementazione V2 basata su Go integrata nella CLI di Docker. V2 è più veloce, supporta completamente la specifica Compose e riceve sviluppo attivo.

Debug delle Applicazioni Compose

La risoluzione dei problemi nelle applicazioni containerizzate richiede tecniche specifiche. Questi comandi rivelano cosa sta succedendo nello stack Compose:

bash
# Visualizzare i log di tutti i servizi
docker compose logs -f

# Log di un servizio specifico con timestamp
docker compose logs -f --timestamps api

# Eseguire comando in un container in esecuzione
docker compose exec api sh

# Eseguire comando one-off (avvia nuovo container)
docker compose run --rm api npm test

# Visualizzare utilizzo risorse
docker compose top
docker stats

# Ispezionare configurazione di rete
docker network inspect project_backend

# Validare file compose
docker compose config

Il comando docker compose config unisce tutti i file compose e mostra la configurazione finale: prezioso per il debug di problemi di interpolazione delle variabili.

Conclusione

  • Docker Compose definisce applicazioni multi-container in un singolo file YAML con servizi, reti e volumi
  • I servizi comunicano via DNS usando i nomi dei servizi come hostname all'interno della rete bridge predefinita
  • Gli health check con condizioni service_healthy assicurano il corretto ordinamento all'avvio
  • Il file compose.override.yaml viene usato per impostazioni specifiche di sviluppo come bind mount e porte di debug
  • I deployment in produzione beneficiano di limiti di risorse, politiche di riavvio e Docker secrets per dati sensibili
  • La CLI docker compose (V2) sostituisce il deprecato docker-compose (V1) con migliori prestazioni e funzionalità

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Condividi

Articoli correlati