Systemd

systemd — система инициализации и менеджер служб Linux. Обычно она запускается как процесс с PID 1, активирует системные службы, управляет зависимостями и расписаниями, а вместе с systemd-journald собирает журналы.

Основные команды:

Проверка:

ps -p 1 -o pid,comm,args
systemctl --version

Юниты systemd

Юнит — объект, которым управляет systemd. Тип определяется расширением имени.

Тип Назначение Пример
.service Служба или процесс sshd.service
.timer Запуск юнита по расписанию backup.timer
.socket Сокет и активация по обращению docker.socket
.target Группа юнитов или состояние системы multi-user.target
.mount Точка монтирования home.mount
.path Реакция на изменение пути import.path
.device Устройство ядра dev-sda.device
.swap Область подкачки dev-sda2.swap

Просмотр юнитов:

systemctl list-units
systemctl list-units --type=service
systemctl list-unit-files
systemctl --failed

Основные состояния:

systemctl is-active nginx.service
systemctl is-enabled nginx.service
systemctl is-failed nginx.service

Управление сервисами

Запуск, остановка и перезапуск:

sudo systemctl start nginx.service
sudo systemctl stop nginx.service
sudo systemctl restart nginx.service

Перечитать конфигурацию приложения, если служба поддерживает это действие:

sudo systemctl reload nginx.service
sudo systemctl reload-or-restart nginx.service

Статус:

systemctl status nginx.service
systemctl --no-pager status nginx.service

Автозапуск:

sudo systemctl enable nginx.service
sudo systemctl disable nginx.service
systemctl is-enabled nginx.service

enable обычно не запускает службу немедленно. Для запуска и включения одной командой:

sudo systemctl enable --now nginx.service

Остановить и отключить:

sudo systemctl disable --now nginx.service

Сбросить отметку failed после устранения причины ошибки:

sudo systemctl reset-failed nginx.service

Полностью запретить запуск:

sudo systemctl mask example.service
sudo systemctl unmask example.service

disable убирает автозапуск, но допускает ручной запуск. mask запрещает и ручной запуск, и запуск как зависимости.


Расположение unit-файлов

Путь Назначение
/etc/systemd/system/ Локальные юниты и переопределения администратора
/run/systemd/system/ Временные юниты до перезагрузки
/usr/lib/systemd/system/ Юниты, установленные пакетами
/lib/systemd/system/ Пакетные юниты в некоторых дистрибутивах
~/.config/systemd/user/ Пользовательские юниты

Локальные файлы в /etc/systemd/system/ имеют приоритет над пакетными. Не следует редактировать пакетные unit-файлы напрямую: обновление пакета может удалить изменения.

Посмотреть итоговую конфигурацию:

systemctl cat nginx.service
systemctl show nginx.service

Пользовательские юниты:

systemctl --user daemon-reload
systemctl --user enable --now my-app.service
systemctl --user status my-app.service

Собственный service unit

Допустим, программа запускается командой:

/usr/local/bin/my-app --config /etc/my-app/config.toml

Файл /etc/systemd/system/my-app.service:

[Unit]
Description=My application
Wants=network-online.target
After=network-online.target

[Service]
Type=exec
User=my-app
Group=my-app
WorkingDirectory=/var/lib/my-app
EnvironmentFile=-/etc/my-app/my-app.env
ExecStart=/usr/local/bin/my-app --config /etc/my-app/config.toml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s

[Install]
WantedBy=multi-user.target

Применение:

sudo systemctl daemon-reload
sudo systemctl enable --now my-app.service
systemctl status my-app.service

daemon-reload перечитывает unit-файлы, но не перезапускает работающую службу. После изменения настроек обычно нужен отдельный restart.

Секции

[Unit] содержит описание и зависимости:

[Unit]
Description=Краткое описание
Documentation=man:my-app(1)
Requires=postgresql.service
After=postgresql.service

[Service] описывает процесс:

[Service]
Type=exec
User=my-app
Group=my-app
ExecStart=/usr/local/bin/my-app
Restart=on-failure

[Install] определяет, куда systemctl enable добавит ссылки:

[Install]
WantedBy=multi-user.target

Частые параметры [Service]:

Параметр Назначение
Type= Способ определения запуска и готовности
User=, Group= Пользователь и группа процесса
WorkingDirectory= Рабочий каталог
ExecStart= Основная команда
ExecStartPre= Команда перед запуском
ExecReload= Перезагрузка конфигурации
Environment= Переменная окружения
EnvironmentFile= Файл переменных окружения
Restart= Политика перезапуска
RestartSec= Задержка перед перезапуском
TimeoutStartSec= Ограничение времени запуска
TimeoutStopSec= Ограничение времени остановки

Основные значения Type=:

Новую службу желательно оставлять в foreground, а не отправлять в фон самостоятельно.

ExecStart и shell

systemd не запускает ExecStart= через shell автоматически. Пайпы, >, &&, glob-шаблоны и $(...) напрямую не обрабатываются.

Предпочтительно вынести сложную команду в скрипт:

ExecStart=/usr/local/libexec/process-data

Если shell действительно нужен:

ExecStart=/bin/bash -c '/usr/bin/cat /var/log/app.log | /usr/bin/grep ERROR'

В ExecStart= следует использовать абсолютные пути. Найти путь:

command -v my-app

Переменные окружения

[Service]
Environment="APP_MODE=production"
Environment="LOG_LEVEL=info"
EnvironmentFile=-/etc/my-app/my-app.env

Пример файла:

APP_MODE=production
LOG_LEVEL=info

Префикс - у EnvironmentFile= разрешает отсутствие файла. Это не полноценный Bash-скрипт: не стоит помещать туда export, подстановки команд и shell-логику.

Проверка unit-файла

systemd-analyze verify /etc/systemd/system/my-app.service
systemctl cat my-app.service
systemctl show my-app.service -p FragmentPath -p User -p ExecStart

Переопределение установленного юнита

Создать drop-in-файл:

sudo systemctl edit nginx.service

Пример /etc/systemd/system/nginx.service.d/override.conf:

[Service]
Restart=on-failure
RestartSec=10s

После сохранения:

sudo systemctl daemon-reload
sudo systemctl restart nginx.service

Чтобы заменить список ExecStart=, сначала сбрасывают старое значение:

[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -g "daemon off;" -c /etc/nginx/custom.conf

Удалить локальные переопределения и вернуть пакетный вариант:

sudo systemctl revert nginx.service

Зависимости между юнитами

Зависимость запуска и порядок запуска — разные понятия.

[Unit]
Requires=postgresql.service
Wants=redis.service
After=postgresql.service redis.service
Before=reporting.service

After= не запускает другой юнит. Если он должен и запускаться, и быть готов раньше, используют оба параметра:

[Unit]
Requires=postgresql.service
After=postgresql.service

Сетевой пример:

[Unit]
Wants=network-online.target
After=network-online.target

network.target не гарантирует получение адреса или доступность внешнего сервера. Даже после network-online.target приложение должно уметь переживать временные сетевые ошибки.

Просмотр зависимостей:

systemctl list-dependencies my-app.service
systemctl list-dependencies --reverse my-app.service
systemd-analyze critical-chain my-app.service

Socket units

.socket позволяет systemd открыть сокет и запустить службу при первом подключении.

/etc/systemd/system/my-echo.socket:

[Unit]
Description=Socket for echo service

[Socket]
ListenStream=127.0.0.1:9000

[Install]
WantedBy=sockets.target

/etc/systemd/system/my-echo.service:

[Unit]
Description=Socket-activated echo service

[Service]
ExecStart=/usr/local/bin/my-echo-server
StandardInput=socket
sudo systemctl daemon-reload
sudo systemctl enable --now my-echo.socket
systemctl status my-echo.socket

По совпадающему имени my-echo.socket активирует my-echo.service. Приложение должно поддерживать получение открытого сокета в выбранном режиме.


Логи через journalctl

Журнал службы:

journalctl -u nginx.service
journalctl -u nginx.service -n 100
journalctl -u nginx.service -f

Текущая и предыдущая загрузки:

journalctl -b
journalctl -b -1
journalctl --list-boots

Сообщения ядра:

journalctl -k -b

Фильтрация по времени:

journalctl --since today
journalctl --since "1 hour ago"
journalctl --since "2026-09-11 09:00" --until "2026-09-11 10:00"

Фильтрация по приоритету:

journalctl -p err
journalctl -p warning..emerg

Форматы:

journalctl -u my-app.service -o short-iso
journalctl -u my-app.service -o verbose
journalctl -u my-app.service -o json-pretty
journalctl -u my-app.service --no-pager

Объём и очистка архивных журналов:

journalctl --disk-usage
sudo journalctl --vacuum-time=14d
sudo journalctl --vacuum-size=500M

Типичная диагностика:

systemctl status my-app.service
journalctl -u my-app.service -b -n 100 --no-pager
systemctl cat my-app.service
systemctl show my-app.service -p Result -p ExecMainStatus

Targets и уровни загрузки

.target объединяет другие юниты и представляет состояние системы.

Target Назначение
default.target Target по умолчанию
multi-user.target Многопользовательский текстовый режим
graphical.target Графическая среда
rescue.target Режим восстановления
emergency.target Минимальная аварийная оболочка
network-online.target Ожидание настроенной сети
timers.target Группа timers
sockets.target Группа sockets
systemctl get-default
sudo systemctl set-default multi-user.target
sudo systemctl set-default graphical.target

Перейти к target сейчас:

sudo systemctl isolate multi-user.target

isolate может остановить лишние для нового target службы и пользовательские процессы. Особенно осторожно применяйте его при удалённом подключении.

Типичное соответствие старым runlevels:

Runlevel systemd target
0 poweroff.target
1 rescue.target
2, 3, 4 multi-user.target
5 graphical.target
6 reboot.target

Systemd timers как замена cron

Timer запускает другой юнит по расписанию. Обычно backup.timer активирует backup.service.

Преимущества:

Service /etc/systemd/system/backup-app.service:

[Unit]
Description=Back up application data

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-app
User=root
Group=root
Nice=10

Timer /etc/systemd/system/backup-app.timer:

[Unit]
Description=Run application backup daily

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10m
Unit=backup-app.service

[Install]
WantedBy=timers.target

Активация и проверка:

sudo systemctl daemon-reload
sudo systemctl enable --now backup-app.timer
systemctl list-timers --all
systemctl status backup-app.timer

Ручной тест задачи:

sudo systemctl start backup-app.service
journalctl -u backup-app.service -n 100

OnCalendar=

# Ежедневно в 02:30
OnCalendar=*-*-* 02:30:00

# Каждый понедельник в 09:00
OnCalendar=Mon *-*-* 09:00:00

# Каждый час
OnCalendar=hourly

# Первого числа месяца
OnCalendar=*-*-01 00:15:00

Проверка выражения:

systemd-analyze calendar 'Mon *-*-* 09:00:00'
systemd-analyze calendar --iterations=5 'daily'

Интервальные timers

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h

Полезные параметры:

[Timer]
Persistent=true
AccuracySec=1min
RandomizedDelaySec=15min

Persistent=true позволяет календарному timer выполнить после старта пропущенную задачу. Обычно это один компенсирующий запуск, а не отдельный запуск за каждый пропущенный период.

Включать для расписания нужно именно .timer; связанный .service будет запускаться им автоматически.


Шаблонные юниты

Шаблон worker@.service позволяет создать несколько экземпляров:

[Unit]
Description=Worker instance %i
After=network.target

[Service]
Type=exec
User=worker
ExecStart=/usr/local/bin/worker --queue=%i
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now worker@emails.service
sudo systemctl enable --now worker@images.service

%i заменяется именем экземпляра: emails или images.


Ограничение и защита службы

[Service]
User=my-app
Group=my-app
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/my-app
MemoryMax=512M
CPUQuota=50%
TasksMax=100
LimitNOFILE=65536

Оценка защиты:

systemd-analyze security my-app.service

Ограничения следует добавлять постепенно: слишком строгие параметры могут нарушить работу приложения.


Типичные ошибки

После изменения unit-файла забыли перечитать конфигурацию:

sudo systemctl daemon-reload
sudo systemctl restart my-app.service

enable не запустил службу сейчас:

sudo systemctl enable --now my-app.service

Программа работает вручную, но не через systemd. Проверьте пользователя, права, абсолютные пути, WorkingDirectory=, переменные окружения и журнал. Профили .bashrc и .profile для системной службы обычно не загружаются.

systemctl status my-app.service
journalctl -u my-app.service -b
systemctl show my-app.service -p User -p Group -p Environment -p WorkingDirectory

Timer не срабатывает:

systemctl status backup-app.timer
systemctl list-timers --all
systemctl status backup-app.service
journalctl -u backup-app.timer -u backup-app.service

Проверьте, что включён .timer, существует связанный .service, а системное время и часовой пояс верны:

timedatectl

Краткая памятка

# Службы
systemctl status name.service
sudo systemctl start name.service
sudo systemctl stop name.service
sudo systemctl restart name.service
sudo systemctl enable --now name.service
sudo systemctl disable --now name.service

# Unit-файлы
systemctl cat name.service
systemctl show name.service
sudo systemctl edit name.service
sudo systemctl daemon-reload
systemd-analyze verify /etc/systemd/system/name.service

# Ошибки и журнал
systemctl --failed
sudo systemctl reset-failed name.service
journalctl -u name.service -b
journalctl -u name.service -n 100
journalctl -u name.service -f

# Зависимости и загрузка
systemctl list-dependencies name.service
systemd-analyze critical-chain
systemctl get-default

# Timers
systemctl list-timers --all
sudo systemctl enable --now task.timer
systemd-analyze calendar 'daily'

Рекомендации