Cosa fa#
File YAML che descrive tutta l'infrastruttura di un'applicazione: servizi, reti, volumi, variabili d'ambiente. Con un solo comando (docker compose up) avvii tutto. Con un altro (docker compose down) spegni tutto.
Struttura del file#
# docker-compose.yml — struttura generale
version: "3.8"
services: # i container da avviare
nome-servizio:
image: ...
...
volumes: # storage persistente
nome-volume:
networks: # reti virtuali
nome-rete:Nome fisso per volumi e reti#
Docker usa il nome della cartella come prefisso per volumi e reti:
# cartella: infra-antonella/
# volume dichiarato: postgres_data
# risultato su Docker: infra-antonella_postgres_data
docker volume ls
# local infra-antonella_postgres_dataSe sposti il compose in un'altra cartella, il prefisso cambia e Docker crea un nuovo volume vuoto — perdendo i dati del vecchio.
La soluzione e usare il campo name: per fissare il nome indipendentemente dalla cartella:
# Senza name — dipende dalla cartella (fragile)
volumes:
postgres_data:
# Con name — nome fisso su Docker (portabile)
volumes:
postgres_data:
name: "n8n_postgres_data" # questo e il nome che vedi in docker volume ls
networks:
web:
name: web # stesso pattern per le reti
#esempio
docker-compose.yml
─────────────────────────────────────
services:
postgres-rag:
volumes:
- db-data:/var/lib/postgresql/data
↑
nome interno al compose
(come una variabile)
volumes:
db-data: ← stesso nome interno
name: postgres_rag_data
↑
nome fisico su Docker
(quello che vedi in "docker volume ls")Lo stesso vale per le reti. Il campo name: e il pattern corretto per qualsiasi servizio in produzione.
Aggiungi sempre name: esplicito a volumi e reti quando crei un nuovo compose. Evita il problema del prefisso e rende il progetto portabile su qualsiasi server senza dover migrare i dati.
Esempio reale annotato — Chatwoot#
services:
# Ancora YAML — definisce configurazione comune riusabile
base: &base
image: chatwoot/chatwoot:v3.11.0 # versione fissa, non latest
env_file: .env # variabili da file esterno
volumes:
- chatwoot_storage:/app/storage # volume named per i file upload
postgres:
image: pgvector/pgvector:pg16
container_name: chatwoot_postgres # nome fisso (invece di hash casuale)
restart: always # riavvia se crasha
ports:
- "127.0.0.1:5434:5432"
# 127.0.0.1 = solo localhost — non esposto a internet
# 5434 = porta sull'host (evita conflitti con postgres locale)
# 5432 = porta dentro il container
environment:
POSTGRES_DB: ${POSTGRES_DATABASE} # legge da .env
POSTGRES_USER: ${POSTGRES_USERNAME}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- chatwoot_db:/var/lib/postgresql/data # dati persistenti
networks:
- internal # solo rete interna — non raggiungibile da Traefik
redis:
image: redis:7-alpine # alpine = immagine minima, piu' sicura
container_name: chatwoot_redis
restart: always
networks:
- internal
rails:
<<: *base # copia tutto da &base
container_name: chatwoot_rails
command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]
networks:
- internal # parla con postgres e redis
- web # raggiungibile da Traefik
sidekiq:
<<: *base # stessa immagine di rails, comando diverso
container_name: chatwoot_sidekiq
command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
networks:
- internal # non ha bisogno di Traefik — solo DB e Redis
volumes:
chatwoot_storage: # file caricati dagli utenti
chatwoot_db: # dati postgres
networks:
internal:
driver: bridge # rete privata tra i container
web:
external: true # gia' esiste — creata da TraefikFlusso di una richiesta in questo stack#
sequenceDiagram
participant U as Utente
participant T as Traefik
participant R as Rails :3000
participant PG as Postgres :5432
participant RD as Redis :6379
U->>T: GET https://chat.dominio.it
T->>R: GET http://rails:3000 (rete web)
R->>PG: SELECT * FROM conversations (rete internal)
PG->>R: risultati
R->>RD: cache lookup (rete internal)
RD->>R: cache hit
R->>T: 200 OK + HTML
T->>U: 200 OK + HTML cifrato TLS
Anchor YAML — &base e <<: *base#
L'anchor evita di ripetere la stessa configurazione:
# Senza anchor — ripetizione
rails:
image: chatwoot/chatwoot:v3.11.0
env_file: .env
volumes:
- chatwoot_storage:/app/storage
sidekiq:
image: chatwoot/chatwoot:v3.11.0 # ripetuto
env_file: .env # ripetuto
volumes:
- chatwoot_storage:/app/storage # ripetuto
# Con anchor — DRY (Don't Repeat Yourself)
base: &base
image: chatwoot/chatwoot:v3.11.0
env_file: .env
volumes:
- chatwoot_storage:/app/storage
rails:
<<: *base # copia tutto da base
command: [...] # aggiunge solo quello che cambia
sidekiq:
<<: *base # stessa cosa
command: [...]Comandi essenziali#
docker compose up -d # avvia tutto in background
# -d = detached
docker compose down # spegne tutto
docker compose down -v # spegne e cancella volumi
# -v = volumes — DISTRUTTIVO
docker compose logs -f rails # segue log di un servizio
# -f = follow
docker compose logs --tail 20 # ultime 20 righe di tutti i servizi
# --tail N = ultime N righe
docker compose restart rails # riavvia un singolo servizio
docker compose exec rails bash # entra nel container rails
# exec = esegui comando in container gia' avviato
docker compose run --rm rails bash
# run = avvia container temporaneo
# --rm = remove, elimina dopo l'uso
docker compose ps # stato di tutti i servizi
docker compose pull # scarica versioni aggiornate delle immagini
docker compose config # mostra il compose risolto: variabili .env sostituite,
# nomi fisici di volumi e reti, path assoluti dei bind mount
# utile per debuggare prima di avviaredocker compose down -v cancella i volumi — il database sparisce. Usalo solo se hai un backup o vuoi resettare completamente.
docker compose exec -it rails bash e' il modo per "entrare" in un container e girare come se fossi dentro un mini Linux. Da li' puoi ispezionare file, variabili d'ambiente, connessioni.
Collegato a#
- docker-image — le immagini usate nei servizi
- docker-network-defense — le reti definite nel file
- docker-security — volumi, porte, permessi
- system — categoria


