opened image

Cron и crontab: автоматизация задач на Linux-сервере

 

Cron - демон, который выполняет команды по расписанию. Запускается при старте системы, читает расписание из файлов crontab и проверяет каждую минуту, не пора ли что-нибудь выполнить. Без cron администрирование сервера превращается в ручной труд: бэкапы, очистка логов, обновление данных - всё это можно автоматизировать.

 

 

Синтаксис crontab: пять полей и команда

 

Каждая строка в crontab - одна задача. Формат:

 

минуты  часы  день_месяца  месяц  день_недели  команда

 

Диапазоны каждого поля:

 

Поле

Диапазон

Минуты

0–59

Часы

0–23

День месяца

1–31

Месяц

1–12

День недели

0–7 (0 и 7 - воскресенье)

 

 

Звёздочка * означает "каждое значение". Примеры:

 

# Каждый день в 02:30
30 2 * * * /usr/bin/backup.sh

# Каждый понедельник в 03:00
0 3 * * 1 /usr/bin/weekly-report.sh

# Каждые 15 минут
*/15 * * * * /usr/bin/check-service.sh

# В первый день каждого месяца в 00:00
0 0 1 * * /usr/bin/monthly-cleanup.sh

# В 12:00 и 18:00 каждый день
0 12,18 * * * /usr/bin/send-digest.sh

 

Запятая перечисляет несколько значений: 0,15,30,45 * * * * - каждые 15 минут. Дефис задаёт диапазон: 0 9-17 * * 1-5 - каждый час с 9 до 17 по будням.

 

 

 

Редактирование через crontab -e

 

Не редактируйте файлы crontab напрямую в /var/spool/cron/. Используйте команду:

 

crontab -e

 

При первом запуске выберите редактор (nano - проще, vim - для тех, кто привык). Команда открывает crontab текущего пользователя.

 

Полезные флаги:

crontab -l           # посмотреть текущее расписание
crontab -e           # редактировать
crontab -r           # удалить все задачи (осторожно, без подтверждения)
crontab -u www-data -e  # редактировать crontab другого пользователя (нужен root)

 

 

 

 

Crontab конкретного пользователя хранится в /var/spool/cron/crontabs/username. Системные задачи находятся в /etc/cron.d/ и в директориях /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/.

 

 

Специальные символы и сокращения

 

*/5   * * * *   # каждые 5 минут
0     */2 * * * # каждые 2 часа
0     0 */3 * * # каждые 3 дня
0     0 * * 0   # каждое воскресенье в полночь

 

Cron поддерживает строки-сокращения вместо пяти полей:

 

Сокращение

Значение

@reboot

При каждом старте системы

@yearly

Раз в год (0 0 1 1 *)

@monthly

Раз в месяц (0 0 1 * *)

@weekly

Раз в неделю (0 0 * * 0)

@daily

Раз в день (0 0 * * *)

@hourly

Каждый час (0 * * * *)

 

Пример с @reboot:

 

@reboot /usr/bin/start-monitoring.sh

 

Скрипт запустится при каждой загрузке системы.

 

 

Переменные MAILTO и SHELL

 

По умолчанию cron отправляет вывод выполненных команд по почте пользователю. Это настраивается переменными в начале crontab:

 

SHELL=/bin/bash
MAILTO=admin@example.com
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Задачи
0 2 * * * /usr/bin/backup.sh

 

 

SHELL=/bin/bash - указывает, каким интерпретатором выполнять команды. По умолчанию /bin/sh, что может вызвать проблемы если скрипты используют bash-специфичный синтаксис.

MAILTO=admin@example.com - куда отправлять вывод команд. Если задача выводит текст в stdout или stderr, cron отправит его на этот адрес.

MAILTO="" - отключить отправку писем полностью. Удобно, когда почта не настроена, а задачи генерируют вывод.

PATH - явно указать пути поиска команд. Cron запускается с минимальным окружением, команды типа python3 или node могут не находиться без явного пути.

 

 

Лучшая практика - всегда писать полные пути к командам:

 

0 3 * * * /usr/bin/python3 /home/deploy/scripts/cleanup.py

 

 

Пять практических примеров задач

 

 

1. Ежедневный бэкап базы данных

 

0 3 * * * /usr/bin/mysqldump -u root -p'secret' mydb > /backups/mydb_$(date +\%Y-\%m-\%d).sql 2>/dev/null

 

Знак % в crontab нужно экранировать: \%. Без экранирования cron интерпретирует % как символ новой строки. Бэкап создаётся каждый день в 03:00 с датой в имени файла.

 

Лучше вынести команду в отдельный скрипт:

# /usr/local/bin/db-backup.sh
#!/bin/bash
BACKUP_DIR="/backups"
DATE=$(date +%Y-%m-%d)
mysqldump -u root -p'secret' mydb > "$BACKUP_DIR/mydb_$DATE.sql"
find "$BACKUP_DIR" -name "*.sql" -mtime +30 -delete
0 3 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1

 

>> /var/log/db-backup.log 2>&1 - весь вывод (stdout и stderr) пишется в лог-файл.

 

 

2. Очистка временных файлов

 

0 4 * * 0 find /tmp -type f -mtime +7 -delete

 

Каждое воскресенье в 04:00 удаляются файлы в /tmp старше 7 дней.

 

 

3. Перезапуск сервиса при зависании

*/5 * * * * /usr/local/bin/check-nginx.sh

 

Скрипт проверяет состояние и перезапускает при необходимости:

#!/bin/bash
if ! systemctl is-active --quiet nginx; then
    systemctl start nginx
    echo "$(date): nginx restarted" >> /var/log/nginx-monitor.log
fi

 

 

4. Обновление сертификатов SSL

 

0 0,12 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"

 

Дважды в сутки certbot проверяет, нужно ли продлить сертификат. --quiet подавляет вывод при успехе. --deploy-hook перезагружает Nginx после продления.

 

 

5. Синхронизация файлов на резервный сервер

 

30 1 * * * rsync -az --delete /var/www/html/ user@backup-server:/var/www/html/ >> /var/log/rsync.log 2>&1

 

Каждую ночь в 01:30 содержимое /var/www/html/ синхронизируется на резервный сервер. --delete удаляет на резервном файлы, которые удалены на основном.

 

 

 

 

Отладка через /var/log/syslog

 

Когда задача не выполняется - первое место проверки:

 

grep CRON /var/log/syslog | tail -20

 

Типичные записи:

May 22 03:00:01 server CRON[12345]: (root) CMD (/usr/local/bin/db-backup.sh)
May 22 03:00:01 server CRON[12346]: (CRON) info (No MTA installed, discarding output)

 

Первая строка - задача запустилась. Вторая - есть вывод, но нет почтового агента. Чтобы увидеть вывод, перенаправьте его в файл.

 

На Ubuntu 22.04 логи cron также доступны через journald:

 

journalctl -u cron --since "today" | grep CMD

 

 

Частые причины незапуска задач:

  • Нет прав на выполнение скрипта (chmod +x script.sh)

  • Неполный путь к интерпретатору или команде

  • % в команде не экранирован

  • Задача работает, но молча падает: проверьте 2>&1 в перенаправлении

  • Переменная PATH не содержит нужную директорию

 

Быстрый тест: запустите команду из crontab вручную от нужного пользователя:

 

sudo -u www-data /usr/local/bin/my-task.sh

 

 

Сравнение с systemd-таймерами

 

Systemd-таймеры - альтернатива cron на современных Linux-системах. Разница:

 

Параметр

Cron

Systemd-таймеры

Настройка

Один файл crontab

Два файла: .timer + .service

Логи

/var/log/syslog

journald (journalctl)

Зависимости

Нет

Можно задать зависимости от других юнитов

Пропущенные запуски

Не восстанавливает

Persistent=true запускает пропущенное

Точность

Минута

Секунда и меньше

Окружение

Минимальное

Полноценное systemd-окружение

 

Для большинства задач cron проще и достаточен. Systemd-таймеры полезны, когда нужны зависимости ("запустить после запуска сети"), точность до секунды или удобный просмотр через journalctl.

 

Пример systemd-таймера для ежедневного бэкапа:

 

# /etc/systemd/system/db-backup.service
[Unit]
Description=Database backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Daily database backup timer

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
systemctl enable --now db-backup.timer
systemctl list-timers | grep backup

 

Persistent=true означает: если система была выключена в момент запуска - задача выполнится при следующем старте.

 

 

Управление cron-демоном

 

systemctl status cron       # состояние
systemctl start cron        # запустить
systemctl enable cron       # добавить в автозапуск
systemctl restart cron      # перезапустить

 

После изменения crontab через crontab -e перезапуск cron не нужен: демон сам отслеживает изменения в файлах расписания.

 

 

Итог

 

Cron - надёжный инструмент с 40-летней историей. Синтаксис из пяти полей покрывает 95% задач автоматизации. Главные правила: полные пути к командам, экранирование %, перенаправление вывода в лог, проверка через /var/log/syslog при проблемах. Для сложных сценариев с зависимостями и мониторингом смотрите в сторону systemd-таймеров.