Поиск по сайту:

Как (и почему) заменить задания cron таймерами systemd


Пора.

Ханна Страйкер/Компьютерщик с практическими рекомендациями

Одним из изменений, внесенных systemd, стал новый способ планирования заданий, более утонченный, чем cron. Некоторые дистрибутивы Linux больше не поставляют cron. Пришло время проверить системные таймеры.

Почему системные таймеры заменяют cron

Истоки cron восходят к 1975 году, в версии 7 Unix. Его надежность вскоре сделала его любимым инструментом для планирования выполнения задач в определенные даты и время. Следует признать, что его синтаксис довольно причудлив. Если вы не используете его часто, вам, вероятно, придется искать более тонкие моменты каждый раз, когда вы захотите запланировать работу.

В расписаниях cron дни и месяцы нумеруются, начиная с единицы. Однако дни недели пронумерованы от нуля до шести, с воскресенья по субботу. А в некоторых системах семь означает еще и воскресенье. Но, как бы странно это ни было, это работает.

Менеджер служб systemd принес гораздо больше, чем простая замена менеджера загрузки init. Частично он представлял собой современную замену cron в виде системных таймеров. Они предлагают большую гибкость, чем cron, и не требуют использования другой внешней утилиты. Они встроены во все дистрибутивы systemd.

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

Неудивительно, что дистрибутивы, основанные на Red Hat, включая Fedora, не поддерживают cron, поскольку systemd — это инициатива Red Hat. Arch и его производные не включают cron, но это, вероятно, больше связано с тем, что они предоставляют такой минимальный дистрибутив, который вы можете заполнить подходящими приложениями. Другие дистрибутивы, такие как Solus, также не видят необходимости включать cron. Конечно, вы можете установить cron в любой дистрибутив, который вам нравится, но убедительных аргументов в пользу этого нет.

По теме: Почему Linux systemd все еще вызывает разногласия после стольких лет

Как работают системные таймеры

Для системных таймеров вам необходимо создать два файла. Один из них — файл служебного. Когда служба запускается, она запускает для вас ваш процесс. Таким образом, служебный файл должен знать о вашем целевом процессе.

Второй файл, который вам нужно создать, — это файл таймера. Это определяет, когда будет запущена служба. Таким образом, файл таймера должен знать о вашем служебном файле.

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

Вы можете вывести список таймеров на вашем компьютере, используя опцию status команды systemctl. Несколько системных таймеров создаются автоматически, поэтому, даже если вы не создавали никаких таймеров, эта команда будет выводить данные.

systemctl status "*timer"

Каждое описание содержит следующую информацию:

  • имя и описание таймера, если оно было предоставлено.
  • Загружен: показывает статус загрузки. Обычно наш таймер считывается и загружается в память. Отображается путь к каталогу с файлом таймера. Мы ожидаем, что наш таймер будет «включен», но он может быть временно «выключен», если мы решим его отключить. Предустановка поставщика указывает, было ли при первом создании таймера установлено значение «включено» или «выключено».
  • Активен: показывает активный статус, включая дату и время активации таймера. Обычно вы ожидаете увидеть таймер как «активный» и «ожидающий» следующего времени и даты запуска.
  • До: как ни странно, эта строка не применима к таймерам. Мы можем игнорировать это.
  • Триггер: показывает имя процесса, запускаемого таймером.
  • Триггеры: показывает, когда таймер сработает в следующий раз и когда в следующий раз будет запущен процесс.
  • Документация. Некоторые таймеры имеют соответствующую документацию. Эта строка необязательна и присутствует не всегда.

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

Создание простого таймера systemd

Письменное слово является статическим носителем, поэтому сложно проиллюстрировать процесс, запускаемый в определенное время. Что мы сделаем, так это создадим скрипт, который будет запускаться нашим новым таймером и записывать временную метку в файл журнала. Это скажет нам, что наша служба работает и когда она была запущена в последний раз.

Мы воспользуемся командой date для создания отметки времени и перенаправим ее в файл с именем «timer.log» в нашем домашнем каталоге.

Мы создадим скрипт в каталоге «/usr/local/bin/». Мы используем редактор «gedit», но вы можете использовать любой редактор, который вам больше нравится.

sudo gedit /usr/local/bin/geek-timer.sh 

Скопируйте эти строки в свой редактор, сохраните файл как «geek-timer.sh» и закройте редактор.

#!/bin/bash
echo "Timer fired: $(date)" >> /home/dave/timer.log

Нам нужно сделать наш скрипт исполняемым.

sudo chmod +x /usr/local/bin/geek-timer.sh

Давайте просто проверим, что наш скрипт делает то, для чего он предназначен.

geek-timer.sh
cat timer.log

Это проверяет, что наш скрипт выполняется должным образом, и помещает временную метку в файл «timer.log».

Теперь мы создадим файл службы, чтобы определить службу, которую мы хотим запускать при срабатывании таймера.

sudo gedit /etc/systemd/system/geek-timer.service 

Скопируйте эти строки в свой редактор, сохраните файл как «/etc/systemd/system/geek-timer.service» и закройте редактор.

[Unit]
Description="How-To Geek systemd timer"
Requires=geek-timer.timer
[Service]
Type=simple
ExecStart=/usr/local/bin/geek-timer.sh
User=dave

Раздел «[Unit]» содержит две строки. Строка «Description=" — это простая строка, в которой говорится, для чего предназначена ваша услуга. Строка «Requires=» указывает, что эта служба использует файл таймера «geek-timer.timer». Далее мы создадим этот файл.

Еще кое-что есть в разделе «[Сервис]». «Type=» означает «простой», что означает, что это базовая услуга. Другие варианты включают «oneshot», что означает, что служба запускалась только один раз.

Строка «ExecStart=» указывает, какой процесс должна запустить служба. Это указывает на наш сценарий, который мы создали ранее.

Строка «User=» определяет, какой пользователь должен запустить команду. Без этого процесс запускался бы под root.

Теперь мы создадим файл таймера. Это определяет, когда запускается служба. Рекомендуется использовать одно и то же базовое имя для файлов сервера и таймера с разными расширениями.

sudo gedit /etc/systemd/system/geek-timer.timer

Скопируйте эти строки в свой редактор, сохраните файл как «/etc/systemd/system/geek-timer.timer» и закройте редактор.

[Unit]
Description="Timer for the geek-timer.service"
[Timer]
Unit=geek-timer.service
OnBootSec=5min
OnUnitActiveSec=1min
[Install]
WantedBy=timers.target

Раздел «[Unit]» содержит текстовую строку «Description=». Раздел «[Таймер]» содержит три настройки. Строка «Unit=» указывает, какая служба должна быть запущена при срабатывании этого таймера. Строка «OnBootSec=» указывает системе запустить службу через пять минут после загрузки компьютера. Строка «OnUnitActiveSec=» указывает таймеру запустить службу через одну минуту после ее последней активации.

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

В раздел «[Install]» мы включили строку «WantedBy=", в которой указывается «timers.target». «timers.target» — это специальный целевой модуль, который настраивает все таймеры, активные после загрузки, и подходит для всех основных таймеров systemd.

Мы можем использовать команду systemctl status, чтобы просмотреть наш новый таймер.

systemctl status geek-timer.service

Ошибок не обнаружено, и это хорошо. Он неактивен, поскольку мы не запустили службу. Даже если мы перезагрузимся сейчас, наша служба и таймер не будут включены. Давайте запустим и включим наш таймер.

sudo systemctl enable geek-timer.timer
sudo systemctl start geek-timer.timer

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

systemctl status geek-timer.service

Это показывает, что компьютер загрузился в 12:18, а наш таймер сработает в 12:23. Наш запрошенный параметр «пять минут после загрузки» обрабатывается правильно. Я подождал, пока истечет пять минут, а затем быстро выполнил ту же команду.

systemctl status geek-timer.service

Мы видим, что время срабатывания сместилось на одну минуту с 12:23 на 12:24. Это означает, что мы сейчас находимся в «фазе повторения каждую минуту» нашего таймера.

Проверка нашего файла журнала через несколько минут показывает, что начальное время срабатывания составляет 12:23, затем последующие запуски происходят с интервалом примерно в минуту.

cat timer.log

Связано: Как составить список служб Linux с помощью systemctl

Точная настройка времени

Время срабатывания повторяющихся событий слегка размыто. Вот почему я сказал, что события в файле журнала различаются примерно на одну минуту. Ко времени запуска добавлен небольшой случайный элемент, чтобы гарантировать, что таймеры, срабатывание которых запланировано точно в одно и то же время, на самом деле срабатывают в шахматном порядке. Обычно для таких задач, как запуск резервного копирования или других действий по обслуживанию системы, этого достаточно.

Если вам нужно более точное разрешение, вы можете использовать микросекундную синхронизацию. Добавление этой строки в раздел «[Timer]» вашего файла таймера устанавливает систему на использование разрешения в одну микросекунду.

AccuracySec=1us

Это настройки точности, которые вы можете использовать, и способы их использования.

  • Микросекунды: нас, мкс мс, мс
  • Секунды: секунды, секунды, секунды, с.
  • Минуты: минуты, минуты, минуты, минуты.
  • Часы: часы, час, час, час
  • Дни: дни, день, д.
  • Недели: недели, неделя, ж.
  • Месяцы: месяцы, месяц, М.
  • Годы: годы, год, г.

Запуск таймера в определенное время и дату достигается с помощью настройки «OnCalendar». Это находится в разделе «[Timer]» файла таймера. Общий формат:

OnCalendar=DayOfTheWeek YYYY-MM-DD HH:MM:SS

DayOfTheWeek не является обязательным. Любые другие значения заменяются звездочкой «*», что означает «каждые», например, каждую минуту или каждый час. Вы можете использовать имена или числа для дней и месяцев, а также списки, разделенные запятыми, для представления выбранных значений. Диапазоны значений обозначаются двумя точками «..», разделяющими начало и значения диапазона.

Это установит таймер, который будет срабатывать в 01:15 в первую пятницу каждого месяца.

OnCalendar=Fri *-*-1..7 01:15:00

Этот процесс будет запускаться каждый день в 19:00.

OnCalendar=*-*-* 19:00:00

Для таймера может быть установлено более одного времени срабатывания. В рабочие дни процесс будет запускаться в другое время, чем в выходные.

OnCalendar=Mon..Fri 23:00:00
OnCalendar=Sat,Sun 19:00:00

Страница руководства systemd time с полным описанием форматов времени и множеством полезных советов и рекомендаций.

Отличная гибкость и простота использования

Большая часть гибкости таймеров systemd заключается в том, как вы можете обслуживать необычные события календаря. Например, чтобы установить срабатывание таймера в 15:00 во все дни, кроме пятницы, вы можете использовать следующий формат:

Mon..Thu,Sat,Sun *-*-* 15:00:00

Объединив списки и диапазоны, разделенные запятыми, вы сможете легко создавать триггеры реального времени для самых разных сложных требований.

Как только у вас появится идея создать службу для запуска вашего процесса и файл таймера для управления запуском службы, вы уже на 90 процентах пути к пониманию системных таймеров. Последние 10 процентов используют изящную силу календарных событий.

Связано: Как запустить программу Linux при запуске с помощью systemd

Статьи по данной тематике: