Systemd таймеры: как заменить cron и правильно настроить задания

Оглавление
- Почему Systemd таймеры лучше cron
- Установка и проверка Systemd
- Просмотр существующих таймеров
- Создание нового сервиса и таймера (пошагово)
- Примеры OnCalendar: синтаксис и шаблоны
- Создание монотонного таймера (uptime-ориентированного)
- Создание транзиентного таймера с systemd-run
- Развёртывание, тестирование и отладка таймеров
- Безопасность и лучшие практики
- SOP: шаблон действий для создания таймера
- Роль-based чек-листы
- Runbook при ошибках и откате
- Краткий глоссарий и сводка
Почему Systemd таймеры лучше cron
Systemd таймеры — часть экосистемы Systemd. Они позволяют связывать юниты (service, socket, timer и проч.) в единый цикл управления. Это упрощает автоматизацию сложных зависимостей и обеспечивает централизованную видимость статуса задач.
Ключевые преимущества:
- Интеграция: таймеры являются Systemd-юнитами и видны в systemctl и journalctl.
- Гибкость: OnCalendar, OnBootSec, OnUnitActiveSec, AccuracySec, RandomizedDelaySec и другие параметры дают детальный контроль.
- Точность: таймеры могут учитывать небольшие временные интервалы и корректировать поведение при пропусках (Persistent).
- Триггеры и зависимости: удобно привязывать запуск сервисов к состоянию других юнитов.

Важно: cron остаётся простым и удобным для многих задач. Systemd таймеры выигрывают, когда нужна интеграция с сервисами и более точный контроль времени и поведения при загрузке/выключении.
Установка и проверка Systemd
Если ваш дистрибутив использует Systemd (Arch, Fedora, Ubuntu и многие другие), дополнительных пакетов для базовых таймеров обычно не требуется. Чтобы проверить работу Systemd, выполните:
systemctlЭта команда покажет состояние daemon-а и список юнитов. Для работы с пользовательскими таймерами используйте systemctl –user (см. раздел ниже).

Просмотр существующих таймеров
Показать активные таймеры:
systemctl list-timersПоказать все таймеры, включая неактивные:
systemctl list-timers --allВы увидите: следующую дату срабатывания, обратный отсчёт, время с момента последнего запуска, имя таймера и сервис, который он активирует.
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2025-01-20 11:43:00 UTC 1h 23m Sun 2025-01-19 11:43:00 UTC 22h ago my-new-timer.timer my-new-timer.serviceДля пользовательских таймеров (в рамках сессии пользователя):
systemctl --user list-timers --all
Создание нового сервиса и таймера — пошагово
Общий рабочий сценарий: вы создаёте service-юнит, который выполняет команду/скрипт, и timer-юнит, который планирует активацию этого сервис-юнита.
Рекомендуется сначала отладить сам скрипт вручную, проверить права и shebang. Пример структуры файлов (системный уровень): /etc/systemd/system/my-new-timer.service и /etc/systemd/system/my-new-timer.timer. Для пользовательских таймеров используйте ~/.config/systemd/user/.
- Создайте файлы:
touch ~/my-new-timer.service ~/my-new-timer.timer- Пример корректного service-файла (замените пути и пользователя):
[Unit]
Description=My New Service — запускает my-script.sh
[Service]
Type=oneshot
User=ramces
WorkingDirectory=/home/ramces
ExecStart=/home/ramces/.local/bin/my-script.sh
[Install]
WantedBy=multi-user.targetПояснение: Description — человекочитаемое описание, Type=oneshot для разовых команд, User определяет, от имени какого пользователя запускается команда. Убедитесь, что скрипт исполним (chmod +x).
- Пример timer-файла для ежедневного запуска в 11:43 (системный таймер):
[Unit]
Description=Timer for My New Service
[Timer]
Unit=my-new-timer.service
OnCalendar=*-*-* 11:43:00
Persistent=true
AccuracySec=1s
[Install]
WantedBy=timers.targetПояснение: OnCalendar использует синтаксис календаря Systemd; Persistent=true означает, что при пропуске запуска (машина была выключена) Systemd инициирует запуск при следующей загрузке.
- Копирование файлов в системную директорию и активация:
sudo cp ~/my-new-timer.service ~/my-new-timer.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now my-new-timer.timerПроверка статуса таймера:
sudo systemctl status my-new-timer.timer
sudo journalctl -u my-new-timer.service --since "1 hour ago"
Важно: в системных юнитах используйте абсолютные пути, указывайте User где нужно и проверяйте SELinux/AppArmor, если они активны.
Примеры OnCalendar: синтаксис и шаблоны
OnCalendar принимает выражения вида:
- Полный формат: YYYY-MM-DD HH:MM:SS
- Шаблоны: для любого значения, например -- 11:43:00 — каждый день в 11:43
- Комбинации: Mon..Fri 06:00 — по будням в 06:00
- Интервалы: 2025-09-15 00:00:00 — однократное событие
Несколько примеров:
OnCalendar=*-*-* 11:43:00 # каждый день в 11:43
OnCalendar=Mon..Fri 06:00 # по будням в 06:00
OnCalendar=*-*-01 00:00 # первый день месяца в полночь
OnCalendar=2025-09-15 12:00 # однократный запуск 15 сентября 2025
OnCalendar=*-*-* 12:00/1h # каждые часы, начиная с 12:00Учтите часовую зону: Systemd использует системное время. Для учёта временных зон и перехода на летнее время планируйте с запасом или используйте системные TZ переменные.
Создание монотонного таймера
Монотонные таймеры зависят от времени с момента загрузки машины. Полезно на ноутбуках и десктопах, где система может быть не всегда включена.
В timer-файле замените OnCalendar/Persistent на OnBootSec и OnUnitActiveSec/OnActiveSec. Пример:
[Timer]
Unit=my-new-timer.service
OnBootSec=1h
OnUnitActiveSec=30min
AccuracySec=1s
[Install]
WantedBy=timers.targetПояснения:
- OnBootSec=1h — первый запуск через час после загрузки системы.
- OnUnitActiveSec=30min — повторять каждые 30 минут от момента последней успешной активации связанного service-юнита.
- OnActiveSec — повторять через фиксированный интервал после активации таймера, независимо от результата сервиса.
![Выделенная секция [Timer] в файле таймера.](/files/dc617458-4963-419a-93e3-2d555dcd9683.png)
Создание транзиентного таймера с systemd-run
Для одноразовых или временных задач можно не создавать файлы, а использовать systemd-run. Примеры:
Одноразовый запуск в конкретное время:
sudo systemd-run --on-calendar="*-*-* 11:46:00" /home/ramces/.local/my-script.shВременный монотонный таймер:
sudo systemd-run --on-boot=1h --on-unit-active=30m /home/ramces/.local/my-script.shМожно задать имя юнита и описание:
sudo systemd-run --unit=temp-job.timer --on-calendar="*-*-* 12:00:00" --description="Временная задача" /usr/bin/dateПроверка транзиентных таймеров:
systemctl status run*.timer
Развёртывание, тестирование и отладка таймеров
Общие шаги тестирования:
- Убедитесь, что скрипт выполняется вручную и возвращает код 0.
- Проверяйте логи сервиса через journalctl:
journalctl -u my-new-timer.service -f. - Запускайте сервис вручную командой
sudo systemctl start my-new-timer.serviceдля отладки. - Для таймера используйте
systemctl start my-new-timer.timerиsystemctl list-timers. - Временно уменьшите интервалы на тестовой машине (например OnUnitActiveSec=1min) для быстрого теста.
Полезные команды:
sudo systemctl daemon-reload
sudo systemctl enable --now my-new-timer.timer
sudo systemctl restart my-new-timer.timer
sudo systemctl status my-new-timer.timer
sudo journalctl -u my-new-timer.service --since "10 minutes ago"Ошибки и их признаки:
- Таймер есть, но сервис не запускается: проверьте Unit= в timer-файле и разрешения на ExecStart.
- Service падает сразу: проверьте shebang, права, зависимости, переменные окружения, WorkingDirectory.
- Таймер не сохраняет срабатывания после перезагрузки: проверьте Persistent=true.
Безопасность и лучшие практики
- Запускайте задачи от ограниченного пользователя (User=), а не от root, если привилегии не нужны.
- Указывайте абсолютные пути в ExecStart.
- Делайте скрипты исполняемыми и с корректным shebang (#!/usr/bin/env bash).
- Проверяйте SELinux/AppArmor: при ограничениях сервис может быть заблокирован.
- Не храните секреты в глобальных переменных окружения; используйте защищённые хранилища.
- Логи собирайте и ротацию логов контролируйте отдельно (rsyslog/logrotate).
SOP: пошаговый шаблон создания и проверки таймера
- Разработчик пишет и тестирует скрипт локально.
- Создать service-файл в ~/.config/systemd/user/ или /etc/systemd/system/.
- Создать timer-файл с выбранной логикой (OnCalendar/OnBootSec).
- Проверить синтаксис и права: chmod +x скрипт.
- Перезагрузить демона: sudo systemctl daemon-reload.
- Включить таймер: sudo systemctl enable –now my-new-timer.timer.
- Проверить list-timers и journalctl для анализа запуска.
- Перевести таймер в prod и настроить мониторинг/уведомления в случае ошибок.
Роль-based чек-листы
Администратор:
- Проверить права пользователя и SELinux/AppArmor.
- Убедиться, что systemd настроен и daemon-reload выполнен.
- Настроить мониторинг успешных/неуспешных запусков.
Разработчик:
- Проверить скрипт вручную, добавить логирование.
- Использовать абсолютные пути и корректный shebang.
- Обеспечить идемпотентность задач, если они могут запускаться повторно.
SRE/операции:
- Настроить Persistent/AccuracySec/RandomizedDelaySec при необходимости.
- Добавить alert на падение сервиса или частые ошибки.
- Тестировать восстановление после перезагрузки.
Runbook при ошибках и откате
- Если таймер не срабатывает —
sudo systemctl status my-new-timer.timer. - Проверьте логи:
sudo journalctl -u my-new-timer.service -n 200. - Запустите сервис вручную для отладки:
sudo systemctl start my-new-timer.service. - Если нужно отменить расписание:
sudo systemctl disable --now my-new-timer.timerи удалить файлы из /etc/systemd/system/. - Для отката изменений конфигурации выполните
sudo systemctl daemon-reloadи перезапустите таймер/сервис.
Модели принятия решений (Mermaid)
flowchart TD
A[Нужно запланировать задачу] --> B{Зависит от других сервисов?}
B -- Да --> C[Использовать systemd timer]
B -- Нет --> D{Простая команда?}
D -- Да --> E[cron или systemd timer 'на выбор']
D -- Нет --> C
C --> F{Требуется запуск после загрузки?}
F -- Да --> G[OnBootSec / OnUnitActiveSec]
F -- Нет --> H[OnCalendar]
E --> I[Если нужен контроль юнитов — выбрать systemd timer]Критерии приёмки
- Таймер корректно отображается в
systemctl list-timers. - Сервис запускается и возвращает код 0 при ручном и запланированном запуске.
- Логи записываются в journalctl и доступны для анализа.
- Права и ограничения безопасности утверждены.
Краткий глоссарий
- timer: юнит Systemd, который планирует активацию service-юнита.
- service: юнит, который выполняет задачу (скрипт, бинарный файл).
- OnCalendar: календарный триггер для таймера.
- OnBootSec / OnUnitActiveSec: триггеры, основанные на uptime/активности.
Советы и случаи, когда Systemd таймеры не подходят
- Если нужна совместимость с crontab у многих пользователей и простота настройки — cron может быть предпочтительнее.
- Для сложных расписаний с сотнями однотипных задач центральное управление через cron+Ansible иногда проще.
Заключение
Systemd таймеры — мощная и гибкая альтернатива cron, особенно когда нужно интегрировать планирование с сервисами, управлением зависимостей и журналированием. Они дают дополнительные параметры для контроля запуска и восстановления после пропуска. Для большинства задач на сервере или в интегрированных сервисах их стоит рассматривать в качестве основного механизма планирования.

Image credit: Alexandr Podvalny via Unsplash. All alterations and screenshots by Ramces Red.
Похожие материалы
Исправление ошибок .NET Framework 3.5 в Windows
Как посмотреть и удалить историю в Reddit
Как преодолеть страх и перейти на Linux
Экран ноутбука как второй монитор в Windows
Восстановление батареи Surface Pro 3 — проверенный способ