Где живут unit-файлы
Три каталога с приоритетом снизу вверх (ниже = перебивает):
/usr/lib/systemd/system/ ← от пакетов (canonical, /lib/systemd/system - symlink)
/run/systemd/system/ ← runtime, generated (systemd-fstab-generator и др.)
/etc/systemd/system/ ← локальные правки SysAdmin'а, override'ы
Если файл с одинаковым именем есть в /etc/ и в /usr/lib/ - /etc/
выигрывает целиком. Для частичной правки - drop-in (см. systemd-drop-ins).
Полный список типов
| Расширение | Кто пишет | Назначение |
|---|---|---|
.service | SysAdmin | Обычный демон (sshd, nginx, postgres) |
.socket | SysAdmin | Слушать сокет, активировать service по запросу |
.timer | SysAdmin | Cron-replacement (см. systemd-timers) |
.mount | SysAdmin / auto | Mount-point (генерится из mount-and-fstab) |
.automount | SysAdmin | Lazy-mount: монтирует при первом обращении |
.swap | SysAdmin / auto | Swap-устройство или файл |
.target | SysAdmin / dist | Группа юнитов (см. systemd-targets) |
.path | SysAdmin | Триггер service'а на изменение файла/каталога |
.slice | SysAdmin / auto | Узел иерархии cgroups для лимитов |
.scope | systemd | Внешне созданная группа процессов (sessions) |
.device | udev → systemd | Появилось /dev/* - авто, файла обычно нет |
.service - самый частый
Управляет демоном. Главное - Type= и ExecStart=.
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
After=network-online.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
Restart=on-failure
User=myapp
[Install]
WantedBy=multi-user.target
Type=simple - самый частый. Бинарь не форкается. Альтернативы - см. systemd.
.socket - socket activation
Главная идея: systemd слушает сокет ВМЕСТО сервиса. При первом
подключении - стартует парный .service и передаёт ему уже открытый fd.
# /etc/systemd/system/myapp.socket
[Unit]
Description=My App socket
[Socket]
ListenStream=8080
Accept=no # один service на все коннекты (по умолчанию)
[Install]
WantedBy=sockets.target
Зачем:
- Lazy-start - сервис не жрёт RAM пока никто не подключился.
- Параллельный boot - клиенты могут писать в сокет ДО того как сервис реально стартанул, systemd буферизует.
- Zero-downtime restart - рестарт сервиса не теряет коннекты.
Пример из реальной жизни: cups.socket, pcscd.socket, docker.socket.
.timer - расписание
См. systemd-timers. Парный .service запускается по расписанию.
.mount - точка монтирования
Имя файла = mount-point с / заменённым на -. /var/data → var-data.mount.
# /etc/systemd/system/var-data.mount
[Unit]
Description=Data partition
[Mount]
What=/dev/disk/by-uuid/abc-123
Where=/var/data
Type=ext4
Options=defaults,noatime
[Install]
WantedBy=multi-user.target
На практике пишут .mount-юниты руками редко - systemd-fstab-generator
парсит mount-and-fstab и создаёт их в /run/systemd/system/. Свой
юнит нужен когда требуются специфичные Requires=/After=.
.automount - монтировать по требованию
Парный .automount к .mount. Сама ФС не монтируется при boot - только
при первом обращении к каталогу. Для редко используемых NFS/съёмных дисков.
# /etc/systemd/system/mnt-nfs.automount
[Unit]
Description=NFS automount
[Automount]
Where=/mnt/nfs
TimeoutIdleSec=600 # отмонтировать после 10 мин простоя
[Install]
WantedBy=multi-user.target
.path - реакция на файл
Триггерит парный service когда файл появился/изменился. Inotify под капотом.
# /etc/systemd/system/upload-watcher.path
[Path]
PathExistsGlob=/var/uploads/*.zip
Unit=process-upload.service
[Install]
WantedBy=multi-user.target
Работает только если парный service Type=oneshot (или просто короткий).
.slice и .scope - узлы cgroup'ов
.slice- иерархический контейнер для группировки сервисов под общие лимиты. Системные дефолты:system.slice(демоны),user.slice(юзеры),machine.slice(виртуалки/контейнеры)..scope- создаётся программно systemd для внешне-запущенных групп процессов: SSH-сессии (session-1.scope),systemd-run, контейнеры от Docker/Podman.
Свой slice пишут чтобы зашить лимит на группу сервисов:
# /etc/systemd/system/heavy.slice
[Slice]
CPUQuota=200%
MemoryMax=4G
И в сервисах: Slice=heavy.slice. См. cgroups.
Дебаг - что есть в системе
systemctl list-unit-files # ВСЕ установленные юниты
systemctl list-unit-files --type=service # только сервисы
systemctl list-units --type=socket # активные сокеты
systemctl list-units --type=mount --all # все mount-юниты, включая стопнутые
systemctl cat docker.socket # содержимое юнита целиком
systemctl show -p TriggeredBy nginx.service # кто триггерит этот сервис
Состояния в STATE колонке:
enabled- есть symlink в*.target.wants/(стартует при boot)disabled- symlink'а нетstatic- нет [Install] секции, нельзя enable, тянется только через зависимостиmasked-/etc/systemd/system/<unit>→/dev/null(не запустить никак)