Как создавать таймеры systemd и управлять ими

Создавайте, включайте, отслеживайте и устраняйте неполадки модулей таймеров systemd с практическими примерами `.timer`, `.service`, `systemctl` и `journalctl`.

Как создавать и управлять модулями таймеров systemd

Модули таймеров systemd планируют выполнение задач в Linux без использования cron. Если вашему серверу необходимо запускать резервное копирование, задачу очистки, проверку работоспособности или отчет в определенное время, systemd-таймер предоставляет планирование, изоляцию служб, обработку зависимостей и ведение журналов в одном месте.

Ключевая идея проста: файл .timer указывает, когда запускать, а файл .service указывает, что запускать. Такое разделение упрощает проверку таймеров с помощью systemctl и отладку с помощью journalctl.

Понимание структуры модуля таймера systemd

Модуль таймера systemd всегда связан с соответствующим модулем службы (или другим типом модуля), который он должен активировать. Сам модуль таймера определяет когда должен быть активирован связанный модуль, а модуль службы определяет какое действие выполнить. Оба модуля обычно находятся в одном каталоге, часто /etc/systemd/system/ для пользовательских модулей.

Типичный файл модуля таймера имеет расширение .timer, а связанный с ним файл модуля службы — .service. Например, если вы хотите запланировать задачу, определенную в mytask.service, вы создадите файл mytask.timer.

Пример: mytask.timer

[Unit]
Description=Run my custom task daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Разберем ключевые разделы:

  • Раздел [Unit]:

    • Description: Понятное человеку описание таймера. Это полезно для идентификации в выходных данных статуса.
  • Раздел [Timer]: Это ядро модуля таймера, определяющее расписание.

    • OnCalendar=daily: Эта директива указывает, когда таймер должен активироваться. daily — это сокращение для полуночи каждого дня. Другие примеры:
      • hourly: Каждый час.
      • weekly: Каждую неделю (эквивалентно Mon *-*-* 00:00:00).
      • Sun *-*-* 10:00: Каждое воскресенье в 10:00.
      • *-*-15 14:30: 15-го числа каждого месяца в 14:30.
      • Mon..Fri *-*-* 09:00: По будням в 9:00.
    • Persistent=true: Если установлено значение true, таймер активируется как можно скорее, если событие произошло, когда система была выключена. Для таймеров OnCalendar это означает, что если система была выключена в запланированное время, таймер сработает после загрузки системы и активации таймера.
    • OnBootSec=: Активирует таймер через указанное время после загрузки системы. Например, OnBootSec=15min сработает через 15 минут после загрузки.
    • OnUnitActiveSec=: Активирует таймер через указанное время после последней активации связанного модуля. Например, OnUnitActiveSec=1h планирует следующий запуск через час после последней активации связанной службы.
    • OnUnitInactiveSec=: Активирует таймер через указанное время после того, как связанный модуль стал неактивным.
    • AccuracySec=: Определяет точность таймера. Systemd пытается пробудить систему для таймеров только в том случае, если событие находится в пределах этого временного окна, что помогает экономить энергию. По умолчанию 1min.
    • RandomizedDelaySec=: Добавляет случайную задержку к срабатыванию таймера, до указанной длительности. Полезно для распределения нагрузки.
  • Раздел [Install]: Этот раздел определяет, как можно включить модуль таймера.

    • WantedBy=timers.target: Эта директива гарантирует, что при включении таймера он становится частью timers.target, который является стандартной целью, включающей все активные таймеры. Это означает, что таймер будет автоматически запускаться при загрузке после включения.

Пример: mytask.service

[Unit]
Description=My custom task service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/my_custom_script.sh
User=myuser
Group=mygroup

[Install]
WantedBy=multi-user.target
  • Раздел [Unit]:

    • Description: Описание службы.
  • Раздел [Service]: Определяет саму службу.

    • Type=oneshot: Подходит для задач, которые выполняются один раз и завершаются. Существуют другие типы для долго работающих демонов.
    • ExecStart: Команда для выполнения. Убедитесь, что скрипт имеет права на выполнение.
    • User/Group: Указывает пользователя и группу, от имени которых должна выполняться команда. Рекомендуется не запускать задачи от root, если это не абсолютно необходимо.
  • Раздел [Install]: Обычно не требуется для службы oneshot, которая должна запускаться только по таймеру. Включайте таймер, а не службу.

Создание и включение модулей таймеров

Выполните следующие шаги для создания и управления модулями таймеров systemd:

  1. Создайте файл модуля службы: Определите задачу в файле .service. Поместите его в /etc/systemd/system/ (или ~/.config/systemd/user/ для пользовательских таймеров).

    sudo nano /etc/systemd/system/mytask.service
    

    Вставьте пример содержимого службы выше и сохраните.

  2. Создайте файл модуля таймера: Определите расписание в соответствующем файле .timer. Поместите его в тот же каталог, что и файл службы.

    sudo nano /etc/systemd/system/mytask.timer
    

    Вставьте пример содержимого таймера выше и сохраните.

  3. Перезагрузите демон systemd: После создания или изменения файлов модулей необходимо сообщить systemd о необходимости перезагрузки конфигурации.

    sudo systemctl daemon-reload
    
  4. Включите таймер: Чтобы таймер автоматически запускался при загрузке, включите его.

    sudo systemctl enable mytask.timer
    

    Примечание: НЕ включайте файл службы, если он предназначен только для запуска по таймеру.

  5. Запустите таймер: Запустите таймер немедленно. Затем он будет работать в соответствии со своим расписанием.

    sudo systemctl start mytask.timer
    

Управление и мониторинг модулей таймеров

Systemd предоставляет несколько команд systemctl для управления и мониторинга таймеров:

  • Список всех таймеров: Просмотр всех активных и неактивных таймеров.

    systemctl list-timers
    

    Эта команда выводит результат, подобный:

    NEXT                        LEFT        LAST        PASSED      UNIT          ACTIVATES
    Tue 2023-10-27 08:00:00 UTC 10h left    Wed 2023-10-26 08:00:00 UTC 14h ago       mytask.timer  mytask.service
    

    Здесь показано, когда таймер должен сработать в следующий раз, сколько времени осталось, когда он сработал в последний раз и какую службу он активирует.

  • Список таймеров для конкретного модуля: Если вы хотите увидеть таймеры, связанные с определенной службой.

    systemctl list-timers --all | grep mytask.service
    
  • Проверка статуса таймера: Получение подробной информации о конкретном таймере.

    systemctl status mytask.timer
    

    Это покажет, активен ли таймер, когда он должен сработать в следующий раз, а также последние записи журнала.

  • Просмотр журналов службы: Чтобы увидеть вывод и статус задачи, выполненной таймером, проверьте журналы связанной службы.

    journalctl -u mytask.service
    

    Вы также можете следить за журналами в реальном времени:

    journalctl -f -u mytask.service
    
  • Остановка таймера: Если вам нужно временно отключить таймер.

    sudo systemctl stop mytask.timer
    
  • Отключение таймера: Чтобы предотвратить запуск таймера при загрузке и остановить его, если он работает.

    sudo systemctl disable --now mytask.timer
    

Расширенные конфигурации таймеров

Установка определенных интервалов

Вместо daily или hourly вы можете определить более точные интервалы:

  • Каждые N минут: OnUnitActiveSec=15min (запускается через 15 минут после последней активации службы).
  • Определенное время: OnCalendar=*-*-* 02:30:00 (запускается ежедневно в 2:30).
  • Комбинирование условий: OnCalendar=Mon..Fri *-*-* 08:00:00 (запускается по будням в 8:00).

Использование AccuracySec для экономии энергии

Если ваша задача не требует выполнения в точный момент, рассмотрите возможность использования AccuracySec. Например, AccuracySec=5min сообщает systemd, что можно разбудить систему в течение 5 минут от запланированного времени. Это позволяет systemd группировать события таймеров и потенциально дольше удерживать систему в состоянии низкого энергопотребления.

[Timer]
OnCalendar=hourly
AccuracySec=5min

Persistent vs. WakeSystem

  • Persistent=true гарантирует, что если событие OnCalendar было пропущено из-за выключения системы, оно выполнится один раз при следующей загрузке. Это важно для задач, которые нельзя пропускать.
  • WakeSystem=true просит systemd разбудить систему из режима ожидания для таймера, если система и оборудование это поддерживают. Это не то же самое, что решение о том, работает ли машина от сети или от батареи.

Таймеры vs. Cron

Особенность Таймеры systemd Cron
Интеграция Глубокая интеграция со службами systemd, целями Автономная утилита
Планирование Гибкое (календарное, относительное, на основе загрузки) В основном выражения на основе времени
Ведение журнала Централизованное через journalctl Разрозненное (/var/log/syslog, /var/log/cron.log)
Обработка ошибок Можно привязать действия к сбоям служб Базовые уведомления по почте
Зависимости Может зависеть от активности других служб Ограниченные
Выполнение Может выполняться от имени конкретных пользователей, групп Может выполняться от имени конкретных пользователей через crontab
Управление питанием Может быть оптимизировано для экономии энергии (AccuracySec) Менее прямой контроль

Когда выбирать таймеры systemd:

  • Когда требуется более тесная интеграция с другими службами systemd.
  • Когда централизованное ведение журнала и более простая отладка являются приоритетом.
  • Когда требуются более продвинутые опции планирования (например, время с последнего запуска).
  • Для задач, связанных с состоянием системы или управлением питанием.

Когда cron может быть предпочтительнее:

  • Для очень простых автономных задач в системах, не полностью использующих systemd.
  • Для максимальной совместимости между различными дистрибутивами Linux и старыми системами.

Устранение распространенных неполадок

  • Задача не выполняется:
    • Проверьте статус таймера: systemctl status mytask.timer. Ищите сообщения Active: active и Triggered....
    • Проверьте журналы службы: journalctl -u mytask.service. Убедитесь, что скрипт исполняемый и не содержит ошибок.
    • Проверьте синтаксис OnCalendar: Используйте systemd-analyze calendar 'your-calendar-string' для тестирования.
    • Убедитесь, что таймер включен и запущен: systemctl list-timers --all.
  • Задача выполняется слишком рано/поздно:
    • Проверьте AccuracySec и RandomizedDelaySec.
    • Убедитесь, что системные часы точны (timedatectl status).
  • Ошибки разрешений:
    • Подтвердите, что User и Group, указанные в файле .service, имеют необходимые разрешения для скрипта и любых файлов, к которым он обращается.
    • Если пользователь не указан, по умолчанию используется root. Будьте осторожны с привилегиями root.

Заключение

Используйте systemd-таймер, когда задача относится к сервисному уровню машины: резервное копирование, задачи очистки, проверки мониторинга, хуки обновления сертификатов и другие операционные работы. Сначала создайте службу, затем создайте таймер, выполните systemctl daemon-reload, включите и запустите таймер, затем проверьте его с помощью systemctl list-timers --all и journalctl -u your.service.