systemd без боли: юниты, таймеры и журналы на практике
Разбираемся, как писать свои сервисы и таймеры systemd и уверенно читать журналы.
systemd часто ругают за сложность, но на практике для повседневных задач достаточно понимать несколько сущностей: юниты служб, таймеры и журнал. Разберёмся с ними по порядку и напишем рабочие примеры, которые можно сразу применить.
Простейший .service
Юнит службы - это обычный текстовый файл. Пользовательские юниты кладут в /etc/systemd/system/. Вот минимальный сервис, запускающий скрипт:
[Unit]
Description=Моя резервная копия
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
[Install]
WantedBy=multi-user.targetСекция Unit описывает метаданные и зависимости, Service - что и как запускать, Install - как включать в автозагрузку. После создания файла выполните перечитывание конфигурации и запуск:
systemctl daemon-reload
systemctl start backup.service
systemctl status backup.serviceТипы служб
Параметр Type определяет, как systemd понимает, что служба запустилась.
- simple - процесс не форкается и работает на переднем плане. Значение по умолчанию.
- oneshot - разовая задача, которая отработала и завершилась. Идеально для скриптов бэкапа.
- forking - классические демоны, уходящие в фон.
- notify - служба сама сообщает о готовности.
Самая частая ошибка новичков - оставить simple для форкающегося демона. Тогда systemd считает службу упавшей и может её перезапускать по кругу. Если процесс уходит в фон, ставьте forking.
Таймеры вместо cron
Таймер - это отдельный юнит, который запускает одноимённую службу по расписанию. Для нашего бэкапа создадим backup.timer:
[Unit]
Description=Ежедневный бэкап
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetСтрока OnCalendar задаёт время в понятном формате. Опция Persistent=true важна: если машина была выключена в момент срабатывания, задача выполнится сразу после включения. Включаем таймер:
systemctl enable --now backup.timer
systemctl list-timersКоманда list-timers покажет все таймеры и время их следующего запуска. Преимущество перед cron в том, что запуск и логи попадают в общий журнал, а таймер можно связать с зависимостями других юнитов.
Чтение журнала
journalctl - единая точка доступа к логам. Несколько приёмов, которые нужны каждый день:
journalctl -u backup.service
journalctl -u backup.service -f
journalctl --since "1 hour ago"
journalctl -p err -bФлаг -u фильтрует по службе, -f следит в реальном времени, --since ограничивает по времени, -p err показывает только ошибки, а -b - записи текущей загрузки. Чтобы журнал не разрастался, ограничьте его размер в /etc/systemd/journald.conf параметром SystemMaxUse.
Типичные ошибки
Большинство проблем с юнитами решаются двумя командами: daemon-reload после правок и status для чтения причины падения.
- Забыли daemon-reload после изменения файла - systemd работает со старой версией.
- Указали относительный путь в ExecStart - нужен только абсолютный.
- Скрипт полагается на переменные окружения, которых нет у systemd - задавайте их через Environment.
- Неверный Type - приводит к ложным перезапускам.
Полезные привычки
Перед включением службы в автозагрузку всегда проверяйте её через start и status. Для отладки запускайте с journalctl -f в соседнем окне. А команда systemd-analyze verify покажет синтаксические ошибки в юните ещё до запуска. Освоив эти основы, вы перестанете бояться systemd и начнёте использовать его как удобный инструмент, а не как источник боли.