MAATRIX / Блог / Антипаттерн: автообновления везде и без бэкапа

Антипаттерн: автообновления везде и без бэкапа

MAATRIX

«Включил автообновления везде и забыл» — фраза, которая звучит как здравый смысл: патчи безопасности накатятся сами, не нужно помнить про apt upgrade по расписанию, не нужно следить за версиями образов в Docker. На практике за этой фразой обычно стоит не продуманная стратегия, а отсутствие какой-либо: обновляется всё подряд — ОС, приложения, зависимости, — без предварительного бэкапа и без контроля результата. Разберём, почему это не экономия времени, а отложенный до случайного момента инцидент, и как настроить автообновления так, чтобы они действительно снимали нагрузку, а не создавали новую.

Как это выглядит на практике

Типичная настройка «автообновления и забыть» на VPS с Ubuntu или Debian — это unattended-upgrades с расширенной конфигурацией, которая молча тянет не только security-патчи:

// /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-updates";
    "${distro_id}ESM:${distro_codename}";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Обратите внимание на ${distro_codename}-updates — это не только security-репозиторий, а весь поток обновлений дистрибутива, включая обновления версий пакетов, не связанные с уязвимостями. Плюс Automatic-Reboot "true" — сервер сам уйдёт в перезагрузку в 2 часа ночи, если обновилось ядро или системная библиотека, требующая рестарта сервиса.

На уровне Docker то же самое встречается в виде Watchtower без ограничений:

services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_POLL_INTERVAL=3600
    # без WATCHTOWER_INCLUDE / WATCHTOWER_LABEL_ENABLE —
    # обновляет вообще все контейнеры на хосте раз в час

И в CMS — плагин автообновлений WordPress, который выставлен на «обновлять все плагины и темы автоматически», или npm-check-updates в cron, который прогоняет ncu -u && npm install по расписанию без единого прогона тестов. Формально в каждом отдельном случае решение объяснимо: «зачем вручную накатывать патчи безопасности, если это можно доверить системе». Проблема не в самой идее автообновлений, а в том, что процесс останавливается на этом решении и не идёт дальше — к вопросу «а что если обновление сломает что-то, и как я это замечу и откачу».

Почему «не думать об этом» — ложная экономия

Аргумент в пользу тотальных автообновлений обычно звучит как экономия времени: не нужно регулярно вручную проверять и накатывать патчи на десяток серверов. Это действительно так — ровно до первого неудачного обновления. Дальше время не экономится, а тратится в кредит, причём с процентами: вместо получаса на плановое обновление в удобное время — несколько часов на разбор, почему упал прод, в момент, который вы не выбирали.

Ключевая проблема в характере рисков. Обновление пакета — не бинарное «сработало или нет», как кажется на первый взгляд. Оно может:

  • изменить формат конфигурационного файла и не примениться из-за конфликта с локальными правками (типичный случай для nginx, PHP-FPM, systemd unit-файлов);
  • поднять мажорную версию зависимости с несовместимым API — приложение стартует, но падает на первом реальном запросе;
  • обновить библиотеку, от которой зависит другой, не обновлённый пакет, и разорвать связку, которая работала только на конкретной комбинации версий;
  • потребовать миграцию схемы базы данных, которую никто не запустил, потому что автообновление тянуло только бинарник.

Ни один из этих сценариев не ловится простой проверкой «apt exit code == 0» или «контейнер поднялся». Система обновилась успешно с точки зрения пакетного менеджера — и одновременно перестала нормально работать с точки зрения пользователей. Разница между «обновление прошло» и «обновление не сломало прод» — именно то, что теряется, когда автообновления настроены и забыты.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Обновление происходит именно тогда, когда некому среагировать

Это отдельный и часто недооценённый риск: автообновления по расписанию систематически происходят в то время, когда меньше всего шансов быстро заметить проблему и отреагировать. Ночь выбирается специально, чтобы не мешать дневному трафику и не пересекаться с ручными релизами — Automatic-Reboot-Time "02:00" в примере выше не случайность, это рекомендация по умолчанию во многих гайдах. Логика понятна: меньше активных пользователей — меньше заметность простоя. Но она же означает, что если обновление пойдёт не так, об этом узнают не сразу, а с задержкой в часы — пока кто-то не проснётся, не откроет сайт или не получит алерт, если он вообще настроен.

Выходные усиливают тот же эффект на уровне команды: обновление пакетов не завязано на рабочий график разработчиков, а unattended-upgrades и Watchtower тикают по своему расписанию independent от того, кто сегодня на связи. Получается комбинация из двух факторов: обновление происходит в момент минимального контроля именно потому, что это удобное время для системы — и оно же оказывается самым неудобным временем для человека, если что-то идёт не так. Ирония в том, что чем меньше внимания уделяется настройке автообновлений заранее, тем больше внимания придётся уделить им в самый неподходящий момент.

Частично эту проблему снимает мониторинг с алертами — но только частично: алерт скажет, что сервис недоступен, а не подскажет мгновенно, что причина — ночное автообновление трёхчасовой давности. Разбор придётся вести по логам постфактум, теряя время именно там, где счёт может идти на минуты.

Без свежего бэкапа мелкий сбой становится инцидентом

Здесь находится главный разрыв в схеме «автообновления везде и без бэкапа»: сама по себе неудачная автоматическая установка пакета — это малоприятное, но обычно решаемое событие, если есть состояние, к которому можно откатиться. Без свежего бэкапа перед обновлением тот же самый сбой превращается в инцидент с непредсказуемым временем восстановления, потому что откатываться приходится «на ощупь» — руками разбирая, что именно изменилось, и пытаясь собрать рабочую конфигурацию заново, а не просто развернуть состояние час-два назад.

Разница особенно заметна на базах данных. Если автообновление СУБД (например, минорная версия PostgreSQL или MySQL, обновившаяся вместе с системными пакетами) уронило сервис из-за несовместимости с текущими данными или конфигом, откат на уровне «переустановить старую версию пакета» не всегда возвращает рабочее состояние — форматы файлов на диске могли уже частично измениться. Тут нужен не откат пакета, а восстановление из бэкапа, сделанного до обновления. Если такого бэкапа нет, потому что «бэкапы у нас идут раз в сутки по расписанию, а не перед каждым обновлением», разрыв между последней рабочей копией и моментом сбоя может быть немаленьким — от нескольких часов до суток, в зависимости от того, в какое время суток случился сбой относительно расписания бэкапов.

Тот же эффект работает на уровне контейнеров: Watchtower подтянул новый образ, старый образ формально ещё лежит локально — но если параллельно чистится WATCHTOWER_CLEANUP=true, старые образы удаляются автоматически, и через какое-то время откатиться на предыдущую версию образа становится нечем, если только она не зафиксирована отдельно в реестре по тегу. Мы отдельно разбирали похожую ситуацию с ложным ощущением быстрого отката — что происходит, когда обновление кладёт прод и приходится откатываться на практике: там же видно, что «просто откатиться» реально работает только тогда, когда откат подготовлен заранее, а не придуман по ходу инцидента.

Что стоит обновлять автоматически, а что — нет

Ответ на «автообновления — это плохо?» — нет, это не так. Проблема конкретно в *безусловных* автообновлениях всего подряд без разбора. У security-патчей и всех остальных обновлений принципиально разный профиль риска, и это стоит закрепить в конфигурации, а не держать в голове:

Тип обновленияАвтоматическиПочему
Security-патчи ОС (CVE-фиксы)ДаУзкий, целевой фикс; риск от неприменённой уязвимости обычно выше риска от патча
Минорные патч-версии приложений (x.y.Z)Да, с осторожностьюОбычно только багфиксы, но иногда меняют поведение по умолчанию
Минорные версии (x.Y.z)Вручную или с задержкой (staged)Могут добавлять/менять API, требовать миграций
Мажорные версии (X.y.z)Только вручнуюВысокая вероятность breaking changes, часто требуют миграции данных
Обновления ядра с автоперезагрузкойВручную по расписанию обслуживанияПростой сервиса, не мгновенный процесс
Обновления СУБД любого масштабаВручную, с бэкапом перед стартомФормат данных на диске — самая дорогая вещь для отката

На практике это означает: unattended-upgrades стоит настраивать так, чтобы он тянул именно security-репозиторий, а не весь поток обновлений дистрибутива:

// /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "false";

Для Watchtower — ограничить область действия конкретными сервисами через лейблы, а не обновлять хост целиком:

services:
  watchtower:
    image: containrrr/watchtower
    command: --label-enable --cleanup
    environment:
      - WATCHTOWER_POLL_INTERVAL=86400

  frontend:
    image: myregistry/frontend:1.4
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  postgres:
    image: postgres:16
    # без лейбла — Watchtower его не трогает,
    # версия базы обновляется только осознанно

Похожий разбор именно security-обновлений и частых ошибок в их настройке — в отдельной статье про автообновления безопасности на сервере, если нужно настроить эту часть с нуля правильно с первого раза.

Как построить процесс, а не выключатель «вкл/выкл»

Рабочая схема — не «автообновления да или нет», а последовательность шагов вокруг любого обновления, которое может задеть продакшен:

  1. Бэкап перед изменением, а не по общему расписанию. Для критичных сервисов — БД, конфиги, состояние приложения — снимок делается непосредственно перед обновлением, отдельно от плановых ночных бэкапов. Это может быть просто дамп или снапшот тома:
# перед мажорным обновлением postgres — снимок именно сейчас,
# а не надежда на то, что ночной бэкап не устарел
pg_dump -Fc mydb > /backups/pre-update-$(date +%F-%H%M).dump

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

  1. Staged rollout вместо обновления всего парка одновременно. Если серверов несколько, автообновление применяется сначала к одному-двум некритичным, и только через несколько дней без проблем — к остальным. Для Watchtower это можно сделать через разные WATCHTOWER_POLL_INTERVAL и лейблы на группах хостов; для unattended-upgrades — через разное время Automatic-Reboot-Time и отдельный мониторинг за первым обновившимся сервером.
  1. Мониторинг сразу после, а не только на инцидент. После автообновления должна быть точка проверки: healthcheck сервиса, алерт на рост ошибок, простая проверка «сайт отвечает 200». Инструменты вроде Uptime Kuma или healthchecks.io закрывают эту задачу без больших затрат — если автообновление сломало сервис в 2 часа ночи, алерт должен прийти в 2:05, а не остаться незамеченным до утра.
  1. Явный план отката, зафиксированный заранее. Не «разберёмся по ситуации», а конкретные команды: apt-mark hold пакет, тег предыдущего образа Docker, команда восстановления из дампа. У нас есть отдельный разбор, как выглядит план отката для более крупных изменений вроде миграций — тот же принцип применим к обычным обновлениям пакетов: план отката пишется до, а не во время инцидента.
# зафиксировать пакет на текущей версии,
# если он критичен и обновляется только вручную
apt-mark hold postgresql-16

Ни один из этих шагов не отменяет автоматизацию — они делают её предсказуемой. Автообновление остаётся автоматическим для security-патчей; для всего, что может сломать продакшен, автоматика ограничивается зоной, где откат подготовлен и мониторинг настроен.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Если сервер маленький и некритичный, можно ли просто оставить автообновления как есть?

Для тестового стенда или личного проекта без SLA — да, риск оправдан экономией времени. Граница проходит там, где сбой сервиса действительно кому-то мешает: продакшену, платному сервису, чему-то, что нельзя терять на несколько часов без последствий.

Автообновления ядра с автоперезагрузкой — это всегда плохо?

Не всегда, но требует явного окна обслуживания и понимания, что сервис на это время недоступен. Для кластера из нескольких узлов с поочерёдным обновлением — приемлемо. Для одиночного сервера с постоянной нагрузкой лучше держать перезагрузку под ручным контролем и планировать заранее.

Сколько по времени должен быть разрыв между бэкапом и обновлением?

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

Достаточно ли просто снапшота виртуальной машины перед обновлением вместо полноценного бэкапа?

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

Как быстро понять после инцидента, что причина именно в автообновлении?

Проверить журнал обновлений (/var/log/unattended-upgrades/ или логи Watchtower) на совпадение по времени с началом проблемы — это первое, что стоит смотреть при внезапном сбое без ручных изменений в тот же день.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →