Esegui Docker Compose come servizio Linux con systemd
Avvio di Docker Compose all'avvio, gestito da systemd.
Docker Compose su un server Linux dovrebbe avviarsi all’avvio, fermarsi in modo pulito allo spegnimento e sopravvivere ai riavvii senza intervento manuale.
Docker Compose non è Kubernetes, e questo va bene per i carichi di lavoro a cui questa guida si rivolge. Per molti sistemi reali, un progetto Compose su un singolo host Linux è la quantità giusta di infrastruttura: semplice, leggibile, facile da backuppare e sufficiente per strumenti interni, progetti laterali, servizi self-hosted, ambienti di staging, piccole applicazioni in produzione e infrastrutture per sviluppatori.

Il pezzo mancante è solitamente la gestione del servizio. Eseguire questo manualmente non è sufficiente:
docker compose up -d
Un singolo comando avvia lo stack, ma non documenta come lo stack dovrebbe avviarsi all’avvio, fermarsi durante lo spegnimento, ricaricarsi dopo le modifiche, scrivere i log, riprendersi dai guasti o essere aggiornato in modo sicuro. È qui che systemd aiuta.
Questa guida illustra come eseguire un progetto Docker Compose come servizio Linux con systemd — file unit, ordine di avvio, aggiornamenti, log e backup. La divisione delle responsabilità è deliberata: Docker esegue i container, Compose definisce lo stack e systemd avvia e ferma il progetto sull’host. Fa parte di Strumenti per Sviluppatori - Una guida ai flussi di lavoro di sviluppo.
Quando ha senso usare Docker Compose come servizio
Eseguire Compose sotto systemd ha senso quando si ha:
- Un singolo server Linux
- Una piccola applicazione self-hosted
- Uno stack di reverse proxy
- Uno stack di monitoraggio
- Una piattaforma di sviluppo locale
- Uno strumento interno
- Un ambiente di staging
- Un semplice servizio di produzione con limiti noti
Esempi:
- Nginx Proxy Manager
- Traefik
- Gitea
- Grafana e Prometheus
- PostgreSQL più una piccola app web
- Uptime Kuma
- Servizi ausiliari per Home Assistant
- Registro privato
- API interna più worker più Redis
Compose è una buona scelta quando il modello operativo è ancora comprensibile da una persona che legge una directory.
Quando Docker Compose non è sufficiente
Usa qualcos’altro quando hai bisogno di:
- Schedulazione multi-nodo
- Riassegnazione automatica tra host
- Scoperta dei servizi a livello di cluster
- Autoscaling orizzontale
- Distribuzioni rolling su molte macchine
- Identità del carico di lavoro granulare
- Policy di rete complesse
- Operazioni di piattaforma multi-team su larga scala
A quel punto, Kubernetes, Nomad, Swarm o una piattaforma gestita potrebbero essere più adatti.
La mia regola pratica è evitare di usare Kubernetes solo per saltare l’apprendimento di systemd, e evitare di usare Compose quando il carico di lavoro ha chiaramente bisogno di orchestrazione tra più host.
L’architettura di base
Una configurazione pulita separa i file del progetto, l’unità systemd e i dati persistenti sull’host. Il progetto Compose risiede sotto /opt/myapp/ con compose.yaml, .env, data/, backups/ e script opzionali come scripts/update.sh. Il file unit systemd si trova a /etc/systemd/system/myapp.service.
Ogni livello ha un compito chiaro: Docker esegue i container, Compose definisce lo stack dell’applicazione, systemd avvia e ferma il progetto Compose all’avvio e allo spegnimento, il filesystem dell’host memorizza i dati persistenti, i backup restano espliciti e gli aggiornamenti passano attraverso passaggi scriptizzati e verificabili. Questo layout è deliberatamente noioso, perché un’infrastruttura noiosa è più facile da riparare quando qualcosa si rompe alle 2 del mattino.
Prepara la directory del progetto Compose
Crea una directory sotto /opt:
sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp
Crea un file Compose:
nano compose.yaml
Esempio:
services:
web:
image: nginx:stable
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
healthcheck:
test: ["CMD-SHELL", "nginx -t || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes: {}
Crea la directory dei contenuti:
mkdir -p html
echo "Hello from Docker Compose" > html/index.html
Testa manualmente prima:
docker compose up -d
docker compose ps
docker compose logs --tail=50
Poi fermalo prima di affidare il ciclo di vita a systemd:
docker compose down
Non creare un servizio systemd finché il progetto Compose non funziona manualmente. Mentre testi, tieni a portata di mano il Docker Compose Cheatsheet per ps, logs, pull e struttura del progetto.
Usa il comando moderno docker compose
Docker Engine e il plugin Compose devono essere installati prima di scrivere un file unit. Su Ubuntu, Installare Docker su Ubuntu illustra APT, Snap, modalità rootless e la sicurezza post-installazione in modo da finire con un comando docker compose funzionante.
Usa questo:
docker compose version
Non questo:
docker-compose version
Il vecchio binario docker-compose esiste ancora su molte macchine, ma Docker moderno usa Compose come plugin della CLI Docker.
Nei file di servizio e negli script, preferisci:
/usr/bin/docker compose
Puoi trovare il percorso di Docker con:
command -v docker
Di solito è:
/usr/bin/docker
Crea un servizio systemd per Docker Compose
Se i file unit sono nuovi per te, Eseguire qualsiasi eseguibile come servizio in Linux spiega Type, ExecStart, systemctl e il flusso di lavoro generale di systemd. Questa sezione applica questi modelli specificamente a uno stack Compose.
Crea il file di servizio:
sudo nano /etc/systemd/system/myapp.service
Usa questa unità:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Ricarica systemd:
sudo systemctl daemon-reload
Avvia il servizio:
sudo systemctl start myapp.service
Abilitalo all’avvio:
sudo systemctl enable myapp.service
Controlla lo stato:
systemctl status myapp.service
Controlla i container:
cd /opt/myapp
docker compose ps
Perché Type=oneshot e RemainAfterExit=yes?
Questa è la parte che molte guide sbagliano in modo sottile.
docker compose up -d avvia i container in modalità staccata ed esce, quindi non c’è un processo Compose in primo piano in esecuzione continua per systemd da supervisionare. L’unità systemd non dovrebbe fingere che docker compose up -d sia un daemon in esecuzione continua.
Usa:
Type=oneshot
RemainAfterExit=yes
Questo dice a systemd:
- Esegui il comando di avvio.
- Considera l’unità attiva dopo che il comando è uscito con successo.
- Esegui
ExecStopquando il servizio viene fermato.
Questo corrisponde al comportamento effettivo di Compose staccato, ecco perché Type=oneshot con RemainAfterExit=yes è il predefinito corretto per la maggior parte degli stack.
Perché non Type=simple?
Con Type=simple, systemd si aspetta che il processo ExecStart continui a essere in esecuzione, ma docker compose up -d esce dopo aver avviato i container. Questo può far credere a systemd che il servizio sia terminato, chiamando poi la logica di stop o segnando l’unità come inattiva a seconda della configurazione.
Se vuoi Type=simple, di solito dovresti eseguire Compose in primo piano:
ExecStart=/usr/bin/docker compose up
Questo può funzionare, ma di solito non lo preferisco per gli stack Compose sui server. Container staccati più ExecStop esplicito sono più facili da gestire.
Un’unità più adatta alla produzione
Per un server reale, preferisco un’unità leggermente più rigorosa:
[Unit]
Description=MyApp Docker Compose stack
Documentation=https://example.com/docs/myapp
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env.systemd
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Dettagli importanti:
WorkingDirectorypunta al progetto Compose.ExecStartPrevalida la configurazione Compose.ExecReloadricrea i servizi modificati.ExecStopferma e rimuove i container del progetto Compose e la rete predefinita.EnvironmentFile=-...significa che il file è opzionale.
Crea il file di ambiente systemd opzionale:
nano /opt/myapp/.env.systemd
Esempio:
COMPOSE_PROJECT_NAME=myapp
Poi ricarica systemd:
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
Compose .env vs systemd EnvironmentFile
Compose e systemd hanno ciascuno il proprio meccanismo di ambiente, e mescolarli causa errori confusi di “variabile non impostata” all’avvio.
Compose legge automaticamente un file .env nella directory del progetto per la sostituzione delle variabili nel file Compose.
Esempio .env:
APP_TAG=1.2.3
WEB_PORT=8080
Esempio compose.yaml:
services:
web:
image: nginx:${APP_TAG}
ports:
- "${WEB_PORT}:80"
Un EnvironmentFile systemd imposta le variabili d’ambiente per il comando docker compose stesso.
Esempio:
EnvironmentFile=-/opt/myapp/.env.systemd
Per molti progetti, hai bisogno solo del .env di Compose.
Usa un file di ambiente systemd quando vuoi definire cose come:
COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock
Non usare né l’uno né l’altro come un vault di segreti occasionale. Se i segreti sono importanti, usa i segreti Docker, un gestore di segreti esterno, file crittografati o almeno permessi rigorosi.
Imposta perm restrittivi:
chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd
Politiche di riavvio: Docker vs systemd
Ci sono due livelli di riavvio — la politica di riavvio del container in Compose e la politica di riavvio del servizio systemd — e non dovrebbero essere mescolati ciecamente.
Per container in esecuzione continua, imposta le politiche di riavvio in Compose:
services:
web:
image: nginx:stable
restart: unless-stopped
Valori comuni di riavvio:
| Policy | Significato |
|---|---|
| no | Non riavviare automaticamente |
| always | Riavvia dopo l’uscita e il riavvio del daemon |
| on-failure | Riavvia solo dopo il fallimento |
| unless-stopped | Riavvia a meno che non sia fermato manualmente |
Per la maggior parte dei servizi persistenti, preferisco:
restart: unless-stopped
È prevedibile e rispetta le fermate manuali intenzionali.
L’unità systemd stessa di solito non dovrebbe riavviarsi ripetutamente, perché docker compose up -d non è il carico di lavoro in esecuzione. Sono i container.
Quindi evita questo a meno che tu non abbia un motivo specifico:
Restart=always
Nella maggior parte delle unità Compose-as-service, lascia che Docker gestisca i riavvii dei container.
Controlli di salute
Le politiche di riavvio riavviano i container quando i processi escono. Non risolvono magicamente ogni applicazione non sana.
Aggiungi controlli di salute dove sono utili:
services:
app:
image: example/app:latest
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Controlla la salute:
docker compose ps
Ispeziona un container:
docker inspect container-name
I controlli di salute sono particolarmente utili per:
- App web
- Reverse proxy
- Database
- Code
- API interne
- Worker con un endpoint di salute
Sono meno utili quando controllano solo che un processo esista, perché un processo che è vivo ma bloccato appare comunque sano. Un controllo di salute cattivo è solo un’altra bugia in YAML.
Ordine di avvio e depends_on
Compose può definire dipendenze:
services:
app:
image: example/app:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Questo può aiutare l’ordine di avvio, ma non fidartene troppo. Le applicazioni dovrebbero comunque gestire i retry — i database si riavviano, le reti fluttuano, DNS impiega tempo, e un’app resiliente riprova le connessioni invece di assumere un ordine di avvio perfetto.
Log: journalctl e docker compose logs
Due viste dei log coprono la maggior parte del debugging: systemd cattura il ciclo di vita dell’unità stessa, mentre Compose cattura l’output dell’applicazione dai container in esecuzione.
Log del servizio systemd:
journalctl -u myapp.service -n 100 --no-pager
Segui i log systemd:
journalctl -u myapp.service -f
Log del servizio Compose:
cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web
Per la maggior parte del debugging delle app, docker compose logs è più utile; per il debugging del ciclo di vita — fallimenti di avvio, crash dell’unità, errori di autorizzazione — journalctl è più utile. Se systemctl start myapp fallisce, controlla prima journalctl. Se lo stack si avvia ma l’app è rotta, controlla docker compose logs.
Rotazione dei log
I log di Docker possono crescere all’infinito se non li configuri.
Per server piccoli, configura la rotazione dei log di Docker in /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Riavvia Docker:
sudo systemctl restart docker
Poi riavvia lo stack Compose:
sudo systemctl restart myapp.service
Questo si applica ai container appena creati. Ricrea i container se necessario:
cd /opt/myapp
docker compose up -d --force-recreate
La rotazione dei log non è glamour, ma è uno dei modi più semplici per prevenire un’interruzione per disco pieno su un server piccolo.
Aggiornamento di un servizio Compose
Un semplice flusso di aggiornamento manuale:
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Se gestito da systemd, puoi usare:
sudo systemctl reload myapp.service
Se la tua unità ha:
ExecReload=/usr/bin/docker compose up -d --remove-orphans
Ma nota: ExecReload non tira le immagini a meno che tu non includa quel passaggio.
Per aggiornamenti espliciti, crea uno script.
mkdir -p /opt/myapp/scripts
nano /opt/myapp/scripts/update.sh
Script:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/myapp
docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
docker compose ps
Rendilo eseguibile:
chmod +x /opt/myapp/scripts/update.sh
Eseguilo:
/opt/myapp/scripts/update.sh
Poi l’unità del servizio può rimanere focalizzata sul ciclo di vita, mentre lo script di aggiornamento gestisce il deployment.
Script di aggiornamento più sicuro con hook di backup
Per servizi con stato, aggiorna solo dopo il backup.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp/backups"
cd "$APP_DIR"
mkdir -p "$BACKUP_DIR"
echo "Validating compose file"
docker compose config --quiet
echo "Running backup hook"
if [ -x "$APP_DIR/scripts/backup.sh" ]; then
"$APP_DIR/scripts/backup.sh"
else
echo "No backup hook found"
fi
echo "Pulling images"
docker compose pull
echo "Recreating services"
docker compose up -d --remove-orphans
echo "Pruning unused images"
docker image prune -f
echo "Current status"
docker compose ps
Questo è ancora semplice, ma ora codifica un’abitudine operativa: backup prima del cambiamento.
Fermare il servizio
Ferma lo stack:
sudo systemctl stop myapp.service
Questo esegue:
docker compose down
Di default, docker compose down rimuove:
- Container per i servizi nel file Compose
- Reti definite dal file Compose
- La rete predefinita
Non rimuove i volumi nominati a meno che tu non glielo chieda.
Non usare casualmente:
docker compose down -v
Questo rimuove i volumi nominati dichiarati nel file Compose e i volumi anonimi attaccati ai container. Per database e app con stato, questo può significare eliminare dati reali.
Usa down -v solo quando intendi “distruggi questo ambiente”.
Riavviare il servizio
Riavvia l’unità systemd:
sudo systemctl restart myapp.service
Questo esegue il comando di stop e poi il comando di avvio.
Per riavviare solo i container senza ricrearli:
cd /opt/myapp
docker compose restart
Importante distinzione:
docker compose restartriavvia i container esistenti.docker compose up -dapplica le modifiche di configurazione o immagine ricreando i container quando necessario.
Se hai modificato compose.yaml, usa:
docker compose up -d
Non solo:
docker compose restart
Gestione dei container orfani
Se rinomini o rimuovi un servizio in compose.yaml, i vecchi container possono rimanere come orfani.
Usa:
docker compose up -d --remove-orphans
È per questo che gli esempi di servizio systemd in questa guida usano:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Mantiene lo stack più vicino al file Compose corrente.
Backup
I backup dipendono dal carico di lavoro, ma i principi sono stabili.
Per bind mounts:
/opt/myapp/data/
Fai il backup di quella directory.
Per volumi nominati:
docker volume ls
Ispeziona un volume:
docker volume inspect volume-name
Per i database, le copie del filesystem non sono sempre sufficienti. Usa backup consapevoli dell’applicazione:
Esempio PostgreSQL:
docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql
Esempio MariaDB:
docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql
Esempio Redis:
docker compose exec redis redis-cli BGSAVE
Uno stack Compose senza un piano di backup non è un servizio — è un esperimento temporaneo che casualmente ha uptime.
Baseline di sicurezza
Per un piccolo servizio Compose su Linux, inizia con questa baseline:
- Mantieni il progetto Compose sotto
/opt/appname. - Usa tag delle immagini espliciti, non solo
latest, quando la stabilità è importante. - Usa bind mounts o volumi nominati deliberatamente.
- Non esporre porte che non ti servono.
- Metti i servizi pubblici dietro un reverse proxy.
- Usa HTTPS al bordo.
- Mantieni i segreti fuori da Git.
- Restringi i permessi di
.env. - Evita container privilegiati a meno che non siano truly richiesti.
- Evita di montare il socket Docker nei container.
- Mantieni Docker e le immagini aggiornate.
- Testa il comportamento del firewall da un’altra macchina.
Un modello pericoloso:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Questo dà al container il controllo su Docker. Nella pratica, questo può diventare il controllo a livello di host. Usalo solo quando comprendi il rischio.
Limiti delle risorse
Sui server piccoli, un container cattivo può consumare l’host.
Compose supporta impostazioni relative alle risorse, ma il comportamento può dipendere dalla versione di Docker Engine e Compose. Per una protezione semplice, inizia con limiti a livello di applicazione e limiti di logging Docker.
Per alcuni carichi di lavoro, puoi aggiungere limiti di memoria:
services:
app:
image: example/app:stable
restart: unless-stopped
mem_limit: 512m
Configura anche i conteggi dei worker a livello di app, i limiti della coda e le dimensioni della cache. I limiti dei container sono utili, ma non sono un sostituto per la comprensione dell’applicazione.
Esempio: Un servizio Compose realistico
Directory:
/opt/whoami/
compose.yaml
.env
File Compose:
services:
whoami:
image: traefik/whoami:v1.10
restart: unless-stopped
ports:
- "${WHOAMI_PORT}:80"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost || exit 1"]
interval: 30s
timeout: 5s
retries: 3
File .env:
WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami
Unità systemd:
[Unit]
Description=Whoami Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/whoami
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Installalo:
sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service
Testa:
curl http://localhost:8080
Controlla lo stato:
systemctl status whoami.service
cd /opt/whoami
docker compose ps
Troubleshooting
Il servizio si avvia ma i container non sono in esecuzione
Controlla systemd:
journalctl -u myapp.service -n 100 --no-pager
Valida Compose:
cd /opt/myapp
docker compose config
Controlla Docker:
systemctl status docker
docker info
WorkingDirectory è sbagliato
Se systemd non trova il tuo file Compose, conferma:
WorkingDirectory=/opt/myapp
Poi controlla:
ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml
Il servizio esegue da WorkingDirectory, non dalla directory corrente del tuo shell.
Docker Permission Denied
Se l’unità si esegue come root, può normalmente accedere a Docker.
Se imposti User=someuser, quell’utente deve poter accedere a Docker. Di solito significa appartenenza al gruppo docker, o una configurazione Docker rootless.
Controlla:
groups someuser
Aggiungi l’utente se appropriato:
sudo usermod -aG docker someuser
Fai attenzione. Il gruppo Docker è effettivamente privilegiato.
Comando Compose non trovato
Trova Docker:
command -v docker
Usa il percorso completo nell’unità:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Se il plugin Compose manca:
docker compose version
Installalo usando la tua fonte del pacchetto Docker.
Variabili d’ambiente mancanti
Controlla la configurazione Compose come systemd la vedrebbe:
cd /opt/myapp
docker compose config
Se systemd ha bisogno di variabili d’ambiente extra, usa:
EnvironmentFile=-/opt/myapp/.env.systemd
Se Compose ha bisogno di variabili per la sostituzione, usa:
/opt/myapp/.env
Questi sono correlati, ma non identici.
I container non si avviano dopo il riavvio
Controlla se il servizio systemd è abilitato:
systemctl is-enabled myapp.service
Abilitalo:
sudo systemctl enable myapp.service
Controlla Docker:
systemctl is-enabled docker
systemctl status docker
Controlla i log di avvio:
journalctl -u myapp.service -b --no-pager
L’app si avvia prima che il database sia pronto
Aggiungi un controllo di salute al database e depends_on con service_healthy.
Correggi anche l’applicazione. Dovrebbe riprovare le connessioni al database. L’ordine di avvio dell’infrastruttura è utile, ma la logica di retry dell’applicazione è migliore.
Disco pieno di log Docker
Controlla l’uso del disco di Docker:
docker system df
Controlla i log dei container grandi:
sudo du -h /var/lib/docker/containers | sort -h | tail
Configura la rotazione dei log di Docker in /etc/docker/daemon.json.
Poi ricrea i container.
Errori comuni
Errore 1: Eseguire docker compose up in rc.local
Eseguire docker compose up da rc.local o da uno script di login funziona finché non smette — usa un’unità systemd appropriata invece.
Errore 2: Usare Restart=always in systemd e restart: always in Compose
Di solito hai bisogno solo delle politiche di riavvio del container in Compose. Evita che due supervisori si combattano.
Errore 3: Dimenticare –remove-orphans
Le rinominazioni e le rimozioni dei servizi possono lasciare vecchi container dietro. Usa:
docker compose up -d --remove-orphans
Errore 4: Usare docker compose restart dopo modifiche alla configurazione
restart riavvia i container. Non applica tutte le modifiche alla configurazione.
Usa:
docker compose up -d
Errore 5: Eseguire down -v senza pensare
Questo può eliminare volumi. Per servizi con stato, questo può significare eliminare dati.
Errore 6: Nessun backup prima di Pull
Le nuove immagini possono rompere. I database possono migrare. I tag possono spostarsi. Fai prima il backup.
Errore 7: Pubblicare ogni porta
Pubblica solo ciò che l’host ha bisogno di esporre. Il traffico servizio-a-servizio interno può rimanere sulla rete Compose.
Modello finale consigliato
Per la maggior parte dei servizi Linux su singolo host, usa questo modello:
File Compose:
services:
app:
image: example/app:stable
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env
Unità systemd:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Abilitalo:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
Gestiscilo:
sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f
Questo modello non è fancy, e questo è il punto. Docker Compose è eccellente per sistemi piccoli e comprensibili, systemd è eccellente nell’avviare e fermare i servizi dell’host, e insieme ti danno un modello di deployment su server singolo affidabile senza fingere che ogni progetto abbia bisogno di un cluster. Per comandi a livello di container fuori da Compose — immagini, volumi, reti e pulizia — vedi il Docker Cheatsheet.