SSD Nodes Learn 8GB di RAM — $66/anno
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-02

Docker Compose: comandi essenziali per server reali

Una guida pratica ai comandi Compose V2 per server: ciclo di vita, modifiche, log, shell, reti, volumi e pulizia sicura, con l'errore di percorso più comune.

I comandi Compose che utilizzerai davvero

Docker Compose include più di quaranta sottocomandi. Nelle attività quotidiane su un server se ne usano circa una dozzina. Questa pagina li raggruppa in base all'operazione da eseguire, indica una motivazione chiara per ciascuno e rimanda all'approfondimento quando un comando presenta un problema non immediato.

Tutto il contenuto qui usa Compose V2: docker compose con uno spazio, non il vecchio script docker-compose. V2 è un plugin Go che viene installato con Docker Engine, mentre V1 non è più incluso nei pacchetti attuali. Per questo, su un'installazione Ubuntu nuova a luglio 2026, un comando docker-compose: command not found è previsto e non indica un problema. Verifica con docker compose version. Se non restituisce alcun risultato, installa il pacchetto docker-compose-plugin.

Ogni comando riportato di seguito deve essere eseguito dalla directory che contiene compose.yaml, perché Compose ricava il nome del progetto da quella directory e cerca il file al suo interno. Se esegui lo stesso comando un livello più in alto, Compose si interrompe con no configuration file provided: not found. Se il formato del file è nuovo per te, inizia da un primo file Compose su un VPS e poi torna qui per consultare i comandi.

Ciclo di vita: i quattro comandi che si digitano e quello che rimuove i container

docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose down

up -d crea la rete, crea i container, li avvia e restituisce il controllo. Restituisce il controllo non appena i container sono creati. Per questo uno script di deploy che esegue subito dopo un controllo curl spesso non riesce al primo tentativo. up -d --wait resta in attesa finché ogni servizio che dichiara un healthcheck non segnala lo stato healthy. Termina con un codice diverso da zero se uno dei servizi non raggiunge mai questo stato. Il flag è efficace solo quanto il controllo su cui si basa. Scrivi quindi un healthcheck di cui Compose possa fidarsi prima di usarlo nell'automazione.

stop arresta i container e li conserva. Di conseguenza, start riporta in esecuzione gli stessi container con lo stesso writable layer. down arresta i container e poi rimuove i container e la rete del progetto. Tutto ciò che è stato scritto all'interno del container e al di fuori di un volume viene eliminato insieme a essi. È l'equivoco più costoso in Compose. La differenza completa tra down e stop spiega in quali casi questo comportamento è rilevante.

restart non esegue un reload. Arresta e avvia lo stesso container con la configurazione già presente. Di conseguenza, una variabile d'ambiente modificata, un nuovo image tag o una mappatura di porte modificata non producono alcun effetto. Per applicare una modifica al file, esegui di nuovo up -d. Compose confronta ogni servizio con il container in esecuzione e ricrea solo quelli la cui configurazione è cambiata.

Applicare una modifica: ricreare, eseguire il pull o ricostruire

docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build web

up -d non esegue alcuna operazione se non è cambiato nulla, ed è per questo che può essere eseguito più volte in sicurezza. --force-recreate forza il confronto e sostituisce ogni container anche quando la configurazione è identica, quindi è il modo più rapido per eliminare uno stato anomalo all'interno del container.

L'aggiornamento di un'immagine richiede due comandi perché svolgono due operazioni diverse. pull scarica l'immagine corrente per ogni tag specificato nel file. up -d rileva quindi che l'ID dell'immagine del servizio non corrisponde più al container in esecuzione e lo ricrea. Se si omette il pull, up -d continua a eseguire il latest del mese scorso senza generare errori.

build si applica ai servizi che dichiarano una sezione build: invece di una sezione image:. up -d --build esegue la build e l'avvio in un unico passaggio, che è il ciclo normale mentre si modifica il codice. Usare --no-cache solo quando un layer nella cache è chiaramente obsoleto, perché ricostruisce ogni layer da zero.

Vedere cosa è in esecuzione

docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose ls

ps elenca solo i container in esecuzione. Un servizio che si è arrestato durante l'avvio non è visibile finché non aggiungi -a. Pertanto, un container assente da ps mentre ps -a lo mostra come Exited (1) è il comportamento normale di un errore di avvio. Leggi il codice di uscita, quindi leggi i log.

logs -f segue contemporaneamente ogni servizio e antepone a ogni riga il nome del servizio. Questa è la vista da usare quando i servizi comunicano tra loro e l'ordine degli eventi è importante. Specifica un servizio per restringere l'output. --tail=100 è importante per un container attivo da un mese, perché per impostazione predefinita stampa l'intera cronologia e riempie il terminale. --since 15m risponde alla domanda che di solito interessa: cosa è successo durante il riavvio appena eseguito.

top elenca i processi all'interno di ogni container. In questo modo puoi distinguere tra "il container è in esecuzione" e "il processo al suo interno è in esecuzione". ls esce dalla directory corrente ed elenca tutti i progetti Compose presenti sull'host con il relativo stato. Puoi così trovare lo stack avviato tre mesi fa.

Ottenere una shell all'interno di un servizio

docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web sh

exec esegue un comando all'interno di un container già avviato. run avvia un nuovo container dalla stessa definizione del servizio; serve quando il servizio non rimane attivo abbastanza a lungo per eseguire il comando al suo interno. Abbina sempre run a --rm, perché senza questa opzione ogni esecuzione lascia un container arrestato e questi si accumulano finché docker compose ps -a diventa illeggibile.

Prova sh prima di bash. Le immagini basate su Alpine non includono bash e l'errore visualizzato è exec: "bash": executable file not found in $PATH. Aggiungere --no-deps a run ignora le dipendenze del servizio ed evita che un rapido controllo della configurazione avvii l'intero database.

run --rm web env è il modo più rapido per vedere l'ambiente effettivamente ricevuto da un servizio, dopo l'unione di ogni file .env, blocco environment: e variabile della shell. Quando un valore è errato, l'ordine di unione è solitamente la causa. come Compose risolve i file env e i secret spiega quale origine ha la precedenza.

Reti, porte e risoluzione dei nomi

docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networks

Compose inserisce tutti i servizi in una rete di progetto e ogni nome di servizio diventa un nome DNS al suo interno. L'esecuzione di getent hosts db all'interno di web stampa l'indirizzo IP del container quando la risoluzione funziona e non stampa nulla quando non funziona. In questo modo risponde alla domanda «questi container possono comunicare tra loro?» in due secondi. Se il nome viene risolto ma la connessione viene rifiutata, il processo all'interno di db è associato a 127.0.0.1 invece che a 0.0.0.0. Di conseguenza non accetta pacchetti dagli altri container. Il resto di questo modello è spiegato in come funzionano le reti Compose e il DNS dei servizi.

port web 80 stampa l'indirizzo e la porta dell'host su cui è pubblicata una porta del container. Questo evita di dover indovinare quando la mappatura proviene da una variabile. La pubblicazione di una porta crea anche una regola firewall gestita direttamente da Docker. Questa regola viene applicata prima delle regole definite dall'utente. Di conseguenza, un servizio che si riteneva privato può essere esposto a internet. Questo caso è descritto in perché le porte Docker pubblicate bypassano ufw.

Volumi e dati

docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -v

config --volumes stampa i volumi denominati dichiarati dal progetto, uno per riga. Questo è l’elenco di cui devi eseguire il backup. cp copia un file dentro o fuori da un container senza aprire una shell, usando il formato service:path sul lato in cui si trova il container.

down -v rimuove questi volumi denominati insieme ai container. È il comando corretto per smantellare uno stack di test, ma quello sbagliato per qualsiasi elemento che contenga dati importanti, perché non richiede conferma e non può essere annullato. I bind mount sopravvivono, perché risiedono nel filesystem dell’host. Questa differenza nell’ampiezza dell’impatto è uno dei motivi per cui conviene scegliere consapevolmente tra bind mount e volumi denominati.

Pulizia che libera spazio su disco senza perdere dati

docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune

--remove-orphans elimina i container appartenenti al progetto che non compaiono più nel file. È esattamente ciò che accade dopo la ridenominazione di un servizio. Senza questa opzione, tali container continuano a essere eseguiti e restano invisibili a docker compose ps.

docker system df mostra dove è stato utilizzato lo spazio su disco prima di eliminare qualsiasi elemento. Suddivide immagini, container, volumi locali e cache di compilazione e indica per ciascuno lo spazio recuperabile. image prune -a rimuove tutte le immagini non referenziate da alcun tag. Su un server che ha scaricato diverse versioni di un'immagine di grandi dimensioni, questa operazione consente solitamente di recuperare più spazio. builder prune cancella la cache di compilazione, che cresce in modo silenzioso su qualsiasi server che compila autonomamente le proprie immagini.

Nessuno di questi comandi modifica un volume denominato. Solo docker volume prune e docker compose down -v lo fanno.

Verifica del file prima che causi problemi

docker compose config --quiet
docker compose config --services
docker compose --dry-run up -d

config --quiet convalida e non stampa nulla in caso di successo, quindi va usato in una fase di pre-deploy o in un hook Git. config senza argomenti stampa il file completamente unito e interpolato. Questo consente di verificare che una variabile sia stata risolta e che un file di override sia stato applicato nel modo previsto. Una variabile non impostata viene visualizzata come valore vuoto, insieme all'avviso The "X" variable is not set. Defaulting to a blank string.

--dry-run è un flag globale, non un flag del sottocomando, quindi va inserito prima di up. Stampa ogni azione che Compose eseguirebbe senza apportare modifiche. Sono trenta secondi ben spesi prima di un down su uno stack importante.

Uso di più file, profili e progetti

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d

Più flag -f vengono uniti nell'ordine indicato. I file successivi sovrascrivono quelli precedenti chiave per chiave. Questo è il metodo standard per mantenere un file di base con una piccola sovrascrittura per la produzione. Le regole però differiscono per elenchi e mappe. Prima di eseguire il debug di un comportamento inatteso, leggi come Compose unisce più file.

--profile avvia i servizi associati a quel profilo insieme a quelli senza profilo. In questo modo gli strumenti di debug restano esclusi da una normale up. -p imposta il nome del progetto, così due copie dello stesso stack possono essere eseguite una accanto all'altra con reti e nomi dei volumi separati. Per ripristinare lo stack dopo un riavvio non devi digitare alcun comando. Devi usare un'unità che esegua il comando automaticamente, come descritto in avvio degli stack Compose all'avvio del sistema.

FAQ

Che cosa ha sostituito docker-compose con un trattino?

Compose V2, richiamato come docker compose con uno spazio. È un plugin incluso in Docker Engine e lo strumento Python V1 non viene più installato dai pacchetti attuali. Se la forma con lo spazio non produce alcun output, installare il pacchetto docker-compose-plugin per la propria distribuzione. Aggiornare gli script obsoleti alla forma con lo spazio invece di aggiungere un alias, perché V2 supporta flag che V1 non aveva.

Perché docker compose restart non rileva la modifica alla configurazione?

restart arresta e riavvia il container esistente usando la configurazione con cui è stato creato e non rilegge mai compose.yaml. Qualsiasi modifica alle variabili d'ambiente, alle porte, ai volumi o al tag dell'immagine richiede docker compose up -d, che confronta ogni servizio con il container in esecuzione e ricrea quelli diversi. Aggiungere --force-recreate per forzare la sostituzione anche quando il file non è cambiato.

Come si aggiorna un servizio a un'immagine più recente?

Eseguire docker compose pull, quindi docker compose up -d. Il pull scarica l'immagine corrente per ogni tag nel file e up -d ricrea ogni servizio il cui ID dell'immagine non corrisponde più a quello del container. L'esecuzione autonoma di up -d riutilizza l'immagine già presente sul disco. Per questo uno stack bloccato su latest può rimanere su una build vecchia di mesi senza visualizzare alcun errore.

Quali comandi di pulizia sono sicuri su un server in produzione?

docker system df, docker image prune -a e docker builder prune rimuovono solo le immagini e la cache, quindi i servizi in esecuzione continuano a funzionare e i volumi denominati non vengono modificati. La coppia pericolosa è docker compose down -v e docker volume prune, che elimina i volumi denominati senza chiedere conferma. Eseguire prima docker compose config --volumes per sapere che cosa è a rischio.

È possibile eseguire un comando senza avviare l'intero stack?

Sì. docker compose run --rm --no-deps web sh avvia un singolo container dalla definizione del servizio web, ignora le dipendenze e rimuove il container quando si esce. Usare invece exec quando il container è già in esecuzione, perché exec si collega al processo attivo e mostra lo stato effettivo del servizio.