← retour aux snippets

systemd-run: service transitoire avec limites et sandbox

Lancer une commande avec limites CPU/mémoire, durée max, sandbox réseau/fs et logs journald.


objectif

Exécuter une commande dans une unité systemd transitoire, avec quotas CPU/mémoire, durée maximale, sandbox réseau/FS, utilisateur dédié, et logs consultables via journalctl. Idéal pour builds, scripts d’ETL, ou maintenance.

code minimal

# run éphémère (unit auto), 50% CPU, 512M RAM, durée max 10 min, logs dans journald
sudo systemd-run -p CPUQuota=50% -p MemoryMax=512M -p RuntimeMaxSec=600 \
  --working-directory=/srv/data.pm \
  --unit=data-pm-build \
  /usr/bin/npm run build

utilisation

# 1) suivre les logs et l'état
journalctl -u data-pm-build -f -o short-iso
systemctl status data-pm-build

# 2) sandbox stricte en lecture seule + pas de réseau (build deterministe)
sudo systemd-run --unit=data-pm-build \
  -p CPUQuota=75% -p MemoryMax=1G -p RuntimeMaxSec=900 \
  -p ProtectSystem=strict -p ProtectHome=read-only -p PrivateTmp=yes \
  -p IPAddressDeny=any \
  --setenv=NODE_ENV=production \
  --working-directory=/srv/data.pm \
  /usr/bin/npm ci && /usr/bin/npm run build

# 3) exécuter sous un utilisateur dédié sans root, avec cwd et env
sudo systemd-run --unit=data-pm-etl \
  -p User=data-pm -p Group=data-pm \
  -p CPUWeight=50 -p IOWeight=50 -p MemoryHigh=768M -p RuntimeMaxSec=1200 \
  --setenv=TZ=UTC --setenv=API_URL=https://api.data.pm \
  --working-directory=/srv/jobs \
  /usr/bin/python3 /srv/jobs/etl_data_pm.py

# 4) scope interactif côté utilisateur (pas besoin de sudo), hérite du TTY
systemd-run --user --scope -p CPUQuota=80% -p MemoryMax=1G \
  bash -lc 'pytest -q'

# 5) arrêter/annuler une unité transitoire en cours
sudo systemctl stop data-pm-build

variante(s) utile(s)

# un service transitoire qui redémarre automatiquement en cas d'échec (Restart=on-failure)
sudo systemd-run --unit=data-pm-task \
  -p Restart=on-failure -p RestartSec=5s \
  -p CPUQuota=60% -p MemoryMax=512M -p RuntimeMaxSec=600 \
  /usr/local/bin/task-data-pm.sh

# verrouillage fin des appels système (seccomp) et des capabilities
sudo systemd-run --unit=data-pm-safe \
  -p NoNewPrivileges=yes \
  -p CapabilityBoundingSet= \
  -p SystemCallFilter='@system-service ~@mount @raw-io @reboot @debug' \
  -p LockPersonality=yes -p PrivateDevices=yes \
  /usr/local/bin/maintenance.sh

# réseau autorisé uniquement vers une IP (ex: cache interne) via sandbox IP
sudo systemd-run --unit=data-pm-net \
  -p IPAddressDeny=any -p IPAddressAllow=10.0.0.5 \
  curl -fsS http://10.0.0.5/cache/prefetch?site=data.pm

# limiter le nombre de fichiers ouverts (NOFILE) et processes (NPROC)
sudo systemd-run --unit=data-pm-limits \
  -p LimitNOFILE=4096 -p TasksMax=256 \
  /usr/bin/node /srv/data.pm/scripts/generate.js

# monter un répertoire en lecture seule dans le namespace du service
sudo systemd-run --unit=data-pm-ro \
  -p ReadOnlyPaths=/srv/data.pm \
  -p TemporaryFileSystem=/tmp:ro \
  /usr/bin/true

notes

  • systemd-run crée une unité transitoire (service ou scope) avec propriétés -p. Nommez-la avec --unit pour la suivre facilement.
  • Quotas et limites utiles: CPUQuota, CPUWeight, MemoryMax/High, IOWeight, RuntimeMaxSec, TasksMax, LimitNOFILE.
  • Sandbox clés: ProtectSystem=strict, ProtectHome=read-only, PrivateTmp=yes, NoNewPrivileges=yes, CapabilityBoundingSet=, IPAddressDeny/Allow, ReadOnlyPaths, TemporaryFileSystem.
  • Pour exécuter en user non privilégié, utilisez -p User= et -p Group= (ou --user si vous restez dans la session utilisateur).
  • Les logs sont dans journald: journalctl -u <unit>. L’état et le code retour sont visibles via systemctl status.