Обновления Ubuntu без простоя: график, волны и откат
«Работает — не трогай» — самая дорогая стратегия обслуживания серверов. Сервер без обновлений рано или поздно взламывают, а сервер, который обновили вручную в обед, ломает печать в 14 пунктах сразу. Рассказываем, как мы обновляем парк из десятков машин так, чтобы этого никто не замечал.
Политика: что ставим сами, что — волнами
Мы делим обновления на две группы.
- Исправления безопасности из репозитория
-securityставятся автоматически каждую ночь на всех серверах. Они точечные, регрессии в них редки, а цена задержки высока: эксплойты к опубликованным уязвимостям появляются за дни. - Всё остальное — обычные исправления из
-updates, сторонние репозитории, новые ядра — раз в две недели волнами: сначала несколько пилотных серверов, через два дня — четверть парка, ещё через два дня — остальные.
Ubuntu и сама распространяет обновления -updates постепенно (phased updates): новая версия пакета сначала приходит небольшой доле машин, и при росте числа отчётов об ошибках выкатка останавливается. Это хорошая страховка, но не замена собственному пилоту: Canonical не знает, что на ваших серверах работает печать этикеток.
unattended-upgrades для исправлений безопасности
Пакет unattended-upgrades установлен в Ubuntu Server по умолчанию. Включается он файлом /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
Основные настройки — в /etc/apt/apt.conf.d/50unattended-upgrades. Мы не правим исходный файл, а кладём свой 52ops-local — он читается позже и переопределяет значения, а при обновлении пакета не будет конфликта:
// /etc/apt/apt.conf.d/52ops-local
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
// Пакеты, которые обновляем только вручную (регулярные выражения)
Unattended-Upgrade::Package-Blacklist {
"postgresql-";
"docker-ce";
};
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Перезагрузка — только если нужна, и только в окно
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
Unattended-Upgrade::Mail "admin@example.org";
Unattended-Upgrade::MailReport "only-on-error";
Сервер базы данных мы почти всегда исключаем из автоматического обновления СУБД: обновление пакета PostgreSQL перезапускает службу, а это обрыв соединений в рабочее время. Такие пакеты обновляем вручную, в окно, после проверки на копии.
Проверить настройки без реальной установки:
sudo unattended-upgrade --dry-run --debug 2>&1 | tail -n 30
# журнал реальных запусков
less /var/log/unattended-upgrades/unattended-upgrades.log
Перезапуск служб после обновления библиотек
Если обновилась, например, libssl, запущенные службы продолжают использовать старую копию библиотеки из памяти, пока их не перезапустят. Это делает needrestart. В интерактивном режиме он спрашивает, что перезапускать, — для серверов включаем автоматический режим:
# /etc/needrestart/conf.d/50-auto.conf
$nrconf{restart} = 'a';
# службы, которые нельзя перезапускать днём, — только при перезагрузке
$nrconf{override_rc}{qr(^postgresql)} = 0;
sudo needrestart -r l # показать, что требует перезапуска, ничего не трогая
Окно обслуживания и перезагрузки
По умолчанию списки пакетов обновляются таймером apt-daily.timer, а установка идёт по таймеру apt-daily-upgrade.timer около 6 утра со случайной задержкой до часа. Для магазина, который открывается в 8, это поздно. Переносим:
sudo systemctl edit apt-daily-upgrade.timer
[Timer]
# пустая строка сбрасывает расписание по умолчанию — без неё добавится второе
OnCalendar=
OnCalendar=*-*-* 02:30
RandomizedDelaySec=20m
sudo systemctl daemon-reload
systemctl list-timers 'apt-daily*'
Установка заканчивается к 03:00, а Automatic-Reboot-Time "03:30" перезагружает сервер, только если появился файл /var/run/reboot-required — обычно после обновления ядра или libc. Какие пакеты потребовали перезагрузки, видно в /var/run/reboot-required.pkgs.
Если у вас два сервера, дублирующих друг друга, — например, два узла за балансировщиком нагрузки, — не давайте им перезагружаться одновременно: разнесите Automatic-Reboot-Time хотя бы на 30 минут.
Волны через Ansible
Плановые обновления запускаем плейбуком. Серверы в инвентаре разбиты на группы pilot, wave1 и wave2; в пилот попадают по одному серверу каждого типа.
# upgrade.yml — запуск: ansible-playbook upgrade.yml -e target=wave1
- hosts: "{{ target }}"
become: true
serial: "20%" # не больше пятой части группы за раз
max_fail_percentage: 0 # первая ошибка останавливает волну
tasks:
- name: Обновить пакеты
ansible.builtin.apt:
update_cache: true
upgrade: safe
autoremove: true
- name: Нужна ли перезагрузка
ansible.builtin.stat:
path: /var/run/reboot-required
register: reboot_flag
- name: Перезагрузить
ansible.builtin.reboot:
reboot_timeout: 600
when: reboot_flag.stat.exists
- name: Служба печати работает
ansible.builtin.command: systemctl is-active cups
changed_when: false
- name: Нет упавших служб
ansible.builtin.command: systemctl --failed --no-legend
register: failed_units
changed_when: false
failed_when: failed_units.stdout | length > 0
Последние две задачи — самые важные. Обновление считается успешным не тогда, когда apt завершился без ошибок, а когда работает то, ради чего сервер существует. Для каждого типа серверов у нас своя проверка: печать тестовой этикетки, запрос к базе, открытие страницы кассового приложения.
Если на пилоте что-то пошло не так, до следующей волны есть два дня. Проблемный пакет замораживается на остальных серверах одной командой, а волна идёт дальше без него:
ansible wave1:wave2 -b -m ansible.builtin.dpkg_selections \
-a "name=cups-filters selection=hold"
Снимки и откат
Перед плановой волной виртуальным машинам делаем снимки. В Proxmox VE это одна команда на узле:
qm snapshot 104 pre-upgrade-2026-10-13 --description "перед плановым обновлением"
# если всё плохо
qm rollback 104 pre-upgrade-2026-10-13
# если всё хорошо — через неделю удаляем, снимки замедляют диск
qm delsnapshot 104 pre-upgrade-2026-10-13
Для физических серверов без снимков остаётся откат пакета на предыдущую версию. Старые .deb обычно ещё лежат в кэше:
grep -A3 'Start-Date: 2026-10-13' /var/log/apt/history.log # что обновилось
ls /var/cache/apt/archives/ | grep cups-filters
sudo apt install ./cups-filters_1.28.17-3ubuntu1_amd64.deb # старая версия из кэша
sudo apt-mark hold cups-filters
Если новое ядро не загружается, в меню GRUB можно выбрать предыдущее: apt не удаляет ни загруженное сейчас ядро, ни предыдущую установленную версию, так что Remove-Unused-Kernel-Packages безопасен.
Что мониторить
- Возраст последнего успешного запуска unattended-upgrades — тревога, если больше 3 суток.
- Число ожидающих исправлений безопасности — тревога, если не ноль дольше недели.
- Наличие
/var/run/reboot-requiredдольше 7 дней — значит, автоматическая перезагрузка отключена или не срабатывает. - Свободное место в
/boot— переполнение ломает установку ядра и, как следствие, все последующие обновления. - Упавшие службы после перезагрузки:
systemctl --failed.
Если эти пять проверок зелёные, можно спокойно спать: серверы обновляются сами, а о проблемах вы узнаете раньше пользователей. Как это выглядит на парке из 60 серверов, мы рассказали в кейсе про сеть пунктов выдачи.