Docker Compose als Linux-service met systemd uitvoeren

Docker Compose bij het opstarten, beheerd door systemd.

Inhoud

Docker Compose op een Linux-server moet bij het opstarten starten, tijdens het afsluiten netjes stoppen en herstarts overleven zonder handmatige ingrepen.

Docker Compose is geen Kubernetes, en dat is prima voor de werklasten die deze gids behandelt. Voor veel echte systemen is een Compose-project op een enkele Linux-host de juiste hoeveelheid infrastructuur: simpel, leesbaar, makkelijk te back-uppen en goed genoeg voor interne tools, bijprojecten, self-hosted services, staging-omgevingen, kleine productie-apps en ontwikkelaarsinfrastructuur.

docker compose config ont the table with laptop

Het ontbrekende stuk is meestal servicemanagement. Dit handmatig uitvoeren is niet genoeg:

docker compose up -d

Een enkel commando start de stack, maar het documenteert niet hoe de stack bij het opstarten moet starten, tijdens het afsluiten moet stoppen, na wijzigingen moet herladen, logs moet schrijven, zich moet herstellen na fouten of veilig geüpdatet kan worden. Daar helpt systemd bij.

Deze gids behandelt het uitvoeren van een Docker Compose-project als een Linux-service met systemd — unit-bestanden, startvolgorde, updates, logs en back-ups. De verdeling van verantwoordelijkheden is bewust: Docker draait containers, Compose definieert de stack en systemd start en stopt het project op de host. Het maakt deel uit van Developer Tools - een gids voor ontwikkelingsworkflows.

Wanneer Docker Compose als service zinvol is

Het uitvoeren van Compose onder systemd is zinvol wanneer je:

  • Een enkele Linux-server hebt
  • Een kleine self-hosted applicatie hebt
  • Een reverse proxy-stack hebt
  • Een monitoring-stack hebt
  • Een lokaal ontwikkelingsplatform hebt
  • Een intern hulpmiddel hebt
  • Een staging-omgeving hebt
  • Een eenvoudige productieservice met bekende beperkingen hebt

Voorbeelden:

  • Nginx Proxy Manager
  • Traefik
  • Gitea
  • Grafana en Prometheus
  • PostgreSQL plus een kleine webapp
  • Uptime Kuma
  • Home Assistant-hulpservices
  • Private registry
  • Interne API plus worker plus Redis

Compose is een goede keuze wanneer het operationele model nog begrijpelijk is voor één persoon die één map leest.

Wanneer Docker Compose niet genoeg is

Gebruik iets anders wanneer je nodig hebt:

  • Scheduling over meerdere knooppunten
  • Automische herscheduling over hosts heen
  • Service discovery op clusterniveau
  • Horizontale autoscaling
  • Rolling deployments over veel machines
  • Fijngegranuleerde workload-identiteit
  • Complexe netwerkbeleid
  • Grote platformoperaties voor meerdere teams

Op dat punt kunnen Kubernetes, Nomad, Swarm of een beheerd platform een betere keuze zijn.

Mijn praktische regel is om Kubernetes te vermijden alleen om systemd niet te hoeven leren, en om Compose te vermijden wanneer de werklast duidelijk orchestration over meerdere hosts nodig heeft.

De basisarchitectuur

Een schone opstelling scheidt projectbestanden, de systemd-unit en persistente data op de host. Het Compose-project zit onder /opt/myapp/ met compose.yaml, .env, data/, backups/ en optionele scripts zoals scripts/update.sh. Het systemd-unit-bestand staat op /etc/systemd/system/myapp.service.

flowchart TB subgraph host["Linux host"] systemd["systemd unit\n/etc/systemd/system/myapp.service"] compose["Docker Compose\n/opt/myapp/compose.yaml"] docker["Docker Engine"] fs["Persistent data\n/opt/myapp/data/"] end systemd -->|"ExecStart: docker compose up -d"| compose compose --> docker docker --> fs

Elke laag heeft een duidelijke taak: Docker draait containers, Compose definieert de applicatiestack, systemd start en stopt het Compose-project bij het opstarten en afsluiten, het host-bestandssysteem bewaart persistente data, back-ups blijven expliciet en updates gaan door gescriptte, reviewbare stappen. Deze indeling is bewust saai, want saaie infrastructuur is makkelijker te repareren als er iets om 2 uur ’s nachts kapotgaat.

Bereid de Compose-projectmap voor

Maak een map aan onder /opt:

sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp

Maak een Compose-bestand:

nano compose.yaml

Voorbeeld:

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: {}

Maak de contentmap aan:

mkdir -p html
echo "Hello from Docker Compose" > html/index.html

Test eerst handmatig:

docker compose up -d
docker compose ps
docker compose logs --tail=50

Stop het dan voordat je de levenscyclus overdraagt aan systemd:

docker compose down

Maak geen systemd-service totdat het Compose-project handmatig werkt. Terwijl je test, houd de Docker Compose Cheatsheet in de buurt voor ps, logs, pull en projectstructuur.

Gebruik het moderne docker compose-commando

Docker Engine en de Compose-plugin moeten geïnstalleerd zijn voordat je een unit-bestand schrijft. Op Ubuntu, Install Docker on Ubuntu behandelt APT, Snap, rootless mode en post-install beveiliging zodat je eindigt met een werkend docker compose-commando.

Gebruik dit:

docker compose version

Niet dit:

docker-compose version

Het oude docker-compose-binary bestaat nog op veel machines, maar modern Docker gebruikt Compose als Docker CLI-plugin.

In servicebestanden en scripts, geef de voorkeur aan:

/usr/bin/docker compose

Je kunt het Docker-pad vinden met:

command -v docker

Meestal is het:

/usr/bin/docker

Maak een systemd-service voor Docker Compose

Als unit-bestanden nieuw voor je zijn, Run any Executable as a Service in Linux legt Type, ExecStart, systemctl en de algemene systemd-workflow uit. Deze sectie past die patronen specifiek toe op een Compose-stack.

Maak het servicebestand:

sudo nano /etc/systemd/system/myapp.service

Gebruik deze 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

Laad systemd opnieuw:

sudo systemctl daemon-reload

Start de service:

sudo systemctl start myapp.service

Schakel het in bij het opstarten:

sudo systemctl enable myapp.service

Controleer de status:

systemctl status myapp.service

Controleer containers:

cd /opt/myapp
docker compose ps

Waarom Type=oneshot en RemainAfterExit=yes?

Dit is het deel dat veel gidsen subtiel verkeerd krijgen.

docker compose up -d start containers in detached mode en eindigt, dus er is geen langlopend foreground Compose-proces voor systemd om te superviseren. De systemd-unit zou niet moeten doen alsof docker compose up -d een langlopend daemon is.

Gebruik:

Type=oneshot
RemainAfterExit=yes

Dit vertelt systemd:

  • Voer het startcommando uit.
  • Beschouw de unit als actief nadat het commando succesvol is afgerond.
  • Voer ExecStop uit wanneer de service wordt gestopt.

Dit komt overeen met het werkelijke gedrag van detached Compose, waardoor Type=oneshot met RemainAfterExit=yes de juiste standaard is voor de meeste stacks.

Waarom niet Type=simple?

Met Type=simple verwacht systemd dat het ExecStart-proces blijft lopen, maar docker compose up -d eindigt na het starten van containers. Dat kan er voor zorgen dat systemd denkt dat de service is beëindigd, vervolgens de stop-logiek aanroept of de unit als inactief markeert, afhankelijk van de configuratie.

Als je Type=simple wilt, zou je meestal Compose in de foreground draaien:

ExecStart=/usr/bin/docker compose up

Dat kan werken, maar ik heb daar meestal geen voorkeur voor bij Compose-stacks op servers. Detached containers plus expliciete ExecStop zijn makkelijker te bedienen.

Een meer productie-vriendelijke unit

Voor een echte server geef ik de voorkeur aan een iets strengere unit:

[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

Belangrijke details:

  • WorkingDirectory verwijst naar het Compose-project.
  • ExecStartPre valideert de Compose-configuratie.
  • ExecReload hermaakt gewijzigde services.
  • ExecStop stopt en verwijdert de Compose-projectcontainers en het standaardnetwerk.
  • EnvironmentFile=-... betekent dat het bestand optioneel is.

Maak het optionele systemd-omgevingsbestand:

nano /opt/myapp/.env.systemd

Voorbeeld:

COMPOSE_PROJECT_NAME=myapp

Laad dan systemd opnieuw:

sudo systemctl daemon-reload
sudo systemctl restart myapp.service

Compose .env vs systemd EnvironmentFile

Compose en systemd hebben elk hun eigen omgevingsmechanisme, en het mengen ervan veroorzaakt verwarrende “variabele niet ingesteld”-fouten bij het opstarten.

Compose leest automatisch een .env-bestand in de projectmap voor variabele substitutie in het Compose-bestand.

Voorbeeld .env:

APP_TAG=1.2.3
WEB_PORT=8080

Voorbeeld compose.yaml:

services:
  web:
    image: nginx:${APP_TAG}
    ports:
      - "${WEB_PORT}:80"

Een systemd EnvironmentFile stelt omgevingsvariabelen in voor het docker compose-commando zelf.

Voorbeeld:

EnvironmentFile=-/opt/myapp/.env.systemd

Voor veel projecten heb je alleen Compose .env nodig.

Gebruik een systemd-omgevingsbestand wanneer je dingen wilt definiëren zoals:

COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock

Gebruik geen van beide bestanden als een casual secrets-vault. Als secrets belangrijk zijn, gebruik dan Docker secrets, een externe secret manager, gecrypteerde bestanden of in ieder geval strikte permissies.

Stel restrictieve permissies in:

chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd

Herstartbeleid: Docker vs systemd

Er zijn twee herstartlagen — het containerherstartbeleid in Compose en het systemd-serviceherstartbeleid — en ze mogen niet blindeling worden gemengd.

Voor langlopende containers, stel herstartbeleiden in Compose:

services:
  web:
    image: nginx:stable
    restart: unless-stopped

Vevoorkomen herstartwaarden:

Policy Meaning
no Niet automatisch herstarten
always Herstarten na exit en daemon restart
on-failure Alleen herstarten na falen
unless-stopped Herstarten tenzij handmatig gestopt

Voor de meeste persistente services geef ik de voorkeur aan:

restart: unless-stopped

Het is voorspelbaar en respecteert intentionele handmatige stops.

De systemd-unit zelf zou meestal niet herhaaldelijk moeten herstarten, omdat docker compose up -d niet de lopende werklast is. De containers zijn dat.

Vermijd dit dus tenzij je een specifieke reden hebt:

Restart=always

In de meeste Compose-as-service-units, laat Docker het containerherstart afhandelen.

Health Checks

Herstartbeleiden herstarten containers wanneer processen eindigen. Ze lossen niet magisch elke ongezonde applicatie op.

Voeg health checks toe waar ze nuttig zijn:

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

Controleer de gezondheid:

docker compose ps

Inspecteer een container:

docker inspect container-name

Health checks zijn vooral nuttig voor:

  • Webapps
  • Reverse proxies
  • Databases
  • Queues
  • Interne API’s
  • Workers met een health-endpoint

Ze zijn minder nuttig wanneer ze alleen controleren of een proces bestaat, omdat een proces dat leeft maar vastzit er nog steeds gezond uitziet. Een slechte health check is slechts een andere leugen in YAML.

Startvolgorde en depends_on

Compose kan afhankelijkheden definiëren:

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

Dit kan helpen bij de startvolgorde, maar vertrouw er niet te veel op. Applicaties moeten nog steeds retries afhandelen — databases herstarten, netwerken flakkeren, DNS kost tijd, en een resiliente app probeert verbindingen opnieuw in plaats van uit te gaan van een perfecte startvolgorde.

Logs: journalctl en docker compose logs

Twee logweergaven dekken het meeste debuggen: systemd vangt de levenscyclus van de unit zelf, terwijl Compose applicatie-output vangt van lopende containers.

systemd-service logs:

journalctl -u myapp.service -n 100 --no-pager

Volg systemd-logs:

journalctl -u myapp.service -f

Compose-service logs:

cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web

Voor de meeste app-debuggen is docker compose logs nuttiger; voor levenscyclus-debuggen — startfouten, unit-crashes, permissiefouten — is journalctl nuttiger. Als systemctl start myapp faalt, controleer dan eerst journalctl. Als de stack start maar de app kapot is, controleer dan docker compose logs.

Log Rotatie

Docker-logs kunnen voor altijd groeien als je ze niet configureert.

Voor kleine servers, configureer Docker-logrotatie in /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Herstart Docker:

sudo systemctl restart docker

Herstart dan de Compose-stack:

sudo systemctl restart myapp.service

Dit geldt voor nieuw gemaakte containers. Hermaak containers indien nodig:

cd /opt/myapp
docker compose up -d --force-recreate

Logrotatie is niet glamoureus, maar het is een van de makkelijkste manieren om een disk-full outage op een kleine server te voorkomen.

Een Compose-service updaten

Een eenvoudige handmatige update-flow:

cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f

Als beheerd door systemd, kun je gebruiken:

sudo systemctl reload myapp.service

Als je unit heeft:

ExecReload=/usr/bin/docker compose up -d --remove-orphans

Maar let op: ExecReload haalt geen images tenzij je die stap included.

Voor expliciete updates, maak een 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

Maak het uitvoerbaar:

chmod +x /opt/myapp/scripts/update.sh

Voer het uit:

/opt/myapp/scripts/update.sh

Dan kan de service-unit gericht blijven op levenscyclus, terwijl het update-script de deployment afhandelt.

Veiligere updatescript met backup-hook

Voor stateful services, update alleen na 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

Dit is nog steeds simpel, maar het codeert nu een operationele gewoonte: backup voor verandering.

De service stoppen

Stop de stack:

sudo systemctl stop myapp.service

Dat voert uit:

docker compose down

Standaard verwijdert docker compose down:

  • Containers voor services in het Compose-bestand
  • Netwerken gedefinieerd door het Compose-bestand
  • Het standaardnetwerk

Het verwijdert geen benoemde volumes tenzij je het vraagt.

Gebruik niet casual:

docker compose down -v

Dat verwijdert benoemde volumes gedeclareerd in het Compose-bestand en anonieme volumes gekoppeld aan containers. Voor databases en stateful apps kan dat betekenen dat echte data wordt verwijderd.

Gebruik down -v alleen wanneer je “vernietig deze omgeving” bedoelt.

De service herstarten

Herstart de systemd-unit:

sudo systemctl restart myapp.service

Dit voert het stopcommando uit en dan het startcommando.

Voor alleen het herstarten van containers zonder ze te hermaken:

cd /opt/myapp
docker compose restart

Belangrijk onderscheid:

  • docker compose restart herstart bestaande containers.
  • docker compose up -d past config- of imagewijzigingen toe door containers te hermaken wanneer nodig.

Als je compose.yaml hebt gewijzigd, gebruik:

docker compose up -d

Niet alleen:

docker compose restart

Orphan-containers afhandelen

Als je een service in compose.yaml hernoemt of verwijdert, kunnen oude containers achterblijven als orphans.

Gebruik:

docker compose up -d --remove-orphans

Daarom gebruiken de systemd-servicevoorbeelden in deze gids:

ExecStart=/usr/bin/docker compose up -d --remove-orphans

Het houdt de stack dichter bij het huidige Compose-bestand.

Back-ups

Back-ups hangen af van de werklast, maar de principes zijn stabiel.

Voor bind mounts:

/opt/myapp/data/

Back-up die map.

Voor benoemde volumes:

docker volume ls

Inspecteer een volume:

docker volume inspect volume-name

Voor databases zijn bestandssysteemkopieën niet altijd genoeg. Gebruik application-aware back-ups:

PostgreSQL-voorbeeld:

docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql

MariaDB-voorbeeld:

docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql

Redis-voorbeeld:

docker compose exec redis redis-cli BGSAVE

Een Compose-stack zonder een backupplan is geen service — het is een tijdelijk experiment dat toevallig uptime heeft.

Beveiligingsbaseline

Voor een kleine Compose-service op Linux, begin met deze baseline:

  • Houd het Compose-project onder /opt/appname.
  • Gebruik expliciete imagetags, niet alleen latest, wanneer stabiliteit belangrijk is.
  • Gebruik bind mounts of benoemde volumes bewust.
  • Publiceer geen poorten die je niet nodig hebt.
  • Zet publieke services achter een reverse proxy.
  • Gebruik HTTPS aan de edge.
  • Houd secrets buiten Git.
  • Beperk .env-permissies.
  • Vermijd privileged containers tenzij echt nodig.
  • Vermijd het mounten van de Docker-socket in containers.
  • Houd Docker en images up-to-date.
  • Test firewallgedrag vanaf een andere machine.

Een gevaarlijk patroon:

volumes:
  - /var/run/docker.sock:/var/run/docker.sock

Dit geeft de container controle over Docker. In de praktijk kan dat host-level controle worden. Gebruik het alleen wanneer je het risico begrijpt.

Resource Limits

Op kleine servers kan één slechte container de host consumeren.

Compose ondersteunt resource-gerelateerde instellingen, maar gedrag kan afhangen van Docker Engine en Compose-versie. Voor eenvoudige bescherming, begin met applicatie-level limits en Docker logging limits.

Voor sommige werklasten kun je memory limits toevoegen:

services:
  app:
    image: example/app:stable
    restart: unless-stopped
    mem_limit: 512m

Configureer ook app-level worker counts, queue limits en cache sizes. Container limits zijn nuttig, maar ze zijn geen vervanging voor het begrijpen van de applicatie.

Voorbeeld: Een realistische Compose-service

Map:

/opt/whoami/
  compose.yaml
  .env

Compose-bestand:

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

.env-bestand:

WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami

systemd-unit:

[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

Installeer het:

sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service

Test:

curl http://localhost:8080

Controleer status:

systemctl status whoami.service
cd /opt/whoami
docker compose ps

Probleemoplossing

Service start maar containers draaien niet

Controleer systemd:

journalctl -u myapp.service -n 100 --no-pager

Valideer Compose:

cd /opt/myapp
docker compose config

Controleer Docker:

systemctl status docker
docker info

WorkingDirectory is verkeerd

Als systemd je Compose-bestand niet kan vinden, bevestig:

WorkingDirectory=/opt/myapp

Controleer dan:

ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml

De service draait vanaf WorkingDirectory, niet vanaf je huidige shell-directory.

Docker Permission Denied

Als de unit als root draait, kan het normaal Docker toegang krijgen.

Als je User=someuser instelt, moet die gebruiker toegang tot Docker hebben. Meestal betekent dat lidmaatschap van de docker-groep, of een rootless Docker-opstelling.

Controleer:

groups someuser

Voeg de gebruiker toe indien gepast:

sudo usermod -aG docker someuser

Wees voorzichtig. De Docker-groep is effectief privileged.

Compose-commando niet gevonden

Vind Docker:

command -v docker

Gebruik het volledige pad in de unit:

ExecStart=/usr/bin/docker compose up -d --remove-orphans

Als Compose-plugin ontbreekt:

docker compose version

Installeer het met je Docker-pakketbron.

Omgevingsvariabelen ontbreken

Controleer de Compose-configuratie zoals systemd het zou zien:

cd /opt/myapp
docker compose config

Als systemd extra omgevingsvariabelen nodig heeft, gebruik:

EnvironmentFile=-/opt/myapp/.env.systemd

Als Compose variabelen nodig heeft voor substitutie, gebruik:

/opt/myapp/.env

Deze zijn gerelateerd, maar niet identiek.

Containers starten niet na reboot

Controleer of de systemd-service is ingeschakeld:

systemctl is-enabled myapp.service

Schakel het in:

sudo systemctl enable myapp.service

Controleer Docker:

systemctl is-enabled docker
systemctl status docker

Controleer boot-logs:

journalctl -u myapp.service -b --no-pager

App start voordat database klaar is

Voeg een database health check en depends_on met service_healthy toe.

Fix ook de applicatie. Het zou databaseverbindingen moeten proberen opnieuw. Infrastructuurstartvolgorde is nuttig, maar applicatie-herhaallogica is beter.

Disk gevuld met Docker-logs

Controleer Docker-schijmgebruik:

docker system df

Controleer grote container-logs:

sudo du -h /var/lib/docker/containers | sort -h | tail

Configureer Docker-logrotatie in /etc/docker/daemon.json.

Herstel dan containers.

Veelgemaakte fouten

Fout 1: docker compose up uitvoeren in rc.local

Het uitvoeren van docker compose up vanuit rc.local of een login-script werkt totdat het niet werkt — gebruik een juiste systemd-unit in plaats daarvan.

Fout 2: Gebruik van Restart=always in systemd en restart: always in Compose

Meestal heb je alleen containerherstartbeleiden in Compose nodig. Vermijd dat twee supervisors elkaar bevechten.

Fout 3: Vergeten –remove-orphans

Servicernamen en -verwijderingen kunnen oude containers achterlaten. Gebruik:

docker compose up -d --remove-orphans

Fout 4: Gebruik van docker compose restart na config-wijzigingen

restart herstart containers. Het past niet alle configuratiewijzigingen toe.

Gebruik:

docker compose up -d

Fout 5: Uitvoeren van down -v zonder na te denken

Dit kan volumes verwijderen. Voor stateful services kan dat betekenen dat data wordt verwijderd.

Fout 6: Geen backup voor pull

Nieuwe images kunnen breken. Databases kunnen migreren. Tags kunnen bewegen. Back-up eerst.

Fout 7: Elke poort publiceren

Publiceer alleen wat de host nodig heeft om bloot te stellen. Intern service-naar-service-verkeer kan op het Compose-netwerk blijven.

Eind aanbevolen patroon

Voor de meeste single-host Linux-services, gebruik dit patroon:

Compose-bestand:

services:
  app:
    image: example/app:stable
    restart: unless-stopped
    ports:
      - "8080:8080"
    env_file:
      - .env

systemd-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
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

Schakel het in:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

Bedien het:

sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f

Dit patroon is niet fancy, en dat is het punt. Docker Compose is uitstekend voor kleine, begrijpelijke systemen, systemd is uitstekend in het starten en stoppen van host-services, en samen geven ze je een betrouwbaar single-server deploymentmodel zonder te doen alsof elk project een cluster nodig heeft. Voor container-level commando’s buiten Compose — images, volumes, netwerken en opschoning — zie de Docker Cheatsheet.

Abonneren

Ontvang nieuwe berichten over systemen, infrastructuur en AI-engineering.