SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-09-14

Ubuntu 24.04 升级 26.04 失败如何恢复

升级中途断开不一定已失败:本文说明如何重新连接 screen,会话中修复 dpkg,处理已切换一半的软件源,并判断何时应恢复快照。

Ubuntu 升级中途失败:先判断症状

从 Ubuntu 24.04 升级到 26.04 失败后,服务器会处于四种状态之一,每种状态的修复方法都不同。升级程序可能仍在您失去连接的 screen 会话中运行。dpkg 可能在某个软件包完成配置前被终止,因此 apt 现在拒绝执行任何命令。apt 软件源可能已经指向 26.04,但已安装的软件包仍属于 24.04。服务器也可能完全无法启动。在执行任何操作前,先确认属于哪种状态,因为针对一种状态的修复操作可能使另一种状态更加严重。

以下规则适用于全部四种状态。在确认 dpkg 的状态前,不要重启。软件包替换过程中重启,可能会把本可修复的 dpkg 中断变成本指南末尾所述的无法启动状态。如果第一个 apt 或 dpkg 进程可能仍在运行,也不要启动第二个进程,因为两个进程同时写入软件包数据库会导致数据库损坏。

本指南假设您已按照24.04 到 26.04 的升级指南操作,并在开始前创建了快照。如果没有创建快照,请结合这一点阅读启动部分,因为快照是处理最严重情况的解决方案。

升级是否仍在运行?

许多报告为失败的升级实际上仍在运行。SSH 会话断开,终端变为空白,但升级程序仍在后台继续执行。

do-release-upgrade 正是为此设计的。它以文本界面运行时(服务器使用的就是这种方式),会将自身置于 GNU screen 会话中,因此即使启动升级的终端断开,升级也能继续运行。另外,如果它检测到自己是从 SSH 会话启动的,还会询问是否在另一个端口上启动第二个 sshd(默认端口为 1022)。这样,如果软件包替换期间主 SSH daemon 出现故障,您仍可登录。现在这两点都很重要。

通过 SSH 重新连接,然后查找 screen 会话。升级程序在 sudo 下运行,因此它的 screen 会话属于 root;使用您自己的用户直接运行 screen -ls 不会列出该会话。

sudo screen -ls

screen -ls 会标记每个会话当前是已连接还是已分离。如果列出了会话,请重新连接到该会话。如果由于已断开的 SSH 连接尚未释放会话,该会话仍标记为已连接,则 -d 会先分离这个失效连接。

sudo screen -d -r

如果列出了多个会话,请将 screen -ls 中的会话名称放在 -r 后面。再次运行 sudo do-release-upgrade 也可以:升级程序会检查自己已有的 screen 会话,并重新连接,而不是启动新的升级。无论采用哪种方式,您都会回到正在运行的升级过程。它通常正停在询问是否处理已更改配置文件或重启服务的提示处。回答提示并让升级完成。

如果您按照升级指南的建议,在 tmux 中启动了升级,请先使用 tmux attach 重新连接 tmux。screen 会话运行在该 tmux 窗格内,因此您会直接看到升级过程。如果窗格中只有 shell 提示符,说明升级程序已不再在那里运行,下一步应检查 sudo screen -ls

如果主 SSH 端口拒绝连接,请尝试备用端口:ssh -p 1022 user@host。该 daemon 只在升级期间存在。因此,如果两个端口都无法连接,请改用服务提供商的控制台。在控制台中,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/status 中。之后的每条 apt 命令都会读取该状态并停止,因为 apt 不会在包含未完成操作的数据库上继续执行。无论 apt 拒绝运行时显示什么提示,第一步都相同。

sudo dpkg --configure -a

此命令会为所有已解压但尚未配置的软件包完成配置。它会按依赖顺序运行维护者脚本。在升级进行到一半的系统上,这可能需要很长时间,因此请等待命令返回,不要中途干预。如果命令在某个软件包处停止,它会打印软件包名称和失败的脚本。记下该名称。它就是导致升级停止的软件包,下一节将说明如何读取其错误信息。

然后让 apt 修复中断留下的未满足依赖,因为部分软件包已经升级,但它们依赖的软件包尚未升级。

sudo apt --fix-broken install

然后完成升级程序正在执行的升级:

sudo apt update
sudo apt full-upgrade

使用 full-upgrade,不要使用 upgrade,因为发行版升级会删除软件包,而普通的 upgrade 拒绝删除任何软件包。确认前先阅读 apt 打印的摘要。删除少量软件包通常正常。如果列表中要删除 ubuntu-serversystemdopenssh-server 或内核软件包,则不正常。此时应回答否,并先查明 apt 要删除它们的原因。

继续执行前,先检查结果:

sudo dpkg --audit
sudo apt-get check

dpkg --audit 会列出所有仍处于损坏状态的软件包,apt-get check 会报告未满足的依赖。两条命令都应不输出任何内容。确认无输出后,运行 sudo apt autoremove,删除不再被任何软件包依赖的 24.04 软件包;然后使用 cat /etc/os-release 确认发行版版本,再运行 sudo update-initramfs -u -k allsudo 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 最后处理的软件包,以及当时正在执行的操作;这与前面的判断结果相互印证。

在服务器上,这一阶段的大多数失败都来自以下几种原因。软件包在 postinst 阶段重启某个服务,但该服务因你修改过的配置文件而无法启动;对该服务运行 systemctl statusjournalctl -xeu,即可看到它不接受的配置行。磁盘已满,最常见的是 /boot 被旧内核占满,或 /var 被 apt 的软件包缓存占满;df -h / /boot /var 可以显示这一情况。即使 apt 已经卡住,sudo apt clean 仍可清空缓存;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 是 24.04 引入的 deb822 源文件,其中的 Suites: 行包含发行版代号。/etc/os-releasebase-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

需要关注以下3种组合。源仍指向24.04(代号为 noble),且 os-release 仍显示24.04:升级尚未通过检查。阅读 main.log 了解停止原因后,可以再次运行 sudo do-release-upgrade。源指向26.04代号,但 os-release 仍显示24.04:软件包替换已经开始,但被中断了。上一节介绍的 dpkg 修复流程,以 apt full-upgrade 结束,是完成升级的方法。源指向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版本的软件包升级,最后运行 sudo apt autoremove。如果 os-release 仍显示24.04,还应排除do-release-upgrade 报告没有新版本的其他原因,例如 LTS 提示会等待第一个点版本发布。

升级程序还会禁用 /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 菜单、内核崩溃、等待回答的文件系统检查,或要求输入 root 密码的 systemd emergency shell。这个判断决定下一步操作。

如果出现 GRUB,请从高级选项子菜单启动之前的 24.04 内核。旧内核通常会一直保留,直到 autoremove 运行。使用旧内核启动系统后,执行 sudo dpkg --configure -a,并按照上一节完成其余修复;然后执行 sudo update-initramfs -u -k allsudo update-grub,再重新尝试启动新内核。修复内核更新后无法启动的 VPS详细介绍了 GRUB 和 initramfs 相关操作。

如果进入 emergency shell,root 文件系统通常以只读方式挂载。重新挂载后执行相同的修复操作:

mount -o remount,rw /
dpkg --configure -a

如果系统完全无法进入 shell,请启动服务商的救援镜像,挂载 VPS 磁盘,然后从 chroot 中修复。使用 lsblk 查找 root 分区,不要凭猜测确定分区名称。

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 中耗费一小时之前,先将其与快照恢复进行比较。你在开始操作前已经创建了快照,而大多数服务商只需几分钟即可完成恢复。之后重新运行升级;在 VPS 上通常不到一小时。这次你已经知道需要提前修复哪个软件包。满足以下任一条件时,恢复快照通常更快:无法访问控制台或救援镜像、无法确定导致升级停止的软件包、有多个软件包卡在未完成状态,或者服务器上运行着有人正在等待使用的服务。只有在你明确知道发生故障的唯一原因,并且修复只需执行一条命令时,手动修补才更快。

恢复前,将 /var/log/dist-upgrade/ 从服务器复制出来;如果只能通过救援镜像访问服务器,就从救援镜像中复制。恢复操作会删除这些日志。如果你没有找出第一次失败的原因,第二次尝试会完全重复同样的失败。依赖快照前,值得阅读快照可以恢复和无法恢复的内容。快照会将整个磁盘回滚,包括创建快照后写入的所有数据。升级过程中这样做通常没有问题,但一周后再这样做就可能造成数据丢失。

应改为重建系统的三个迹象

有些升级不值得继续修复。恢复快照并重新执行升级的成本很低,但如果故障源于系统本身的状态,第二次执行也会失败。此时,正确的做法是使用全新的 26.04 镜像,再从备份恢复数据。出现以下三个迹象时,就说明应当这样处理。

第一,dpkg 自身的数据库已损坏。如果 dpkg --auditapt-get check 完全无法读取 /var/lib/dpkg/status,而不是报告其中存在损坏的软件包,那么已安装软件包的记录就丢失了。Ubuntu 会在 /var/backups/ls -la /var/backups/dpkg.status*)下保存每日副本,将最新的可用副本替换到原位置有时可以解决问题。但如果该副本与磁盘上的实际状态不一致,后续操作就只能依靠猜测,而每次 apt 执行都会继续建立在这个猜测之上。

第二,修复系统所需的工具本身已损坏。如果 aptdpkg 因共享库被删除或部分替换而无法启动,或者 systemd 因自身的软件包处于半配置状态而无法启动单元,那么系统中就没有可用的软件包管理器来修复软件包管理器了。ldd /usr/bin/apt 可用于确认 apt 所需的库是否全部存在。有时可以从救援镜像中的 chroot 环境启动修复,但这通常比重建系统耗时更长。

第三,损坏软件包的列表没有减少。如果您循环运行 dpkg --configure -aapt --fix-broken install 超过一小时,而每次执行都会发现新的软件包,却无法清除上一次发现的问题,说明系统在升级前就已带有升级过程未造成的问题:/usr 下的文件曾被手动修改,软件包被固定或锁定,第三方软件源替换了核心库,或者之前的升级本身从未完成。全新的镜像不存在这些问题,将数据恢复到新系统所需的时间少于逐一查找这些问题。

只有当数据存储在系统之外时,重建才真正省时。这就是快照与备份的区别,也是升级指南要求同时准备二者的原因。

FAQ

我可以在 do-release-upgrade 中断后直接再次运行它吗?

可以,这是首选操作。如果升级程序仍在其 screen 会话中运行,再次运行该命令会重新连接到该会话。如果升级程序已退出,请先运行 sudo dpkg --configure -asudo apt --fix-broken install,然后再次启动升级程序。它会重新读取当前状态并继续升级。唯一无法这样处理的情况是 /etc/os-release 已经显示 26.04,因为升级程序会认为升级已完成;此时应改为运行 sudo apt full-upgrade 完成后续操作。

为什么升级失败后,do-release-upgrade 会提示没有新版本?

因为 base-files(负责写入 /etc/os-release 的软件包)在中断前已经完成升级。该工具现在读取该文件,判断系统已运行 26.04,因此找不到可提供的新版本。请比较 grep VERSION_ID /etc/os-releasegrep Suites /etc/apt/sources.list.d/ubuntu.sources,然后运行 sudo apt update && sudo apt full-upgrade 完成后续操作。

Ubuntu 服务器完成部分升级后重启是否安全?

sudo dpkg --audit 返回空结果前都不安全。如果内核已解包但尚未配置,或者 GRUB 尚未重新生成,此时重启很可能会使原本 10 分钟即可修复的升级问题变成需要使用救援镜像处理的问题。请完成 dpkg 修复和 apt full-upgrade,运行 update-initramfs -u -k allupdate-grub,然后再重启。

如何找出导致升级停止的软件包?

查看 /var/log/dist-upgrade/apt-term.log 的末尾,其中包含 dpkg 的终端输出。日志结束前最后出现的软件包就是当时正在处理的软件包;如果维护脚本失败,其错误信息通常会显示在 dpkg 报错的正上方。tail -n 30 /var/log/dpkg.log 可以从第二个来源确认这一点。如果 main.log 以 Python traceback 结尾,则表示升级程序本身崩溃,没有软件包导致该问题。

我应该恢复快照,还是继续修复?

以下情况应恢复快照:无法确定失败的软件包;有多个软件包卡住;没有控制台访问权限;或者服务器必须尽快恢复。只有在明确知道唯一故障点,且修复只需运行一条命令时,才应继续修复。恢复前请将 /var/log/dist-upgrade/ 复制到服务器外部,否则第二次尝试仍会以相同方式失败。