Сбой обновления Ubuntu: как восстановить систему
Если обновление Ubuntu с 24.04 до 26.04 прервалось, не перезагружайте сервер. В статье описано, как восстановить сессию screen, исправить ошибки dpkg и вернуть apt в работу.
Сбой обновления Ubuntu: сначала определите симптомы
Неудачное обновление релиза Ubuntu с 24.04 до 26.04 оставляет сервер в одном из четырех состояний, и для каждого из них требуется свой метод исправления. Процесс обновления может все еще выполняться внутри сессии screen, связь с которой была потеряна. Утилита dpkg могла быть принудительно завершена, когда пакет был настроен лишь частично, поэтому apt теперь блокирует любые операции установки, удаления или обновления пакетов, хотя apt update и команды для чтения, такие как apt show, по-прежнему работают. В источниках apt могут быть указаны репозитории 26.04, в то время как установленные пакеты все еще относятся к 24.04. Либо сервер может вовсе не загружаться. Прежде чем вводить какие-либо команды, определите, в каком состоянии находится система, так как решение для одного случая может усугубить другой.
Одно правило применимо ко всем четырем ситуациям. Не выполняйте перезагрузку, пока не выясните состояние dpkg. Перезагрузка в процессе замены пакетов превращает устранимую ошибку dpkg в ситуацию, когда система не загружается, что описано в конце этого руководства. Также не запускайте второй процесс apt или dpkg, пока первый может быть активен, так как одновременная запись двумя процессами приводит к повреждению базы данных пакетов.
Это руководство предполагает, что вы следовали инструкции по обновлению с 24.04 до 26.04 и сделали снимок состояния системы (snapshot) перед началом. Если вы этого не сделали, ознакомьтесь с разделом о загрузке с учетом этого факта, так как наличие снимка — это решение для самого худшего сценария.
Обновление всё ещё выполняется?
Многие обновления, которые кажутся неудачными, на самом деле продолжают выполняться. SSH-сессия прервалась, терминал погас, а процесс обновления продолжил работу без вашего участия.
do-release-upgrade создан именно для таких ситуаций. При запуске в текстовом интерфейсе, который используется на серверах, он автоматически запускается внутри сессии GNU screen, поэтому процесс обновления не завершается при потере терминала. Кроме того, если программа обнаруживает, что была запущена через SSH, она предлагает открыть вторую сессию sshd на другом порту (по умолчанию 1022). Это позволяет войти в систему, если основной SSH-демон выйдет из строя во время замены пакетов. Оба этих факта сейчас важны.
Подключитесь по SSH и найдите сессию screen. Обновление запускалось от имени sudo, поэтому сессия screen принадлежит пользователю root, и обычная команда screen -ls от вашего имени её не покажет.
sudo screen -lsscreen -ls помечает каждую сессию как присоединенную (attached) или отсоединенную (detached). Если сессия найдена, подключитесь к ней. Если она всё ещё помечена как присоединенная, потому что разорванное SSH-соединение не освободило её, -d сначала принудительно отсоединит этот зависший процесс.
sudo screen -d -rЕсли найдено несколько сессий, укажите имя сессии из screen -ls после -r. Не полагайтесь на то, что sudo do-release-upgrade автоматически восстановит подключение. Код, который находит существующую сессию screen, находится внутри загружаемого установщика. Перед тем как что-либо загрузить, do-release-upgrade завершает работу с сообщением "Please install all available updates for your release before upgrading", если находит пакеты, ожидающие обновления (за исключением поэтапных обновлений). Именно в таком состоянии находится система в середине процесса замены пакетов. После повторного подключения вы вернетесь к работающему обновлению, которое обычно ожидает ответа на запрос о замене файла конфигурации или перезапуске службы. Ответьте на запрос и позвольте процессу завершиться.
Если вы запустили обновление внутри tmux, как рекомендуется в руководстве, сначала восстановите сессию tmux с помощью tmux attach. Сессия screen запущена внутри этой панели tmux, поэтому вы увидите процесс обновления напрямую. Если в панели отображается только приглашение командной строки, значит, обновление там больше не выполняется, и следующим шагом будет sudo screen -ls.
Если основной SSH-порт отклоняет соединение, попробуйте резервный порт: ssh -p 1022 user@host. Этот демон существует только на время обновления. Если войти не удается ни через один из портов, используйте консоль вашего провайдера. В консоли sudo ss -ltnp покажет, на каких портах ожидает соединений процесс sshd, а sudo ufw status покажет, разрешает ли межсетевой экран трафик через резервный порт.
Если сессия screen отсутствует и в консоли нет ожидающих запросов, значит, обновление действительно остановилось. Прежде чем предпринимать какие-либо действия, убедитесь, что база данных пакетов не используется:
ps -eo pid,etime,cmd | grep -iE '[u]pgrade|[d]pkg|[a]pt'Пустой результат означает, что dpkg неактивен, и вы можете переходить к исправлению. Если процесс dpkg или apt выполняется долгое время, а сессии screen для подключения нет, значит, он завис. Подождите несколько минут, проверьте консоль на наличие вопроса debconf, на который никто не ответил, и только после этого завершайте процесс. Никогда не удаляйте файлы блокировки в /var/lib/dpkg/ или /var/lib/apt/lists/, пока их удерживает какой-либо процесс. Блокировка — это единственный механизм, предотвращающий одновременную запись, которая может привести к повреждению базы данных пакетов.
Процесс dpkg был прерван, и apt отказывается работать
Если процесс dpkg был завершен принудительно в момент между распаковкой пакета и выполнением его скрипта настройки, пакет остается в состоянии «частично настроен», а в журнале по пути /var/lib/dpkg/updates/ остаются незавершенные записи. Любая команда apt, захватывающая блокировку dpkg (то есть установка, удаление или обновление), сначала проверяет этот журнал и останавливается с ошибкой dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.. Команды, не требующие блокировки, такие как apt update, apt list, apt show и apt-cache, продолжают работать, поэтому вы можете просмотреть состояние системы. Независимо от того, что выводит apt, первым шагом всегда будет следующее действие.
sudo dpkg --configure -aЭта команда завершает настройку всех пакетов, которые были распакованы, но не настроены. Она выполняет скрипты сопровождения в порядке зависимостей. На системе с прерванным обновлением это может занять много времени, поэтому дождитесь завершения процесса. Если выполнение остановится на каком-либо пакете, apt выведет его имя и скрипт, который вызвал ошибку. Запишите это имя. Именно этот пакет остановил обновление, а в следующем разделе описано, как прочитать текст ошибки.
Затем позвольте apt исправить зависимости, которые остались неразрешенными из-за прерывания, так как некоторые пакеты были обновлены, а пакеты, от которых они зависят — нет.
sudo apt --fix-broken installПосле этого завершите обновление, которое было прервано:
sudo apt update
sudo apt full-upgradeИспользуйте full-upgrade, а не upgrade, так как обновление дистрибутива подразумевает удаление пакетов, а обычная команда upgrade запрещает удаление чего-либо. Прочитайте сводку, которую выводит apt, перед подтверждением. Небольшой список удаляемых пакетов — это нормально. Список, в который входят ubuntu-server, systemd, openssh-server или пакет ядра, является подозрительным: откажитесь от операции и выясните, почему apt хочет их удалить, прежде чем продолжать.
Проверьте результат, прежде чем выполнять другие действия:
sudo dpkg --audit
sudo apt-get checkКоманда dpkg --audit выводит список всех пакетов, находящихся в неисправном состоянии, а apt-get check сообщает о неразрешенных зависимостях. Обе команды не должны выводить ничего. Когда это условие будет выполнено, запустите sudo apt autoremove, чтобы удалить автоматически установленные зависимости, которые больше не нужны (пакеты, помеченные как установленные вручную, останутся, даже если их никто не использует), затем подтвердите выпуск с помощью cat /etc/os-release, выполните sudo update-initramfs -u -k all и sudo update-grub, и только после этого перезагружайтесь.
Как прочитать /var/log/dist-upgrade, чтобы найти пакет, остановивший обновление
Программа обновления записывает все действия в /var/log/dist-upgrade/. Если вы запускали её несколько раз, логи предыдущих попыток перемещаются в подкаталог с меткой времени, поэтому сначала проверьте ls -la /var/log/dist-upgrade/ и откройте каталог, соответствующий неудачному запуску.
main.log — это основной журнал работы программы обновления. В нем фиксируется текущая фаза и принятые решения относительно источников пакетов. Если программа обновления аварийно завершилась, здесь же будет указана трассировка стека Python. Читайте её с конца: последние строки указывают на фазу, на которой произошла остановка. Если там находится трассировка, значит, произошел сбой самой утилиты, а не пакета.
apt.log содержит логику работы механизма разрешения зависимостей. Этот файл очень подробный и важен, если apt отказался выполнять обновление в самом начале, еще до изменения каких-либо пакетов. Если обновление дошло до стадии установки пакетов, этот файл обычно можно пропустить.
apt-term.log — это файл, который нужен при сбое конкретного пакета. Он содержит вывод терминала dpkg во время обновления. Последний пакет, упомянутый перед окончанием файла, — это тот, который обрабатывался в момент остановки. Если произошла ошибка в скрипте сопровождения, сообщение dpkg об этом будет находиться прямо под текстом ошибки самого скрипта.
sudo tail -n 60 /var/log/dist-upgrade/apt-term.log
sudo grep -in 'error' /var/log/dist-upgrade/apt-term.log | tailСверьтесь с /var/log/dpkg.log, где фиксируются изменения статуса и действия dpkg с метками времени. tail -n 30 /var/log/dpkg.log показывает последний пакет, с которым работал dpkg, и выполненное действие. Это будет верным источником информации только в том случае, если после сбоя dpkg больше не запускался. Если вы уже запускали dpkg --configure -a или apt --fix-broken install, их записи будут последними, поэтому прокрутите файл до строк с меткой времени, соответствующей моменту остановки обновления.
Большинство сбоев на этой стадии на сервере вызваны несколькими причинами. Сервис, который пакет пытается перезапустить в postinst, не запускается из-за измененного вами файла конфигурации; команды systemctl status и journalctl -xeu для этого сервиса укажут на строку, которую он не может обработать. Заполнился диск (чаще всего /boot старыми ядрами или /var кэшем пакетов apt), что покажет df -h / /boot /var; sudo apt clean очищает кэш, даже если apt заблокирован, а диск, который сообщает о заполнении, хотя du показывает свободное место имеет свои причины. Пакет из стороннего репозитория, который программа обновления отключила, зависит от библиотеки, отсутствующей в 26.04. Удерживаемый пакет (apt-mark showhold) блокирует обновление зависимостей. Устраните причину и снова запустите sudo dpkg --configure -a. Процесс продолжится с места остановки.
Если пакет отказывается настраиваться, несмотря на все попытки, и от него не зависят важные компоненты, удалите его и переустановите после завершения обновления:
sudo dpkg --remove --force-remove-reinstreq package-name
sudo dpkg --configure -aИспользуйте этот метод только для пакета, который вы можете идентифицировать и объяснить, но никогда не применяйте его к библиотекам или компонентам из цепочки зависимостей ubuntu-server, так как принудительное удаление пропускает проверки, которые могли бы предупредить вас о других поломках.
Источники обновлены, но пакеты — нет
Программа обновления перезаписывает apt-источники на раннем этапе, до загрузки пакетов. Если процесс прервался после этого, в источниках указана версия 26.04, а установленные пакеты представляют собой смесь версий. Эта смесь сбивает инструменты с толку, поэтому do-release-upgrade может сообщать об отсутствии новых релизов.
Сравните два источника, определяющих текущий релиз. /etc/apt/sources.list.d/ubuntu.sources — это файл источников deb822, появившийся в 24.04, где строки Suites: содержат кодовое имя релиза. Файл /etc/os-release создается пакетом base-files и указывает, какой релиз фактически установлен.
grep -E '^(Suites|Components):' /etc/apt/sources.list.d/ubuntu.sources
grep -E '^(VERSION_ID|VERSION_CODENAME)=' /etc/os-release
apt-cache policy base-filesВажны три комбинации. В источниках указана 24.04 (кодовое имя noble), а в os-release — 24.04: обновление не прошло проверку, и вы можете запустить sudo do-release-upgrade снова, предварительно изучив main.log, чтобы понять причину остановки. Программа отказывается запускаться, если есть ожидающие обновления 24.04 или если в /var/run/reboot-required.pkgs указаны libc6, linux-base или пакет linux-image; в этом случае выполните sudo apt full-upgrade и перезагрузитесь, если файл этого требует. В источниках указано кодовое имя 26.04, а в os-release — 24.04: замена пакетов началась и была прервана; завершить её поможет процедура восстановления dpkg из предыдущего раздела, заканчивающаяся командой apt full-upgrade. Не запускайте программу обновления повторно в этом состоянии; при наличии пакетов 26.04 она остановится и потребует сначала установить все доступные обновления. В источниках указана 26.04, и в os-release — 26.04: base-files был одним из пакетов, которые успели обновиться, и система теперь считает себя версией 26.04, даже если большая часть пакетов осталась прежней.
Последняя комбинация — ловушка. do-release-upgrade определяет текущий релиз на основе данных из os-release. Если там уже указана 26.04, инструмент ищет что-то новее 26.04, ничего не находит и сообщает, что новых релизов нет. Инструмент отвечает на вопрос, основываясь на os-release, а os-release содержит неверные данные. Прекратите попытки использовать программу обновления и завершите процесс через apt: sudo apt update, затем sudo apt full-upgrade, что обновит пакеты, оставшиеся на версии 24.04 (за исключением удерживаемых, список которых можно получить через apt-mark showhold), и, возможно, удалит некоторые из них — внимательно изучите сводку, затем выполните sudo apt autoremove. Другие причины, по которым do-release-upgrade сообщает об отсутствии новых релизов, например, ожидание первого точечного релиза в LTS, стоит исключить, если в os-release всё ещё указана 24.04.
Программа обновления также отключает сторонние источники в /etc/apt/sources.list.d/ и сохраняет резервную копию каждого измененного файла, добавляя суффикс к исходному имени. Выполните ls -la /etc/apt/sources.list.d/ и diff для каждого исходного файла и его копии, чтобы увидеть внесенные изменения. Оставьте сторонние записи отключенными до тех пор, пока пакеты Ubuntu не придут в согласованное состояние, а затем включайте их по одному, убедившись, что поставщик выпустил пакеты для 26.04. Если apt update выдает ошибку о том, что источник настроен более одного раза, значит, старая запись sources.list и новая запись ubuntu.sources описывают один и тот же набор пакетов, и ошибка дублирования источника deb822 объясняет, какую из них нужно удалить.
Сервер не загружается после обновления
Перезагрузка — это момент, когда последствия незавершенного обновления становятся очевидны. Вероятные причины на VPS: ядро установлено без соответствующего initramfs, конфигурация GRUB не была пересоздана, пакет остался в полунастроенном состоянии, от которого зависит юнит автозагрузки, или диск переполнился во время записи данных процессом dpkg.
Прежде чем предпринимать какие-либо действия, откройте консоль провайдера. Она покажет, на каком этапе останавливается загрузка: меню GRUB, kernel panic, проверка файловой системы, ожидающая ввода, или emergency shell systemd, запрашивающий пароль root. Это наблюдение определяет дальнейшие шаги.
Если появилось меню GRUB, загрузитесь с предыдущим ядром 24.04 из подменю дополнительных параметров. Старое ядро обычно остается в системе до тех пор, пока не будет выполнен autoremove. Как только система загрузится на старом ядре, выполните sudo dpkg --configure -a и остальные действия по восстановлению из раздела выше, а затем sudo update-initramfs -u -k all и sudo update-grub, прежде чем снова пробовать новое ядро. В Восстановление VPS, который не загружается после обновления ядра подробно описаны аспекты работы с GRUB и initramfs.
Если вы попали в emergency shell, корневая файловая система обычно смонтирована в режиме только для чтения. Перемонтируйте её и выполните те же действия по восстановлению:
mount -o remount,rw /
dpkg --configure -aЕсли система вообще не доходит до командной строки, загрузитесь с rescue-образа вашего провайдера, смонтируйте диск VPS и выполните восстановление через chroot. Найдите корневой раздел с помощью lsblk, вместо того чтобы угадывать его имя.
lsblk
mount /dev/<root-partition> /mnt
for d in dev proc sys run; do mount --bind /$d /mnt/$d; done
chroot /mnt /bin/bash
dpkg --configure -a
apt --fix-broken install
update-initramfs -u -k all
update-grub
exit
rebootПрежде чем тратить час на работу в chroot, сопоставьте это время с использованием снимка (snapshot). Вы сделали его перед началом работ, а восстановление из него у большинства провайдеров занимает считанные минуты. После этого вы повторно запустите обновление, что на VPS занимает значительно меньше часа, и в этот раз вы будете заранее знать, какой пакет требует исправления. Восстановление из снимка — более быстрый путь, если верно хотя бы одно из следующих утверждений: вы не можете получить доступ к консоли или rescue-образу, вы не можете определить пакет, который остановил обновление, застряло более одного пакета или на сервере запущены сервисы, ожидаемые пользователями. Исправление вручную быстрее только в том случае, если вы точно знаете, что именно сломалось, и для починки достаточно одной команды.
Скопируйте /var/log/dist-upgrade/ с сервера перед восстановлением; если это единственный способ доступа, сделайте это из rescue-образа. Восстановление удалит эти логи, и вторая попытка завершится точно так же, если вы не выясните причину первой неудачи. Стоит прочитать Что может и чего не может восстановить snapshot, прежде чем полагаться на него. Снимок откатывает весь диск целиком, включая любые данные, записанные после его создания, что допустимо в процессе обновления, но неприемлемо спустя неделю.
Три признака того, что систему лучше переустановить
Некоторые обновления не стоят усилий по их спасению. Восстановление снимка и повторный запуск — это быстро, но если сбой вызван состоянием самой системы, вторая попытка также завершится неудачей. В таком случае честным решением будет развертывание свежего образа 26.04 с последующим восстановлением данных из резервной копии. Есть три признака, указывающих на то, что вы достигли этой точки.
Во-первых, повреждена база данных dpkg. Если dpkg --audit или apt-get check не могут прочитать /var/lib/dpkg/status, а не просто сообщают о поврежденных пакетах внутри, значит, запись об установленном ПО утрачена. Ubuntu хранит ежедневные копии в /var/backups/ (ls -la /var/backups/dpkg.status*), и иногда помогает замена поврежденного файла на самую свежую рабочую копию. Однако, как только эта копия перестает соответствовать реальному состоянию диска, вы начинаете действовать наугад, и каждый последующий запуск apt будет опираться на эти догадки.
Во-вторых, инструменты, необходимые для восстановления системы, сами вышли из строя. Когда apt или dpkg не запускаются из-за удаления или частичной замены общей библиотеки, или systemd не может запустить юниты, так как его собственный пакет настроен лишь частично, не остается работающего менеджера пакетов для исправления самого менеджера пакетов. ldd /usr/bin/apt позволяет проверить, все ли библиотеки apt на месте. Иногда можно выйти из этой ситуации через chroot в rescue-образе, но затраченное время обычно превышает время переустановки.
В-третьих, список поврежденных пакетов не сокращается. Если вы запускали dpkg --configure -a и apt --fix-broken install в цикле более часа, и каждая итерация выявляет новый проблемный пакет вместо исправления предыдущего, значит, система принесла в обновление проблемы, которые не были созданы самим процессом обновления: файлы в /usr, отредактированные вручную, зафиксированные (pinned) или удерживаемые (held) пакеты, сторонний репозиторий, заменивший системные библиотеки, или предыдущее обновление, которое так и не было завершено. Свежий образ лишен этих проблем, а восстановление данных на него занимает меньше времени, чем их поиск.
Переустановка оправдана только в том случае, если данные хранятся отдельно от сервера. В этом заключается разница между снимком (snapshot) и резервной копией (backup), и именно поэтому руководство по обновлению требует наличия обоих вариантов.
FAQ
Можно ли просто запустить do-release-upgrade снова, если процесс был прерван?
Не сразу. Если процесс обновления всё ещё активен в сессии screen, подключитесь к ней командой sudo screen -d -r; повторный запуск do-release-upgrade остановится, не дойдя до собственного кода переподключения, так как утилита не запускается, если есть пакеты, ожидающие обновления. Если процесс обновления завершился, сначала выполните sudo dpkg --configure -a и sudo apt --fix-broken install. Если в файле источников уже указана версия 26.04, завершите процесс с помощью sudo apt full-upgrade вместо использования утилиты обновления. Если там всё ещё указана 24.04, выполните sudo apt full-upgrade, перезагрузитесь, если /var/run/reboot-required.pkgs выводит libc6, linux-base или ядро, а затем снова запустите утилиту обновления. Она также выдаст отказ, если в /etc/update-manager/release-upgrades установлен параметр Prompt=never или если сервер Ubuntu сообщает: "Release upgrade not possible right now".
Почему do-release-upgrade говорит, что нет новых релизов после сбоя обновления?
Потому что base-files, пакет, который записывает данные в /etc/os-release, был одним из тех, что обновились до прерывания. Утилита теперь считывает этот файл, делает вывод, что вы уже используете 26.04, и не находит ничего более нового. Сравните grep VERSION_ID /etc/os-release с grep Suites /etc/apt/sources.list.d/ubuntu.sources, затем завершите обновление с помощью sudo apt update && sudo apt full-upgrade.
Безопасно ли перезагружать частично обновленный сервер Ubuntu?
Не делайте этого, пока sudo dpkg --audit не вернет пустой результат. Перезагрузка с распакованным, но не настроенным ядром или с непересозданным GRUB — самая частая причина, по которой обновление, которое можно было исправить за десять минут, превращается в задачу по восстановлению системы из образа. Завершите восстановление dpkg и apt full-upgrade, выполните update-initramfs -u -k all и update-grub, и только после этого перезагружайтесь.
Как найти пакет, который остановил обновление?
Прочитайте конец файла /var/log/dist-upgrade/apt-term.log, где хранятся данные вывода терминала dpkg. Последний пакет, упомянутый перед окончанием лога, — это тот, который обрабатывался в момент сбоя; ошибка скрипта сопровождения (maintainer script) обычно печатается прямо над сообщением об ошибке dpkg. /var/log/dpkg.log — второй источник информации: строки с отметками времени, когда обновление остановилось, указывают на тот же пакет, но любые действия, выполненные через dpkg позже, будут записаны после них, поэтому последние строки могут не содержать нужной информации. Если файл main.log заканчивается трассировкой Python (traceback), значит, произошел сбой самой утилиты обновления, и ни один пакет не является причиной ошибки.
Стоит ли восстанавливать снапшот или продолжать исправление?
Восстанавливайте снапшот, если вы не можете определить пакет, вызвавший сбой, если застряло более одного пакета, если у вас нет доступа к консоли или если сервер должен вернуться в строй как можно быстрее. Продолжайте исправление только в том случае, если вы точно знаете, что именно сломалось, и для исправления достаточно одной команды. Скопируйте /var/log/dist-upgrade/ с сервера перед восстановлением, иначе вторая попытка завершится с той же ошибкой.