Запуск скрипта по таймеру linux

Systemd.timer. Запуск задач по расписанию

Чтобы SystemD принял во внимание то, что у него есть сервис, который он должен запускать по таймеру, у сервиса должен быть соответствующий unit-файл (файл конфигурации службы для SystemD), он должен лежать в правильном месте, иметь расширение «.service» и быть доступным на чтение, а также специальный одноименный unit-файл, но с расширением «.timer», описывающий, соответственно, когда указанный сервис должен быть запущен. Также желательно, чтобы в один и тот же момент времени у того же самого сервиса не было соответствующего ему init-скрипта — скрипта, который запускала служба init (когда еще была актуальна), для избежания конфликтов — многие системные администраторы все еще по привычке лезут в каталог /etc/init.d/ в поисках этих самых скриптов. Освоив systemd.timer, вы вполне сможете отказаться от CRON и ANACRON — синхронного и, соответственно, асинхронного планировщиков под Linux, освободив системные ресурсы для чего-то более важного.

Итак приступим. Для примера создадим простенький скрипт на языке командного интерпретатора bash, который выполнит архивирование со сжатием домашнего каталога пользователя, например, begemot, который располагается в /home, а затем отправит архив на бэкап сервер, используя утилиту ncat. Не будем его больше ничем перегружать — он нам нужен только для демонстрации:

#!/bin/bash
tar -cz /home/begemot | ncat 10.1.14.72 7000

Что мы здесь видим: запускается bash, вызывает tar, который создает архив папки /home, перенаправляя вывод gzip’у для сжатия данных, который уже в свою очередь передает уже сжатый поток данных ncat’у в направлении порта 7000 сервера с IP 10.1.14.72. Чтобы вся это кухня заработала, на той стороне должен стоят такой же ncat и принимать это всё с 7000-ого порта, но это тема для другой статьи. Сейчас нам нужно создать unit-файл описывающий данный сервис. Условимся, что скрипт мы положили в /opt, назвали его home_backup и, конечно, не забыли дать ему право на исполнение командой

chmod +x /opt/home_backup

А вот и содержание самого unit-файла, который нужно положить в /lib/systemd/system с названием, например, home_backup.service

[Unit]
Description=Backup script for /home/begemot

Обратить внимание здесь можно разве что на директиву ExecStart, которая описывает, что будем запускать, Description — это простое описание, не более. Наконец, чтобы активировать механизм systemd.timer осталось создать unit-файл типа timer и положить туда же с тем же названием, сменив только расширение с «.service» на «.timer»

[Unit]
Description=timer for home_backup script

Здесь стоит обратить внимание на директиву «OnCalendar», которая показывает, что запускать сервис надо «по календарю» и, поскольку, ничего иного не указано, в 02:50 ночи. Ничего — не значит ничего, на самом деле SytemD просто остальные переменные сам заменит на «*», означающую «всегда» — точно так же, как и в терминологии CRON. Иными словами всегда, но только в 02:50, а 02:50 встречается в сутках только раз, поэтому это задание будет выполняться каждый день в 02:50. Какие еще вариации можно туда писать? Приведем несколько примеров, описанных в документации к SystemD:

Пн-Вт,СБ и ВС в 00:00:00
Sat,Thu,Mon-Wed,Sat-Sun

Все Пн и Вс в 2016-ом в 01:23 и в 02:23
Mon,Sun 16-*-* 2,1:23

1-ого числа каждого месяца, но только если это среда в 00:00:00
Wed *-1

То же самое
Wed-Wed,Wed *-1

По средам 17:48:00
Wed, 17:48

15-ого октября 2016-ого в 01:02:03, но только, если это Вт, Ср, Чт, Пт, Сб
Wed-Sat,Tue 12-10-16 1:2:3

7-ого числа каждого месяца в 00:00
*-*-7 0:0:0

Каждый год 15-ого октября в 00:00
*-10-15 00:00:00

Каждой 5-ое марта в 08:05:40
03-05 08:05:40

Ежедневно в 08:05:40
08:05:40

Ежедневно в 5:40
*-*-* 05:40:00

В 2016-ом 3-его мая в 00:00
2003-03-05

Ежегодно 3-его мая в 00:00
03-05

Ежечастно в 0 минут
hourly

Ежедневно в 00:00
daily

Ежемесяно 1-ого числа в 00:00
monthly

Еженедельно в понедельник в 00:00
weekly

Ежегодно 1-ого января в 00:00
yearly

Тоже самое
annually

Как видите, очень гибко. Практически любую вариацию можно легко настроить. «OnCalendar=» также можно комбинировать с другими типами таймеров, например «OnActiveSec=» задает время в секундах, которое должно пройти после активации timer файла, чтобы единовременно запустился указанный сервис. «OnBootSec=» делает то же самое, но отправной точкой является момент времени, когда компьютер был заружен. Осталось только понять зачем нужна директива «WantedBy=timers.target». На сам сервис она никак не влияет — она нужна для того, чтобы при следующей перезагрузке, наш таймер поднялся автоматически. Поэтому командой

перечитываем конфигурацию SystemD. Командой

systemctl enable home_backup.timer

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

Источник

Systemd, интерактивные скрипты и таймеры

Введение

При разработке под linux возникают задачи создания интерактивных скриптов, выполняемых при включении или завершении работы системы. В system V это делалось легко, но с systemd вносит коррективы. Зато оно умеет свои таймеры.

Читайте также:  Скрипт для подключения принтера mac os

Зачем нужны target

Часто пишут, что target служат аналогом runlevel в system V -init. В корне не согласен. Их больше и можно разделять пакеты по группам и, к примеру, запускать одной командой группу сервисов, выполнять дополнительные действия. Кроме того, у них нет иерархии, только зависимости.

Пример target при включении(обзор возможности) с запуском интерактивного скрипта

Описание самого target:

Данный target запустится, когда будет запущен multi-user.target и вызовет installer.service. При этом таких сервисов может быть несколько.

И наконец, пример выполняемого скрипта:

Самое главное — выбрать final.target — target, к которому система должна придти при запуске. В процессе запуска systemd пройдёт по зависимостям и запустит всё нужное.
Выбрать final.target можно разными способами, я использовал для этого опцию загрузчика.

Итоговый запуск выглядит так:

  1. Стартует загрузчик
  2. Загрузчик начинает запуск прошивки, передавая параметр final.target
  3. Systemd начинает запуск системы. Последовательно идёт к installer.target или work.target от basic.target через их зависимости (например,multi-user.target). Последние и приводят систему к работе в нужном режиме

Подготовка прошивки к запуску

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

Systemd запускает процессу в одном таргете параллельно. Есть зависимости, которые позволяют определить последовательность запуска скриптов.

  1. Система стартует
  2. Запускается сервис settings_restore.service.Он проверяет наличие файла settings.txt в разделе с данными. Если его нет, то на его место кладётся эталонный файл.Далее происходит восстановление настроек системы:
    • пароля администратора
    • hostname,
    • часового пояс
    • локаль
    • Определение, весь ли носитель используется. По умолчанию размер образа небольшой — для удобства копирования и записи на носитель. При старте проверяется — есть ли ещё неиспользуемое место. Если есть — диск переразбивается.
    • Генерация machine-id из MAC-адреса. Это важно для получения одного и того же адреса по DHCP
    • Настройки сети
    • Ограничивается размер логов
    • Подготавливается к работа внешний диск(если включена соответствующая опция и диск новый)
  3. Запускаться postgresq
  4. запускается сервис restore. Он нужен для подготовки самого zabbix и его базы данных:
    • Проверяется, есть ли уже база данных zabbix. Если нет — создается из инициализирующих дампов(идут в поставке zabbix)
    • создается список часовых поясов (нужно для их отображения в web-интерфейсе)
    • Находится текущий IP, он выводится в issue (приглашение для входа в консоли)
  5. Меняется приглашение — появляется фраза Ready to work
  6. Прошивка готова к работе

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

Как видно, я поставил зависимости, что бы сначала отработал мой скрипт, а только потом поднималась сеть и стартовала СУБД.

И второй сервис(подготовка zabbix)

Здесь немного сложнее.Запуск так же в multi-user.target, но ПОСЛЕ запуска СУБД postgresql и моего setting_restore. Но ПЕРЕД запуском служб zabbix.

Сервис с таймером для logrotate

Systemd может заменить CRON. Серьезно. Причем точность не до минуты, а до секунды(а вдруг понадобится).А можно создать монотонный таймер, вызываемый по таймауту от события.
Именно монотонный таймер, считающий время от запуска машины, я и создал.
Для этого потребуется 2 файла
logrotateTimer.service — собственно описание сервиса:

Всё просто — описание команда запуска.
Второй файл logrotateTimer.timer — вот он и задает работу таймеров:

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

Интерактивный скрипт при выключении и свой таргет выключения

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

А дело в том, что команды, запускаемые опцией ExecOnStop выполняются вне TTY! Проверить просто — вставьте команду tty и сохраните её вывод.

Поэтому я реализовал выключение через свой таргет. На 100% правильность не претендую, но это работает!
Как это делалось(в общих чертах):
Создал таргет my_shutdown.target, который ни от кого не зависел:
my_shutdown.target

При переходе в этот таргет(через systemctl isolate my_shutdwn.target), он запускал сервис my_shutdown.service, задача которого простая — выполнить скрипт my_shutdown.sh:

  • Внутри этого скрипта я выполняю нужные действия. Можно в таргет добавить много скриптов, для гибкости и удобства:

Примечание. Использование файлов /tmp/reboot и /tmp/shutdown. Нельзя вызвать target с параметрами. Можно только service.

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

Однако, самое интересное было потом. Машину же надо выключить/перезагрузить. И тут есть 2 варианта:

  • Заменить команды reboot,shutdown и прочие(они все равно являются симлинками на systemctl) на свой скрипт.Внутри скрипта — переход в my_shutdown.target. А скрипты внутри таргета потом вызывают напрямую systemctl, например, systemctl reboot
  • Более простой, но мне не нравящийся вариант. Во всех интерфейсах вызывать не shutdown/reboot/прочие, а напрямую вызывать таргет systemctl isolate my_shutdown.target

Я выбрал первый вариант. В systemd reboot(как и poweroff) являются симлинками на systemd.

Читайте также:  Wifi анализатор для linux

Поэтому их можно заменить на свои скрипты:
reboot

Источник

Записки IT специалиста

Технический блог специалистов ООО»Интерфейс»

  • Главная
  • Настраиваем таймеры systemd вместо заданий cron

Настраиваем таймеры systemd вместо заданий cron

Технологии постоянно развиваются, внося в нашу жизнь новые инструменты, которые вытесняют и заменяют старые и привычные нам. Но зачастую администраторы не спешат не только применять их на практике, но даже изучать. Нет, здоровый консерватизм безусловно оправдан, но исключительно в разумных пределах. Гораздо хуже, когда внедрение новых технологий тормозится по надуманным или «идеологическим» причинам несмотря на то, что они предоставляют гораздо более широкие возможности. Одна из таких технологий — таймеры systemd, которые позволяют по-новому взглянуть на некоторые классические задачи.

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

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

Да, сron многим привычен, но если рассматривать его сильные и слабые стороны, то в плюсы ему можно записать только простоту, все остальное — обратная сторона медали от этой простоты. Что умеет cron? Запускать задачи по расписанию и уведомлять администратора, если такой запуск завершился неудачей. Неудачей в данном случае считается возврат запускаемым приложением или скриптом кода ошибки, все остальное cron не касается, его дело запустить. Уведомление по электронной почте в современных реалиях фактически равноценно его отсутствию, мало кто будет настраивать почтовый сервер ради нескольких уведомлений.

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

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

Теперь посмотрим, что нам предлагает systеmd. Таймеры — это специальные триггеры, позволяющие запускать любые сервисы периодически, либо по наступлению какого-либо события. Здесь кроется существенное отличие от cron, запись которого содержит и расписание, и действие, в systemd эта логика разделена: таймер отвечает за управление сервисом, который уже выполняет действие. Для таймеров используются юниты с расширением .timer, в то время как для служб с расширением .service. Чтобы управлять каким-либо сервисом вам понадобится создать для него одноименный таймер.

В чем плюсы такого подхода? Их много. Давайте рассмотрим работу с таймерами на простом примере. Для начала создадим собственный юнит сервиса, который будет выполнять какое-нибудь простое действие, скажем выводить строку «Hello, world!». Для этого создадим файл с расширением .service в /etc/systemd/system:

И начнем его заполнять, первой секцией является [Unit], в которую мы помещаем описание нашей службы:

В минимальной конфигурации этого достаточно, но возможности systemd гораздо шире. Здесь же можно указать зависимости, если для работы вашему сервису требуются, либо желательны другие службы. Для указания строгой зависимости используйте Requires, например:

В случае если указанные в этой опции службы не получится запустить, запуск нашего сервиса также завершится неудачей. Более мягкую зависимость предполагает директива Wants:

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

Это достаточно удобно, так как позволяет сразу указать требуемые условия для запуска сервиса, скажем для скрипта резервного копирования баз данных мы можем указать в зависимостях службу СУБД и, если она недоступна скрипт выполняться не будет. В то время как cron просто запустит задание без всяких проверок. Чтобы реализовать такое условие запуска службы потребуется указать:

Такой набор директив указывает, что нашей службе для работы обязательно нужен рабочий MySQL и запуск службы должен осуществляться только после его запуска.

Следующая секция — [Service], здесь мы описываем нашу службу. Обязательно указываем тип, в нашем случае oneshot — одноразовый запуск и выполняемое действие в директиве ExecStart, для служб с типом oneshot таких директив можно указать несколько.

Читайте также:  Diskinternals linux reader инструкция

Какие еще опции можно указать в данной секции? В рамках нашей задачи могут пригодиться WorkingDirectory — для указания рабочей директории, Environment для задания переменных окружения и User, Group чтобы запустить сервис от указанного пользователя или группы, например:

И завершает юнит секция [Install] в которой укажем уровень запуска сервиса:

multi-user.target соответствует runlevel=3 или многопользовательский режим без графики.

В итоге у нас должно получиться:

Перезагружаем службу systemd:

И пробуем запустить наш сервис:

Вообще правильно было бы написать hello.service, но если мы не указали расширение юнита, то systemd по умолчанию считает, что мы запускаем именно службу. Состояние службы мы можем посмотреть командой:

Кроме состояния службы — неактивна, мы увидим результат ее прошлого запуска — заветную строку Hello, world!.

Но как быть, если что-то пошло не так? И здесь systemd приходит на помощь, весь поток вывода вашего скрипта или приложения автоматически логируется, чтобы просмотреть лог выполните команду:

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

Убедившись, что ваш сервис работает как надо перейдем к созданию таймера, для этого создадим еще один файл юнита:

Обратите внимание, что его название соответствует файлу юнита сервиса, но имеет другое расширение. Точно также начнём его заполнять, секция [Unit] должна содержать описание:

За ней следует секция [Timer] в которой мы указываем условия запуска. Таймеры могут быть двух типов, событийные и монотонные. Первые активируются по событию, вторые выполняются периодически. Из событийных таймеров нас будет интересовать OnBootSec, срабатывающий через указанное время после старта системы. Из монотонных следует выделить:

  • OnUnitActiveSec — сработает через указанное время после активации целевого юнита
  • OnUnitInactiveSec — все тоже самое, только время будет отсчитываться с момента прекращения работы целевого юнита, хорошо подходит для «долгоиграющих» задач, скажем бекапов.
  • OnCalendar — сработает по условию календаря.

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

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

DOW YYYY-MM-DD HH:MM:SS

Где DOWDay Of Week — день недели, это необязательный параметр. За ним следует указание года, месяца и дня через дефис и час, минута, секунда через двоеточие. Для указания любого значения можно использовать *, перечисления делаются через запятую, а диапазоны разделяются .. (двумя точками). Знак тильды

можно использовать для указания количества интервалов от конца диапазона, а косую черту / в качестве модификатора. Несколько примеров:

Также можно использовать следующие алиасы:

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

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

Еще один важный момент — точность. По умолчанию точность таймеров systemd равна одно минуте, это значит, что при наступлении указанного в таймере времени запуск сервиса произойдет в случайный промежуток времени равный одной минуте. Это сделано для того, чтобы разнести срабатывание таймеров, назначенных на одно время и исключить повышенную нагрузку на систему. Изменить это поведение можно при помощи директивы AccuracySec, с ее помощью можно как увеличить, так и уменьшить значение точности. Например, увеличим ее до одного часа:

Еще одна полезная опция — Persistent, которая указывает запускать таймер немедленно, если был пропущен предыдущий запуск:

И завершает юнит секция [Install] со следующим содержимым:

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

В нашем случае условие самое простое — запуск один раз в минуту. Сохраним файл юнита и запустим его:

После чего проверим его статус:

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

В котором вы увидите все запуски вашей службы, выполненные таймером.

Если вы внесли какие-либо изменения в файлы юнитов не забывайте перезапустить systemd командой:

Теперь нам остается последний штрих — добавить таймер в автозагрузку, для чего воспользуйтесь командой:

Для выключения следует использовать:

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

Надеемся данный материал окажется вам полезным, и вы начнете применять таймеры systemd в своей практике вместо заданий cron.

Помогла статья? Поддержи автора и новые статьи будут выходить чаще:

Или подпишись на наш Телеграм-канал:

Источник

Оцените статью