systemd-run: запуск сервиса без unit-файла
Иногда нужно быстро поднять процесс под systemd, но писать unit-файл и класть его в /etc/systemd/system лень или нельзя — контейнер без systemd, чужая машина, временный запуск. На этот случай есть systemd-run.
Зачем systemd-run
Инструмент создает transient unit — юнит, который существует только в памяти systemd, без файла на диске. Это удобно, когда:
- нужен контроль ресурсов (cgroup) над разовым процессом;
- важно, чтобы процесс пережил закрытие терминала;
- хочется изолировать команду в отдельном слайсе.
По сути, это обертка над systemctl start для юнитов, которые никто не сохраняет.
Базовый синтаксис
Простейший запуск:
Процесс попадает в user.slice, работает в фоне, управляется через systemctl. Проверить:
В выводе появится что-то вроде run-u1234.service.
Ключевые флаги
| Флаг | Назначение |
|---|---|
--scope | Создать scope unit вместо service (родительский процесс остается в scope) |
--unit=NAME | Задать имя юнита вместо автоматического |
--uid=USER | Запустить от указанного пользователя |
--gid=GROUP | Запустить от указанной группы |
--nice=N | Приоритет (от -20 до 19) |
--property=KEY=VALUE | Передать свойство в unit (CPUAccounting, MemoryMax и т.д.) |
--chdir=PATH | Рабочая директория |
--setenv=VAR=VALUE | Переменная окружения |
--tmpfs=PATH:OPTIONS | Примонтировать tmpfs в указанную точку |
Флаги комбинируются. Пример с ограничениями:
Изоляция: CPU, RAM, root через cgroup
Основная ценность — управление ресурсами через cgroup v2.
Ограничение по памяти:
Если процесс превысит лимит, systemd убьет его (OOM kill через cgroup).
Ограничение по CPU:
50% от одного ядра. Для многоядерных систем считайте проценты от суммарных единиц.
Изоляция с отдельным root:
RootDirectory требует корректной структуры директорий внутри. Без нее процесс не стартует с ошибкой “Failed to pivot root”.
Примонтировать tmpfs:
Пригождается для обработки временных файлов с ограничением места.
Комбинированный пример:
Все ресурсы процесса учтены в cgroup, видны через systemd-cgtop и /sys/fs/cgroup.
Сравнение с nohup, setsid, chroot
| Инструмент | Ресурсы | Изоляция | Жив после logout | Управление |
|---|---|---|---|---|
nohup | Нет | Нет | Да | Нет |
setsid | Нет | Нет | Да | Нет |
chroot | Нет | Файловая система | Зависит | Нет |
systemd-run | cgroup | CPU, RAM, I/O, пользователь | Да | systemctl |
nohup и setsid хороши для фоновых скриптов. Но если нужен контроль памяти или приоритета — без cgroup не обойтись.
chroot решает только задачу изоляции ФС. Запустить systemd-run --chroot нельзя, но можно скомбинировать:
Здесь chroot изолирует файловую систему, systemd-run ограничивает ресурсы.
Подводные камни: scope vs service
По умолчанию systemd-run создает service unit. Разница:
- service — полноценный unit, регистрируется в systemd, имеет зависимости, управляется стандартно.
- scope — привязан к родительскому процессу. Указывается флагом
--scope. Родитель умирает — scope умирает.
В повседневной практике service подходит для долгоживущих процессов:
Scope полезен для группировки связанных процессов:
Если запустить с --scope и закрыть терминал — процессы умрут. Без --scope — останутся.
Ограничения transient units
Transien units не сохраняются после перезагрузки. Это очевидно, но есть и другие нюансы:
- Нет зависимостей. Юниты не имеют
After=,Wants=,Requires=. Процесс стартует сразу. Если нужна последовательность — запускайте отдельные команды в скрипте сsleep. - Ограниченный набор свойств. Не все поля unit-файла доступны через
--property. Например,Restart=alwaysв transient unit не поддерживается (проверено на systemd 254). - Сложнее отладка. Нет файла — нет
systemctl edit. Все параметры только в командной строке.
Для долгоживущих сервисов с зависимостями и стратегией рестарта — unit-файл остается правильным выбором. systemd-run — для одноразовых задач, прототипирования и ограничения ресурсов “на лету”.