Linux перезапуск службы по расписанию
Чтобы обеспечить как можно более долгое функционирование императивных программ (даже после сбоя или перезагрузки сервера), можно создать простой bash-скрипт, который будет проверять, работают ли программы, и запустит их в случае необходимости. Чтобы скрипт работал на регулярной основе, можно использовать cron для составления графика запуска скрипта, что гарантирует перезапуск программы в случае ее падения.
Bash-скрипт
Итак, первый шаг – создание самого скрипта. Существует целый ряд программ, таких как Upstart, Supervisor и Monit, которые могут запускать и мониторить приложения на виртуальных частных серверах; bash-скрипт выполняет только запуск программ. Ниже приведен пример сценария, который запускает Apache, в случае если приложение выключено.
После сохранения скрипта нужно дать ему права на выполнение, чтобы иметь возможность запускать его.
chmod +x launch.sh
Apache можно заменить любым необходимым приложением. При необходимости установить скрипт для нескольких приложений, нужно создать новый скрипт для каждого приложения и поместить скрипты в отдельную строку cron-файла.
Установка Cron
После создания скрипта нужно установить график его запуска. Утилита cron позволяет установить интервалы выполнения скрипта. Для начала откройте cron-файл:
Cron предоставляет подробную информацию работе системы расписаний в начале файла.
Определив необходимую частоту запуска скрипта, внесите ее в соответствующую строку. Самый короткий интервал запуска скрипта в cron – 1 минута. Чтобы установить данный интервал, используйте следующий шаблон:
Для запуска скрипта каждые 5 минут используйте шаблон:
Установка простого скрипта обеспечит запуск программы после ее падения по любой причине. Это дает гарантию того, что максимальное время, на протяжении которого программа будет отключена – это интервал времени, указанный в конфигурациях cron.
Если серверу нужна программа, работающая более тщательно, можно установить одну из нескольких программ мониторинга сервера (Supervisor, Upstart, or Monit)
Иногда сервисы ни с того ни с сего падают и приходиться их вручную восстанавливать. Если для пользователя домашнего компьютера это не критично, потому что если сервис падает во время разработки, то это даже хорошо, можно сразу увидеть что есть проблема. Но на серверах и VPS сервисы должны работать постоянно для обеспечения доступа к веб-сайту или приложению.
В этой инструкции я покажу как настроить автоматический перезапуск сервиса Linux несколькими способами: с помощью скрипта мониторинга периодически запускаемого через cron и в systemd.
Автоматический перезапуск сервиса в systemd
По умолчанию, если ваш сервис будет убит или завершится некорректно, systemd не будет с ним ничего делать. Но можно настроить сервис так, чтобы при падении или даже остановке он автоматически перезапускался. Для этого используется директива Restart, которую надо добавить в секцию Service. Например, рассмотрим настройку автоматического перезапуска сервиса Apache:
sudo systemctl edit apache2
[Service]
Restart=on-failure
RestartSec=5s
Директива RestartSec указывает сколько ждать перед перезапуском сервиса. Когда завершите сохраните изменения и выполните команду daemon-reload, чтобы перечитать конфигурацию:
sudo systemctl daemon-reload
Затем чтобы проверить что всё работает посмотрите состояние процесса, завершите процесс сигналом kill:
sudo systemctl status apache2
kill -KILL 32091
И снова посмотрите состояние. Процесс будет запущен. Система инициализации автоматически перезапустит его как только он завершится с кодом возврата ошибки. Если вы хотите чтобы процесс перезапускался всегда, необходимо использовать директиву Restart: always. Однако с ней надо быть осторожным, она вовсе не даст вам завершить процесс, даже если будет необходимо. Для того, чтобы процесс, который постоянно падает не перезапускался, можно добавить лимит на количество перезапусков в секцию Service:
sudo systemctl edit apache2
[Service]
StartLimitIntervalSec=500
StartLimitBurst=5
Restart=on-failure
RestartSec=5s
Директивы StartLimitBurst и StartLimitIntervalSec указывают, что надо попытаться перезапустить сервис пять раз, и если он все эти пять раз упадёт, то больше его не трогать. Вторая директива ограничивает время перезапусков сервиса до 500 секунд.
Автоматический перезапуск сервиса с помощью скрипта
Это самый простой и самый надежный способ работающий абсолютно во всех дистрибутивах linux и не требующий установки дополнительных утилит. Для того же Apache скрипт выглядит следующим образом:
sudo vi /usr/local/bin/apache-monitor.sh
Сохраните файл, сделайте его исполняемым:
chmod ugo+x /usr/local/bin/apache-monitor.sh
Теперь добавьте запись в 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 таких директив можно указать несколько.
Какие еще опции можно указать в данной секции? В рамках нашей задачи могут пригодиться 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
Где DOW - Day Of Week - день недели, это необязательный параметр. За ним следует указание года, месяца и дня через дефис и час, минута, секунда через двоеточие. Для указания любого значения можно использовать *, перечисления делаются через запятую, а диапазоны разделяются .. (двумя точками). Знак тильды
можно использовать для указания количества интервалов от конца диапазона, а косую черту / в качестве модификатора. Несколько примеров:
Также можно использовать следующие алиасы:
На первый взгляд несколько сложно, но systemd предоставляет удобный инструмент для проверки таких конструкций, чтобы проверить ваше условие выполните, заключив анализируемые данные в кавычки:
Опять таки очень удобно, не нужно гадать правильно ли вы создали сложное условие, его можно сразу проверить и увидеть планируемое время срабатывания.
Еще один важный момент - точность. По умолчанию точность таймеров systemd равна одно минуте, это значит, что при наступлении указанного в таймере времени запуск сервиса произойдет в случайный промежуток времени равный одной минуте. Это сделано для того, чтобы разнести срабатывание таймеров, назначенных на одно время и исключить повышенную нагрузку на систему. Изменить это поведение можно при помощи директивы AccuracySec, с ее помощью можно как увеличить, так и уменьшить значение точности. Например, увеличим ее до одного часа:
Еще одна полезная опция - Persistent, которая указывает запускать таймер немедленно, если был пропущен предыдущий запуск:
И завершает юнит секция [Install] со следующим содержимым:
Итоговый юнит таймера в нашем примере будет выглядеть следующим образом:
В нашем случае условие самое простое - запуск один раз в минуту. Сохраним файл юнита и запустим его:
После чего проверим его статус:
Если все сделано правильно, то таймер будет в состоянии активен (ожидание) и ниже будет указано время до следующего запуска. Подождем несколько минут и снова изучим журнал нашей службы:
В котором вы увидите все запуски вашей службы, выполненные таймером.
Если вы внесли какие-либо изменения в файлы юнитов не забывайте перезапустить systemd командой:
Теперь нам остается последний штрих - добавить таймер в автозагрузку, для чего воспользуйтесь командой:
Для выключения следует использовать:
Как видим, таймеры systemd открывают перед нами гораздо более широкие возможности, чем классический cron, кроме того, юнит службы всегда можно запустить вручную, будучи твердо уверенным, что запускаете вы именно то, что выполняется по расписанию. Если же что-то пошло не так, вам поможет журнал, который systemd ведет автоматически.
Надеемся данный материал окажется вам полезным, и вы начнете применять таймеры systemd в своей практике вместо заданий cron.
Используя терминал или bash-файл, как я могу настроить Ubuntu для перезагрузки каждый день в (например, в 3 часа ночи)?
Другими словами, я хочу запланировать автоматическую перезагрузку через терминал.
Я не смог найти ничего связанного с этим в Google или AskUbuntu, и я довольно новичок в Ubuntu в целом (только что получил мой новый Raspberry Pi).
Сохраните файл и проверьте новую запись crontab с помощью crontab -l .
Если вы хотите использовать только:
как crontab, это не работает нормально, и вы должны проверить этот пост, чтобы увидеть, как вы можете заставить его работать.
Или просто добавьте crontab в файл crontab пользователя root, предложив полный путь к reboot команде, используя sudo crontab -e :
Не могли бы вы положить это в crontab root и не слишком беспокоиться о echo $PASSWD Я этого не знал. Это ошибка cron или это нормально? Я имею в виду, если вы отредактируете crontab как root, то задание будет выполнено, только если вы вошли в систему как root? Я думаю, что это неправильно. (или должно быть). @ RaduRădeanu Это не правда. Root cronjobs будет работать без входа в систему как root. @OrangeTux Вы имеете право, извините, я сказал это, потому что я тестировал без указания полного пути для reboot команды. В противном случае не будет работать. Смотрите мои новые правки.Обратите внимание, что помещать ваш текстовый пароль в текстовый файл не очень хорошая идея, поэтому лучше всего запускать это задание с правами root с самого начала. Обычно вместо того, чтобы редактировать crontab root с помощью crontab команды, которая оставляет записи в /var/spool/cron/crontabs несколько загадочном месте, я предпочитаю вводить их явно в /etc/cron.d . Записи в cron.d запускаются как системные записи crontab, обрабатываются как файлы конфигурации, поэтому они должны выдерживать перезагрузки системы, обновления и обновления, и вы можете явно указать работающего пользователя:
Если вам не нужно определенное время, а просто хотите, чтобы система перезагружалась один раз в день, добавьте исполняемый файл или скрипт, /etc/cron.daily и он будет автоматически запускаться в заданное время (системное время 6:25 по умолчанию):
Обратите внимание, что вместо того, чтобы просто перезагрузить систему без предупреждения, я устанавливаю 5-минутное предупреждение, поэтому, если кто-то вошел в систему, у него есть шанс сохранить свою работу или даже прервать выключение sudo shutdown -c , вместо того, чтобы вытащить систему прочь из-под них. Вы можете настроить их соответствующим образом, если вы хотите дать более подробное предупреждение (например, используйте shutdown -h 60 и выполните команду в 2:00 AM, и вы будете предупреждать пользователей за 1 час).
Это основано на моем прошлом опыте; в какой - то момент вы будете войти в систему, работать , когда кронтаб работает ввод, и если он просто перезагружается без предупреждения вы будете очень грустная панда.
Почему вы хотите - или должны это сделать? Хотя сделать это довольно просто, почти наверняка есть лучшее решение для Linux, которое не требует перезагрузки. В отличие от Windows, ОС на базе Linux не требуют перезагрузок практически для всего, кроме обновления ядра.
Если вы объясните, чего вы пытаетесь достичь, мы, возможно, поможем вам лучше.
Читайте также: