1. 问题现象与初步判断
先说结论:Ubuntu 19.04 的sudo apt-get upgrade提示失败,绝大多数情况不是你的操作问题,而是这个版本本身已经走到了生命周期的尽头。19.04 属于短期支持版本(代号 Disco Dingo),官方只维护 9 个月,到 2020 年 1 月就停止维护了。一旦停止维护,软件源里的仓库会被官方移除或迁移到旧版本归档服务器,这时候你执行apt-get update或者apt-get upgrade,自然就会遇到各种 404、仓库无法解析、依赖冲突的报错。
我在实际排查这类问题时发现,很多人第一步就被报错信息带偏了。看到404 Not Found就以为是网络问题,看到Unable to correct problems就认为是依赖损坏,其实根源往往只有一个:源失效。所以这篇文章会把整个排查过程、原理、解决方案从头到尾捋一遍,尤其是针对 19.04 这种已经停止维护的系统,到底应该怎么处理才最稳妥。
2. 错误日志逐行拆解
先看一个典型的报错场景,执行sudo apt-get update && sudo apt-get upgrade后,终端会输出类似这样的内容:
Hit:1 http://archive.ubuntu.com/ubuntu disco InRelease Err:2 http://security.ubuntu.com/ubuntu disco-security InRelease 404 Not Found [IP: 91.189.88.152 80] Reading package lists... Done W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/disco-security/InRelease 404 Not Found E: Some index files failed to download. They have been ignored, or old ones used instead.接着执行 upgrade 时:
Reading package lists... Done Building dependency tree... Done Reading state information... Done Calculating upgrade... Done E: Unable to correct problems, you have held broken packages.这两段日志看起来像是两个问题,其实是同一个根源。第一段告诉你源仓库地址已经失效,第二段告诉你因为包索引不完整,依赖关系无法正确解析。很多人看到you have held broken packages就开始折腾dpkg --configure -a、apt --fix-broken install,这些命令在正常情况下确实能解决依赖问题,但在源已经404的情况下,apt 根本拿不到正确的包列表,修复自然无从谈起。
2.1 为什么 19.04 的源会失效
Ubuntu 的版本分为两种:长期支持版(LTS)和短期支持版(普通版本)。19.04 属于短期支持版,官方维护周期只有 9 个月。维护期结束后:
- 主仓库
archive.ubuntu.com里的disco目录会被移除 - 安全仓库
security.ubuntu.com里的disco-security目录会被移除 - 所有指向这些目录的源地址都会变成 404
有一个很关键的点容易被忽略:即使你用的是国内镜像源,比如阿里云、清华源,镜像站为了保持和官方一致,也会同步移除这些失效目录。所以如果你换了国内源还是一样报错,不用怀疑是镜像源的问题,这是版本生命周期决定的。
2.2 如何确认系统版本和源配置
排查第一步,先确认自己是不是真的在用 19.04:
lsb_release -a输出:
No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 19.04 Release: 19.04 Codename: disco然后查看源配置文件:
cat /etc/apt/sources.list以及:
ls /etc/apt/sources.list.d/很多情况下,源配置可能不止一个文件,sources.list.d目录下还可能有第三方仓库的.list文件,这些文件同样需要检查。
3. 解决方案一:切换到旧版本归档源
如果你的诉求是让这台 19.04 系统继续能安装软件、更新包,最直接的方案是切换到 Ubuntu 官方提供的旧版本归档服务器。这个服务器的域名是old-releases.ubuntu.com,专门存放已经停止维护的版本。
3.1 备份原有源配置
动手改之前,先把原始配置备份一下。这不是走形式,而是方便你随时回滚:
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak如果sources.list.d目录下有第三方源文件,也一并备份:
sudo cp -r /etc/apt/sources.list.d /etc/apt/sources.list.d.bak3.2 编辑源列表文件
用你习惯的编辑器打开:
sudo vim /etc/apt/sources.list将文件中所有archive.ubuntu.com和security.ubuntu.com替换为old-releases.ubuntu.com。如果你之前改过国内镜像源,比如mirrors.aliyun.com,也需要一并替换成old-releases.ubuntu.com。
替换后的完整源列表大致长这样:
deb http://old-releases.ubuntu.com/ubuntu/ disco main restricted universe multiverse deb http://old-releases.ubuntu.com/ubuntu/ disco-updates main restricted universe multiverse deb http://old-releases.ubuntu.com/ubuntu/ disco-security main restricted universe multiverse这里有一个细节值得注意:旧版本归档服务器上,disco主仓库和disco-updates、disco-security这几个路径都是存在的,但disco-backports和disco-proposed不一定完整。所以源列表里我建议只保留主仓库、updates、security 这三类,不要贪多。
3.3 更新索引并升级
执行:
sudo apt-get update正常情况下应该能正常拉取索引了。然后再执行:
sudo apt-get upgrade如果一切顺利,系统会列出可升级的软件包。这里我要提醒一句:一个已经停止维护的系统,跨了这么长时间后再升级,涉及的包数量可能非常多,而且部分软件的新版本依赖的是更新版本的系统库,升级过程中有可能会遇到新的依赖冲突。
3.4 实际操作中的注意点
切换到旧归档源之后,还有几个坑需要提前预防:
第一,apt-get update过程中如果出现Hash Sum mismatch错误,不要慌,通常是因为镜像缓存不一致,执行sudo apt-get clean然后重新 update 即可。
第二,如果升级过程中提示某个包需要先卸载才能升级,不要盲目执行apt remove。先看清楚这个包的依赖关系,确认不会影响系统关键组件再动手。
第三,旧归档源的速度一般,如果你在海外或者网络环境一般,下载速度可能会比较慢。这种情况下可以尝试用apt-get的-o Acquire::http::Dl-Max-Speed参数限制下载速度,避免长时间占用带宽。
4. 解决方案二:升级到仍受支持的系统版本
如果你不需要一直停留在 19.04,更推荐直接升级到仍然受支持的版本。这里说的升级,不是指apt upgrade这种包级别升级,而是指do-release-upgrade这种版本级别升级。
4.1 为什么推荐升级而不是一直修修补补
19.04 停止维护意味着:不再有安全更新,不再有 bug 修复,新的软件包不会进入官方源。即使你切换到旧归档源能正常安装软件,也只是修好了“能装包”的问题,“安全性”这个核心问题依然没有解决。长期把一台机器跑在停止维护的系统上,一旦暴露在公网,漏洞风险会随时间推移越来越大。
如果你这台机器只是本地开发用的,不暴露公网,那切换到旧归档源继续用一段时间是可以接受的。但如果它是服务器、生产环境,或者需要访问公网,我的建议很明确:尽早升级。
4.2 通过 do-release-upgrade 升级的正确姿势
19.04 之后的下一个版本是 19.10(Eoan),19.10 也已经停止维护了,所以直接从 19.04 升级到 19.10 意义不大。更合理的路径是跨版本升级到 20.04 LTS。
直接执行:
sudo do-release-upgrade大概率会提示没有找到新版本,因为 19.04 到 20.04 需要先升级到 19.10,再升级到 20.04,逐级走。而且 19.04 生命周期结束后,官方升级通道可能已经关闭,需要加-d参数或者手动修改配置来强制执行。
我踩过的坑是:停维护版本直接跨版本升级,中途很容易因为源失效、依赖冲突、第三方源不兼容而中断。升级失败后系统可能处于半升级状态,这时候反而更麻烦。所以如果你决定升级,优先考虑方案 4.3 的备份重装。
4.3 备份重装,最稳妥的路线
如果说旧归档源是“续命”,那么备份重装就是“重生”。我个人的实践体会是:对于已经停止维护的系统,与其费劲升级,不如把重要数据备份出来,然后全新安装 20.04 LTS 或 22.04 LTS。
步骤很清晰:
- 备份
/home目录下的个人文件 - 备份
/etc下的关键配置(比如 nginx 配置、ssh 配置、数据库配置) - 用
dpkg --get-selections导出已安装软件列表 - 全新安装新系统
- 用
dpkg --set-selections配合apt-get dselect-upgrade恢复软件安装清单
软件列表恢复的命令:
dpkg --get-selections > /tmp/package-list.txt装好新系统后:
dpkg --set-selections < /tmp/package-list.txt sudo apt-get dselect-upgrade这个方法能做到“软件清单完整还原”,但不建议无脑全量恢复,因为有些旧版本的软件在新系统上可能已经有更新的替代版本,全量恢复反而会引入版本冲突。建议只恢复自己真正需要的应用软件,系统自带的基础组件让它用新系统的默认版本。
5. 常见问题与排查技巧实录
5.1 换源后仍然提示 404
这种情况最典型的原因是两个:一是sources.list里虽然改了主域名,但sources.list.d目录下还残留着第三方源文件;二是源列表里混进了disco-backports或disco-proposed这类归档源上没有的目录。
排查方式:
sudo grep -r "disco" /etc/apt/sources.list /etc/apt/sources.list.d/把输出里所有包含disco的源地址都看一下,凡是域名不是old-releases.ubuntu.com的,全部替换或注释掉,然后把backports和proposed相关的行注释掉。
5.2 执行 upgrade 时提示无法锁定 dpkg
如果你开了多个终端,或者之前有 apt 进程异常退出,可能会遇到:
E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)这不算疑难杂症,执行:
sudo rm /var/lib/dpkg/lock-frontend sudo rm /var/lib/dpkg/lock sudo rm /var/cache/apt/archives/lock然后重新执行sudo apt-get update && sudo apt-get upgrade。
需要注意的是:删除锁文件之前,先用ps aux | grep apt和ps aux | grep dpkg确认没有正在运行的 apt/dpkg 进程。如果确实有进程在跑,等它结束,或者用sudo kill结束掉。直接删锁文件虽然多数情况下没事,但不检查进程就删,有可能破坏正在进行的安装事务。
5.3 提示“you have held broken packages”怎么处理
这是 apt 最经典也最让人头疼的报错之一。在 19.04 的场景下,根源绝大多数是源失效导致包索引不完整,而不是真的“包被 hold 了”。所以处理顺序应该是:
- 先确认源配置是否正确(参考第 3 节)
- 确认是否能正常
apt-get update - 再尝试
sudo apt --fix-broken install - 如果还不行,查看具体是哪个包冲突,用
apt-cache policy 包名查看候选版本
举一个实际遇到的例子:某次升级过程中,系统提示libssl1.1和openssl版本冲突。我检查后发现,是因为旧归档源里这两个包的版本号更新顺序不一致,导致 apt 无法解析出满足所有依赖的版本组合。处理方法是手动指定版本安装:
sudo apt-get install libssl1.1=1.1.1-1ubuntu2.1然后再执行sudo apt-get upgrade,问题就解决了。
5.4 第三方软件源导致的依赖混乱
19.04 年代比较流行的一些第三方源,比如某些 PPA(Personal Package Archive),在系统停止维护后会变得非常尴尬——它们的软件包是为 19.04 构建的,但维护者可能早就停止更新了。这些 PPA 在apt-get update阶段通常会报 404,虽然不影响系统核心功能,但会干扰你的判断。
处理方式:在sources.list.d目录下找到对应的.list文件,用#注释掉,或者直接删除。然后重新执行sudo apt-get update,确认没有任何Err输出后,再继续 upgrade。
如果某个 PPA 里的软件你确实还需要,可以到 Launchpad 上查看该 PPA 是否提供了其他 Ubuntu 版本的构建包,如果有,手动下载.deb文件用dpkg -i安装即可。
6. 快速排查清单
为了方便后续遇到类似问题时能快速定位,我把整个排查路径整理成一张速查表。
| 现象 | 原因 | 处理方案 |
|---|---|---|
apt-get update出现 404 | 软件源指向已移除的仓库 | 切换为old-releases.ubuntu.com归档源 |
apt-get upgrade提示 held broken packages | 包索引不完整,依赖解析失败 | 先修复源,再apt --fix-broken install |
apt-get update出现 Hash Sum mismatch | 镜像缓存不一致 | sudo apt-get clean后重新 update |
| 无法获取 /var/lib/dpkg/lock | apt/dpkg 进程残留或异常退出 | 确认无 apt 进程后删除锁文件 |
| 有第三方源持续报错 | PPA 停止维护,仓库已失效 | 注释或删除对应.list文件 |
| 更新后软件版本过旧 | 归档源不再提供新版本 | 备份数据后全新安装新版本系统 |
这张表覆盖了 90% 以上的常见场景。如果你按照这个路径走完,还是没能解决问题,那大概率是某个特定软件包自身的依赖关系太复杂,这时候就需要针对具体报错信息逐条排查了。
7. 一些兜底建议
最后分享几点我在实际维护旧系统过程中的个人体会。
不要因为系统还能开机就觉得“没啥问题”。一个停止维护的系统,表面上看能正常运行,但背后的安全隐患和软件生态断供是真实存在的。如果你只是临时用一下,切换到旧归档源完全够用;如果是长期使用,真的建议花半天时间做一次备份重装。
在操作 apt 之前养成看日志的习惯。/var/log/apt/目录下会有history.log和term.log,里面记录了每次 apt 操作的详细输出。遇到问题时先翻日志,往往比在网上搜报错信息更高效。
还有一个小技巧:修改源文件后,先用sudo apt-get update验证,不要直接就去执行upgrade。update 成功是 upgrade 的前提,如果 update 阶段就有错误报出来,先解决掉再说。很多人图快,update 看到几个 WARNING 就跳过,结果 upgrade 阶段出问题又回头来查源,白白浪费时间。
如果你手头也是 19.04 或者其他已经停止维护的 Ubuntu 版本,希望这篇文章能帮你少走一些弯路。按着第 3 节的步骤切换归档源,或者按第 4 节的思路规划升级路径,基本都能把问题解决掉。