
Мы каждый день сталкиваемся со множеством однотипных задач. Постоянно возвращаясь к ним, мы расходуем самый ценный ресурс — время. В итоге застреваем в рутине, рискуем не уложиться в сроки и совершить ошибку.
Но можно остановиться и передать повторяющуюся работу тому, кто не забудет и не промахнётся. Нас спасёт автоматизация!
Сегодня расскажем о том, как автоматизировать рутинные задачи на Linux-сервере при помощи cron и немного с помощью скриптов.
Планировщик заданий в Linux: cron
Cron — стандартный планировщик в Unix-подобных операционных системах. Он работает как фоновый демон: непрерывно следит за расписанием и в нужный момент запускает указанную команду или скрипт.
Cron — от греческого «χρόνος» (chronos) — время. Он появился в Unix ещё в 1970-х и с тех пор не потерял своей значимости в администрировании систем. Cron запускает задачу с точностью до минуты. Его расписание может быть очень гибким: от «каждую минуту» до «один раз в год». Cron может иметь отдельные планы заданий для каждого пользователя системы, и после настройки он работает автономно и не требует вмешательства пользователя. По факту, любую повторяющуюся задачу, которую вы делаете вручную по расписанию, можно автоматизировать через cron. Любую на Linux. Почти любую.
Для работы с cron используется утилита crontab, которая управляет таблицей заданий для текущего пользователя. В основных Linux-системах каждый пользователь может иметь собственный crontab, независимый от других.
А может и не иметь, ведь crontab создаётся только тогда, когда пользователь впервые запускает команду:
crontab -e
Данная команда открывает файл задач в текстовом редакторе, обычно это — vi или nano, и после сохранения cron сразу же подхватывает изменения без перезапуска сервиса.
Задание в cron задаётся в следующем формате:
* * * * * команда
│ │ │ │ └────────── день недели (0–7)
│ │ │ └────────── месяц (1–12)
│ │ └────────── день месяца (1–31)
│ └────────── час (0–23)
└────────── минута (0–59)
Звёздочку (*) система воспринимает как любое значение, то есть задание будет выполняться при каждом значении соответствующего поля.
Кроме звёздочки, поля в задании могут содержать:
одно какое-либо число, например, 29 или 6;
диапазон чисел, например, 1-4, то есть все значения от 1 до 4 включительно из диапазона, допустимого для данного поля;
список чисел, например, 2,5,6;
шаг, например, */5 означает каждые 5 единиц, начиная с минимального значения.
Здесь есть некоторые неочевидные для новичков тонкости. Например, дни недели могут принимать значения от 0 до 7. Не от одного, а от нуля. В итоге получается целых 8 значений, а дней недели — всего 7. Почему так? Потому что в cron два воскресенья — 0 и 7. Дело в том, что в старых его реализациях для воскресенья использовался 0, но чтобы упростить совместимость с ISO-стандартом, позже разрешили ещё и 7 для обозначения воскресного дня.
Или, вот шаг. В нём число после знака / определяет, через сколько единиц значений будет выполняться задание, начиная с минимально допустимого в этом поле значения. Например, /10 для минут будет означать, что задание будет выполняться в минимально возможное количество минут, а затем каждые +10 пока не закончится нумерация минут в пределах часа. То есть, данная запись означает выполнение задания в 0, 10, 20, 30, 40 и 50 минут означенного часа. В отношении часов такая запись означает запуск задачи в 0 (полночь), 10 и 20 часов означенных суток. Для дней месяца минимальным значением является 1 — первый день месяца. Это означает. что запись /10 в третьей слева позиции инициирует выполнение задачи в первый день месяца, а затем в каждый +10-й день, пока не закончится месяц — 11, 21 и 31-е число, при условии, что последнее значение присутствует в нумерации текущего месяца. Аналогично для месяцев: /10 означает 1-й и 11-й месяцы, то есть январь и ноябрь. Применительно к дням недели запись /10 не имеет практического смысла, так как диапазон значений здесь ограничен числами от 0 до 7, то есть всего восемь возможных значений. Таким образом, шаг 10 превышает длину диапазона, и задание будет выполняться только для минимального значения, то есть для 0 — воскресенья. Здесь важно понимать, что указанное в шаге число не означает каждые x единиц времени от последнего запуска или от текущего момента, а определяет выполнение задачи каждые x значений поля от его минимального значения.
Это мы рассмотрели запись */10. А ведь можно вместо звёздочки использовать число, например, 3/10. Такая запись означает, что планировщик будет прибавлять 10, но уже не к минимальному значению, а к значению 3. То есть, для минут задание будет выполняться в 3, 13, 23, 33, 43, 53 минуты; для часов и чисел месяца — в 3, 13, 23; для месяцев и дней недели — только в 3 (март или среда).
Для некоторых значений времени в cron существуют специальные директивы:
@yearlyили@annuallyозначает один раз в год и заменяет собой комбинацию0 0 1 1 *, то есть в 00:00 1 января каждого года;@monthly— раз в месяц, заменяет комбинацию0 0 1 * *, то есть в 00:00 первого числа каждого месяца;@weekly— раз в неделю, заменяет комбинацию0 0 * * 0и означает каждое воскресенье в 00:00;@dailyили@midnight— раз в день, заменяет комбинацию0 0 * * *и означает в полночь каждый день;@hourly— догадайтесь сами :-) (ответ — ноль и четыре звёздочки).
Есть ещё одна полезная директива — @reboot. Она позволяет выполнять указанную команду один раз при запуске системы. Полезность данной директивы заключается в том, что она не зависит от времени или дня и запускается только при перезагрузке или старте сервера.
Ну если разобрались с форматом записи месяцев, дней, часов и минут, то в шестом поле указываем команду, которая должна выполняться в указанное время.
Что можно использовать в качестве команды? Во-первых, любые shell-команды: ls, cp, rm и т.д. Во-вторых, скрипты: bash, python, php и т.п. В-третьих, исполняемые файлы. А также, цепочки команд с операторами &&, ||, ; и перенаправление вывода типа >, >>, 2>&1.
Из важных моментов можно отметить следующее: всегда используйте полные абсолютные пути к скриптам и файлам, в противном случае cron не всегда сможет их отыскать. И ещё — старайтесь логировать вывод. Поверьте, это пригождается чаще, чем хотелось бы.
Какие задачи можно решать при помощи cron?
Основное назначение cron — делегирование системе задач, для выполнения которых можно использовать расписание, чтобы разгрузить администратора данной системы, оградив его от определённого количества рутинной работы. Давайте рассмотрим некоторые типы и примеры задач, решить которые может помочь cron.
Резервное копирование и архивация
Обсуждение важности создания резервных копий чего бы то ни было, наверное, уже набило оскомину. И хотя cron и не является полноценным инструментом бэкапирования, но всё же с его помощью можно кое-что реализовать, поскольку расписание плюс копирование это и есть несложное решение для подобной задачи. Например:
0 2 * * * /usr/bin/mysqldump -u mysql-user -p'mysql-password' mysql-database > /backup/db_$(date +\%Y\%m\%d).sql
Такая строка в cron представляет собой пример ежедневного создания дампа базы данных MySQL или MariaDB с сохранением его в директории /backup/ под именем, частью которого будет текущая дата. Это, чтобы можно было понять, когда этот бэкап сделан.
Ещё один пример — еженедельное создание tar-архива каталога /var/www/html/, в котором, вероятно, находятся файлы веб-сайта. 0 в пятой позиции означает запуск команды каждое воскресенье, а имя архива, как и в предыдущем примере, будет содержать дату архивирования данных:
0 3 * * 0 tar -czf /backup/weekly_$(date +\%Y\%m\%d).tar.gz /var/www/html
Подобным же образом при помощи rsync — утилиты для быстрой и надёжной синхронизации файлов и каталогов, можно с определённой периодичностью копировать данные из одной Linux-системы в другую:
30 4 * * * rsync -avz /important/data/ remote-user@192.168.0.11:/backup/
Прелесть данной утилиты в том, что она копирует только изменённые данные, что позволяет экономить трафик и время. Конкретно в этой команде:
/important/data/— каталог, содержимое которого подлежит синхронизации с удалённым ресурсом. Обратите внимание на слэш в конце: он означает, что копировать нужно только содержимое каталога, а не сам каталог.-
remote-user@192.168.0.11:/backup/— место назначения, где:remote-user— это имя пользователя на удалённой системе;192.168.0.11— IP-адрес удалённой системы;/backup/— директория на удалённом узле, в который будет помещено содержимое исходного каталога.
На VPS всё это особенно актуально: регулярные дампы, архивация и перенос данных между серверами — типичная практика. На виртуальных серверах UltraVDS, например, можно настроить такие задачи буквально за несколько минут.
Очистка и обслуживание системы
Это — ещё одно направление в администрировании Linux-систем, где использование планировщика является частью повседневности. При работе операционной системы, служб и приложений появляются и накапливаются временные файлы, которые создаются при установке, обновлении или обработке данных, и после выполнения своей задачи зачастую становятся бесполезными.
Ниже — пример простенького скрипта, который удаляет из каталога /tmp файлы, не изменявшиеся больше семи дней:
#!/bin/bash
TMP_DIR="/tmp"
find "$TMP_DIR" -type f -mtime +7 -delete
Такая запись в cron позволит запускать этот скрипт раз в сутки:
0 5 * * * /usr/local/bin/clean_script.sh >/dev/null 2>&1
Можно обойтись и без скрипта, записав команду удаления файлов сразу в cron:
0 5 * * * find /tmp -type f -mtime +7 -delete
То же относится к логам — записям о событиях, ошибках и действиях системы. Логи полезны для диагностики, но со временем становятся слишком объёмными и могут занимать полезное пространство. Так может выглядеть задача по еженедельному удалению старых лог-файлов в директории /var/log. Здесь опция -mtime +30 говорит нам, что необходимо найти и удалить файлы старше тридцати дней:
0 0 * 0 find /var/log -name ".log" -mtime +30 -exec rm {} \;
Или вот кэш — временное хранилище данных, которое призвано ускорить загрузку приложения, но по прошествии времени в нём накапливается много устаревших и ненужных данных. Пример ниже — ежедневное принудительное удаление содержимого кэш-директории условного приложения app:
15 3 * * rm -rf /var/cache/app/
Мониторинг и уведомления
Планировщик cron в том числе можно использовать как простейший инструмент мониторинга системы. Например, так можно настроить периодическую отправку отчёта об использовании дискового пространства на электронную почту администратора:
0 */6 * * * df -h | mail -s "Disk Space Report" admin@vash-domain.ru
Правда, чтобы отправка писем действительно работала, сервер нужно заранее настроить — почтовая система должна понимать, куда и каким способом доставлять сообщения.
Мониторинг используется не только как внимательный наблюдатель за состоянием сервисов и процессов. При помощи планировщика и несложного скрипта можно попытаться своевременно, или почти своевременно, поднять упавшую службу. Например, следующим образом каждые 10 минут cron проверяет, запущена ли служба Nginx, и если не запущена — перезапускает её:
*/10 * * * * systemctl is-active --quiet nginx || systemctl restart nginx
Обновления
Классическая задача для cron — обновление бесплатного SSL-сертификата от Let's Encrypt с использованием Certbot. Как правило, такой сертификат выдаётся на 90 дней и перед истечением данного срока его нужно обновить, чтобы сайт продолжал быть доступным через HTTPS. Certbot — это утилита, которая позволяет автоматизировать процесс получения и продления SSL-сертификата от Let's Encrypt. Для проверки срока действия сертификата и его обновления в Certbot используется cron. Официальная документация Let's Encrypt рекомендует запускать проверку дважды в день, что должно гарантировать обновление сертификата даже при временном отсутствии интернета.
0 7,19 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
Здесь:
certbot renew— команда, которая пытается обновить SSL-сертификаты Let’s Encrypt, срок которых подходит к концу;--quiet— опция, определяющая запуск команд в «тихом» режиме, то есть без вывода сообщений;--deploy-hook— команда, которая выполнится только при успешном обновлении сертификата — перезапустит конфигурацию веб-сервера, в данном случае Nginx, чтобы он применил новый сертификат.
Обработка данных
Ещё один популярный сценарий для cron — автоматическая обработка данных. Например, регулярная генерация разных отчётов без вашего участия. Вместо ежедневной или еженедельной ручной сборки данных можно создать скрипт, который будет выполнять такую задачу, и автоматизировать процесс при помощи расписания.
Примером могут послужить ежедневные отчёты, которые необходимо собирать в нерабочее время — до начала или, наоборот, после окончания рабочего дня. Сюда же можно отнести различную периодическую аналитику или статистику за определённый регулярно повторяющийся период. Такой отчёт, как правило, сохраняется в файл для последующей отправки на email, загрузки на файлообменник или ещё куда-либо.
Python-скрипт, допустим, собирает данные из SQLite:
#!/usr/bin/env python3
import sqlite3
import smtplib
from email.mime.text import MIMEText
conn = sqlite3.connect('/data/base.db')
cursor = conn.cursor()
cursor.execute("SELECT SUM(amount), COUNT(*) FROM orders WHERE date > date('now', '-7 days')")
total, count = cursor.fetchone()
conn.close()
Потом формирует текстовый отчёт и отправляет его на электронную почту:
report = f"Продажи за неделю:\nЗаказов: {count}\nСумма: {total} руб."
msg = MIMEText(report)
msg['Subject'] = 'Еженедельный отчёт'
msg['To'] = 'ceo@org.com'
with smtplib.SMTP('localhost') as server:
server.send_message(msg)
Запуск задачи поручаем cron — в 8 утра каждый понедельник:
0 8 * * 1 /usr/bin/python3 /scripts/weekly.py >> /var/log/reports.log 2>&1
Некоторые полезные команды
Кроме команды crontab -e, упомянутой в самом начале, при работе с планировщиком будут полезны инструменты командной строки, как, например, просмотр текущих задач:
crontab -l
Команда выводит список всех запланированных заданий для текущего пользователя. Удобно, например, для того, чтобы убедиться в корректном добавлении задачи.
Для удаления всех заданий запускаем:
crontab -r
Команда полностью очищает crontab текущего пользователя. Поэтому используйте её осторожно, при выполнении команды не выводится никаких подтверждений.
Команда для просмотра логов cron выглядит как:
grep CRON /var/log/syslog
Вывод показывает записи о событиях при запуске задач cron.
Заключение
Потратив немного времени на настройку и проверку заданий для планировщика, мы получаем отличный бонус — больше не нужно вручную выполнять однообразные задачи и переживать, что что-то пойдёт не так. Теперь всё происходит по расписанию и без лишних нервов.
Так мы постепенно переключаемся с вечного «тушения пожаров» на спокойное, продуманное управление. А своё время наконец можно потратить на то, что действительно требует человеческих мозгов или творчества.