Модуль 08 — cron, таймеры и резервное копирование

Скрипт, который работает ночью без вас — и копия, из которой можно восстановиться

Прогресс курса Модуль 8 из 9

Что вы освоите в этом модуле

01

cron

cron — служба, которая запускает команды по расписанию. Расписание пользователя редактируется командой crontab -e, просмотр — crontab -l. Строка — пять полей времени и команда:

# мин  час  день  месяц  день_недели  команда
10   3    *     *      *            /usr/local/bin/backup >> /var/log/backup.log 2>&1
*/15 *    *     *      *            /usr/local/bin/check-disk
0    9    *     *      1-5          /usr/local/bin/report
30   2    1     *      *            /usr/local/bin/monthly-cleanup
ЗаписьЗначение
*Любое значение
*/15Каждые 15 (минут, часов…)
1-5Диапазон: дни недели с понедельника по пятницу (0 и 7 — воскресенье)
9,18Список значений

Системные задания лежат в /etc/crontab и файлах /etc/cron.d/ — у них есть шестое поле: от чьего имени запускать. Скрипты в /etc/cron.daily/ выполняются раз в день целиком (имена файлов без точек — иначе их пропустят).

$ grep -v '^#' /etc/crontab | grep .
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
17 *	* * *	root	cd / && run-parts --report /etc/cron.hourly
25 6	* * *	root	test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
...
02

Почему в cron не работает то, что работает в терминале

Классическая история: скрипт отлично работает руками, а из cron молча не делает ничего. Причина — другое окружение.

ОтличиеСледствиеРешение
Короткий PATHКоманды из /usr/local/sbin или ~/.local/bin «не найдены»Полные пути или PATH=… в начале скрипта
Оболочка /bin/shБашизмы в строке crontab не работаютСложную логику — в скрипт с #!/bin/bash
Текущий каталог — домашнийОтносительные пути ведут не тудаАбсолютные пути или cd /путь || exit
Нет терминалаВывод теряется или уходит письмом, которое никто не читает>> журнал 2>&1 или logger
Знак %В crontab означает перевод строки: date +%F ломает командуЭкранировать \% или вынести в скрипт
Нет LANGСообщения на английском, кириллица в именах может отображаться неверноЗадать в скрипте, если важно

Проверка «как в cron» — запуск с пустым окружением: env -i /bin/sh -c '/usr/local/bin/backup'. Если в таком виде скрипт работает, в cron он тоже заработает.

03

Таймеры systemd

В современных дистрибутивах расписание всё чаще задают таймерами systemd. Таймер состоит из двух файлов в /etc/systemd/system/: служба описывает, что запускать, таймер — когда.

# /etc/systemd/system/backup.service
[Unit]
Description=Резервное копирование сайта

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup
Nice=10
IOSchedulingClass=idle
# /etc/systemd/system/backup.timer
[Unit]
Description=Резервное копирование сайта ежедневно в 03:10

[Timer]
OnCalendar=*-*-* 03:10:00
Persistent=true
RandomizedDelaySec=5min

[Install]
WantedBy=timers.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now backup.timer
$ systemctl list-timers backup.timer
$ sudo systemctl start backup.service      # запустить вне расписания, для проверки
$ journalctl -u backup.service -n 20        # весь вывод скрипта — здесь

Формат OnCalendar проверяется командой systemd-analyze calendar — она покажет ближайшие срабатывания:

$ systemd-analyze calendar "Mon..Fri *-*-* 09,18:00" --iterations=3
  Original form: Mon..Fri *-*-* 09,18:00
...
    Next elapse: Thu 2026-10-15 09:00:00 MSK
   Iteration #2: Thu 2026-10-15 18:00:00 MSK
   Iteration #3: Fri 2026-10-16 09:00:00 MSK
cronТаймер systemd
НастройкаОдна строкаДва файла
Вывод скриптаНужно перенаправлять самомуАвтоматически в журнал службы
Машина была выключена в момент запускаЗапуск пропущенPersistent=true — выполнится при включении
Запуск, пока идёт предыдущийЗапустится второй экземплярСлужба уже активна — второй не стартует
Ограничение ресурсов, запуск от пользователяВручнуюNice=, User=, MemoryMax= в службе

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

04

rsync: зеркало каталога

rsync копирует каталоги, передавая только изменения, — локально или через SSH. Ставится пакетом rsync.

$ rsync -av --delete --dry-run site/ mirror/     # сначала посмотреть
sending incremental file list
index.html
deleting css/s.css
css/

sent 183 bytes  received 44 bytes  454,00 bytes/sec
total size is 20.015  speedup is 88,17 (DRY RUN)
$ rsync -av --delete site/ mirror/                # потом выполнить
$ rsync -az -e ssh /var/www/site/ backup@srv02:/srv/mirror/site/    # на другой сервер
ОпцияЗначение
-aАрхивный режим: рекурсивно, с правами, владельцами, датами, ссылками
-v, --statsСписок файлов, итоговая статистика
-zСжимать при передаче по сети
--deleteУдалять в копии то, чего больше нет в источнике
-n, --dry-runПоказать, что будет сделано
--exclude 'cache/'Не копировать
Косая черта в конце источника меняет смысл: rsync -a site/ mirror/ копирует содержимое site, rsync -a site mirror/ — сам каталог, получится mirror/site/. А --delete с перепутанными источником и приёмником стирает оригинал. Поэтому — сначала --dry-run.

Зеркало — ещё не резервная копия: случайное удаление файла на сайте с --delete ночью удалит его и в зеркале. Нужны копии на разные даты.

05

Архив с датой и контрольная сумма

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

$ name=site-$(date +%F).tar.gz
$ tar -czf "$name" -C /var/www site && gzip -t "$name" && echo "архив цел"
архив цел
$ sha256sum "$name" > "$name.sha256"
$ sha256sum -c "$name.sha256"
site-2026-10-14.tar.gz: ЦЕЛ
$ echo x >> "$name"; sha256sum -c "$name.sha256"     # имитация порчи
site-2026-10-14.tar.gz: ПОВРЕЖДЁН
sha256sum: WARNING: 1 computed checksum did NOT match

-C /var/www site — перейти в /var/www и упаковать site: в архиве будут относительные пути site/…, а не var/www/site/…, и распаковать его можно куда угодно. gzip -t проверяет целостность сжатия, tar -tzf — что архив читается.

06

Ротация: сколько копий хранить

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

По количеству — хранить N последних. ls -1t сортирует по времени, новые сверху; tail -n +8 выдаёт всё начиная с восьмой строки, то есть лишнее при N = 7:

$ ls arch | wc -l
10
$ ls -1t arch/site-*.tar.gz | tail -n +8
arch/site-2026-10-03.tar.gz
arch/site-2026-10-02.tar.gz
arch/site-2026-10-01.tar.gz
$ ls -1t arch/site-*.tar.gz | tail -n +8 | xargs -r rm --
$ ls arch | wc -l
7

Имена архивов здесь без пробелов — вы сами их формируете, поэтому разбор вывода ls допустим. xargs -r не вызывает rm, если удалять нечего.

По возрасту — удалять старше N дней: find /srv/backup -name 'site-*.tar.gz' -mtime +30 -delete. Опасность: если копии перестали создаваться, через месяц find удалит последние. Ротация по количеству такого не допускает — поэтому для резервных копий она надёжнее, а лучше — обе с проверкой, что свежая копия создана перед удалением старых.

07

Копия, из которой можно восстановиться

Резервная копия, из которой ни разу не восстанавливались, — гипотеза, а не копия. Правило 3-2-1: три копии данных, на двух разных носителях, одна — в другом месте (другой сервер, облачное хранилище, офис).

Что проверить в своей схеме

  • Что копируется. Данные сайта, базы (дамп, а не файлы работающей СУБД), конфигурация /etc, ключи и сертификаты. Список — в шапке скрипта.
  • Куда. Не на тот же диск, что и данные: при отказе диска пропадёт всё. Для копии на другом сервере — отдельный пользователь с доступом только на запись в свой каталог.
  • Как узнать о сбое. Скрипт возвращает ненулевой код, пишет в журнал; есть проверка «последней копии не больше суток».
  • Восстановление. Раз в месяц — распаковать копию в отдельный каталог или на тестовую машину и убедиться, что сайт открывается. Записать, сколько это заняло времени.
  • Секреты. Копия содержит пароли из конфигурации — права 600, каталог 700, при выносе наружу — шифрование.

Ключевые выводы модуля

Запомните главное

  • crontab: пять полей времени и команда; окружение cron скудное — полные пути, вывод в журнал
  • Таймер systemd: служба + таймер, Persistent=true, вывод в journalctl -u; проверка — systemd-analyze calendar
  • rsync -a --delete — зеркало; сначала --dry-run; косая черта в конце источника важна
  • Копия на дату — tar -czf имя-$(date +%F), проверка gzip -t и sha256sum
  • Ротация по количеству надёжнее ротации по возрасту; копия без проверки восстановления — не копия
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Модуль 07: Надёжность Все модули Итоговый проект