Ubuntu 20.04 升级到 24.04 实战详细教程/记录
距离 Ubuntu 20.04 LTS 发布已经过了快四年,这台服务器从 2020 年装好系统一直跑到现在,中间经历了内核小版本更新、Docker 迁移、Python 环境重构,但系统版本始终没动过。直到最近需要装一个新工具链,对方明确要求 glibc 版本必须高于 2.35,而 20.04 自带的 glibc 2.31 直接卡死了安装条件。20.04 还在维护期内,但 24.04 的 LTS 生命周期到 2029 年,早晚得升,不如趁业务低峰期一次到位。这篇记录就是我在真实服务器上从 Ubuntu 20.04 跨版本升级到 24.04 的完整过程,包括升级前的检查、源切换、系统更新、版本跃迁、内核切换、驱动和软件环境修复、以及升级后的验证和回滚预案,全部基于实际执行过的命令和输出整理,给同样要跨大版本升级的朋友一个可参考的操作路径。
先说结论:Ubuntu 官方支持的跨版本升级路径是 20.04 → 22.04 → 24.04,不推荐直接从 20.04 跳到 24.04。虽然 do-release-upgrade 默认只允许逐级升级,但很多人会尝试修改配置强制跨两个大版本,这种做法风险极大。我这次就是老老实实走了两段式升级,每一段都单独验证、单独备份,虽然多花了一些时间,但整体非常平稳,业务中断时间控制在 20 分钟以内。
1. 为什么要选择两段式升级而不是直接跨版本
1.1 官方升级机制的限制
Ubuntu 的 do-release-upgrade 工具默认配置里有一行关键参数:
bash复制# /etc/update-manager/release-upgrades
Prompt=lts
当 Prompt=lts 时,系统只允许从 LTS 升级到下一个 LTS,也就是说 20.04 → 22.04 → 24.04 是官方支持的唯一路径。如果你尝试直接修改为 Prompt=normal 然后跳到 24.04,工具会报错或者干脆拒绝执行。
更深层的原因是:Ubuntu 的包管理器(APT)在跨版本升级时,依赖解析器要走一遍完整的包依赖图。两个大版本的跨度意味着 glibc、libssl、Python、Perl 这些底层组件全部要换新,依赖关系变化太大,APT 很难保证不出冲突。我在测试环境里试过一次直接跨版本,升级到一半就卡在 libc6 的配置脚本上,那个包一旦处于半配置状态,整个系统的 apt 就不能用了,恢复起来非常麻烦。
1.2 两段式升级的实际耗时和风险对比
| 升级路径 | 预估耗时 | 主要风险 | 官方支持 |
|---|---|---|---|
| 20.04 → 22.04 | 30~60 分钟 | 内核切换、驱动兼容 | 支持 |
| 22.04 → 24.04 | 40~70 分钟 | Python 环境、snap 版本 | 支持 |
| 20.04 → 24.04 直接跳 | 无法预计 | 依赖解析崩溃、系统无法启动 | 不支持 |
我这次两段式升级总共用了大约 1 小时 40 分钟,包括中间的业务验证时间。相比测试环境里直接跨版本折腾了四个小时还以失败告终的惨痛经历,这个时间成本是非常划算的。
1.3 什么样的机器适合在线升级
不是所有 Ubuntu 20.04 机器都适合走在线升级,以下几个条件至少要满足三条以上才建议尝试:
- 数据有完整备份(至少数据库做过 dump,或者有快照)
- 系统盘剩余空间在 10GB 以上
- 服务器不是唯一的生产节点(至少能接受 30 分钟以上的中断)
- 业务依赖的第三方软件在当前版本下没有强制的 glibc 版本要求(或者说升级后能接受重新适配)
我这次操作的机器是一台跑内部服务的管理节点,不直接对外提供服务,数据量不大,所以在线升级的容错空间足够大。如果你的机器是核心数据库节点,强烈建议先做虚拟机克隆或者云厂商快照,在任何情况下都不要跳过备份这一步。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 升级前的完整状态检查与备份
2.1 系统信息收集
在动手之前,先把系统当前状态完整记录下来。这一步是为了后面升级过程中出现异常时,能快速对比哪些东西变了、哪些东西没变。
bash复制# 当前系统版本
lsb_release -a
# 内核版本
uname -r
# 已安装的第三方内核模块
dpkg -l | grep -E "linux-modules|linux-image|linux-header"
# 重要软件版本
docker --version
python3 --version
nginx -v
mysql --version
# 系统架构
dpkg --print-architecture
这是我升级前记录的机器状态:
code复制Distributor ID: Ubuntu
Description: Ubuntu 20.04.6 LTS
Release: 20.04
Codename: focal
内核: 5.4.0-167-generic
Docker: 24.0.7
Python: 3.8.10
Nginx: 1.18.0
2.2 查看是否有第三方源和 PPA
第三方软件源是跨版本升级最容易踩坑的地方。因为每个 Ubuntu 版本的软件源都有对应的代号(20.04 叫 focal,22.04 叫 jammy,24.04 叫 noble),如果你加了 PPA,升级到一个新版本后这个 PPA 可能还没有适配新版,APT 就会因为找不到包而中断升级。
检查所有源文件:
bash复制grep -rh "^deb" /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null
常见的需要处理的第三方源包括:
- Docker 官方源:支持所有 Ubuntu 版本,但需要在升级后手动确认版本是否匹配
- NVIDIA GPU 驱动源:升级后必须重新安装驱动,否则会黑屏或者无法启动图形界面
- NodeSource(Node.js 源):必须手动更新,因为不同 Ubuntu 版本的发行代号不同
- 各种 PPA:例如
ppa:deadsnakes/ppa(Python 多版本源),升级前最好逐个检查
我这次机器上加了 Docker 官方源和 ppa:deadsnakes/ppa,其中 deadsnakes 在 jammy 和 noble 都有对应版本,所以问题不大。如果你的第三方源没有适配 22.04 或 24.04,建议在升级前先注释掉,等升级完成后再重新配置。
2.3 备份策略
这里说的备份不是简单的复制文件,而是要有明确的恢复路径。我给自己定了一个"三条备份"原则:
- 系统配置备份:
/etc目录整体打包,这是系统恢复的关键,所有网络配置、服务配置、用户权限都在里面 - 业务数据备份:数据库 dump + 关键目录打包
- 软件包列表备份:记录当前安装的所有包,方便回滚时恢复
bash复制# 备份软件包列表
dpkg --get-selections > /root/backup/dpkg-selections.txt
# 备份 apt 源配置
cp -r /etc/apt /root/backup/apt-backup
# 备份系统配置目录(排除运行时文件)
tar -czf /root/backup/etc-backup.tar.gz \
--exclude='/etc/ssl/private' \
/etc
# 备份 Docker 容器和镜像列表
docker ps -a > /root/backup/docker-containers.txt
docker images > /root/backup/docker-images.txt
# 数据库备份(如果有 MySQL)
mysqldump -u root -p --all-databases > /root/backup/all-databases.sql
提示:备份文件不要放在系统盘上。如果升级过程中文件系统被破坏,放在同一个分区里的备份也一起完蛋。我习惯把备份放到另一块数据盘或者直接通过 scp 传到其他机器。
2.4 检查磁盘空间
跨版本升级需要足够的磁盘空间来下载新软件包和临时文件。20.04 → 22.04 大约需要 6~8GB,22.04 → 24.04 需要多一些,通常 8~12GB。加上原有的系统占用,建议至少保证 20GB 可用空间。
bash复制df -h /
如果空间不够,可以清理一下:
bash复制# 清理 apt 缓存
apt clean
# 清理旧内核(保留当前正在运行的内核)
apt autoremove --purge
# 清理 journal 日志
journalctl --vacuum-time=7d
# 清理孤儿包
apt purge $(dpkg -l | awk '/^rc/ {print $2}')
2.5 重要服务状态记录
升级过程中系统会自动重启,所有服务都会中断。升级前建议记录服务的启动方式和运行状态,方便升级完成后核对:
bash复制systemctl list-units --type=service --state=running
# 记录开机自启动项
systemctl list-unit-files | grep enabled
升级后部分服务可能因为配置格式变化或者依赖包版本变化而启动失败,对比升级前的记录能快速定位问题。这次升级过程中 Nginx 就遇到了 worker 进程无法绑定的问题,后面会详细说排查过程。
3. 第一段升级:从 20.04 到 22.04
3.1 升级前最后一次系统更新
在开始跨版本升级前,一定要先把当前系统的所有软件包更新到最新状态。这样做的原因有两个:一是很多问题在旧版本软件包上才存在,更新后能规避部分升级事故;二是 do-release-upgrade 会要求系统包管理器处于干净状态,如果本地有未安装的依赖或者 broken 状态,升级工具会直接拒绝执行。
bash复制apt update
apt full-upgrade -y
apt autoremove --purge -y
apt clean
full-upgrade 和 upgrade 的区别要说明一下:upgrade 只会升级已安装的包,不会处理新出现的依赖关系;full-upgrade 会智能处理依赖变化,可能会安装新包或删除旧包。跨版本升级前用 full-upgrade 更合适。
全量更新后需要重启一次,确保当前运行的内核是最新的,同时让所有服务都在新版本软件包状态下运行:
bash复制reboot
3.2 执行升级命令
do-release-upgrade 是 Ubuntu 官方的版本升级工具,底层调用的是 update-manager-core 里的逻辑。在执行前先检查一下这个工具本身是否需要更新:
bash复制apt install update-manager-core -y
然后开始升级:
bash复制do-release-upgrade
这个命令会:
- 检查当前系统版本和可升级的目标版本
- 下载升级所需的元数据
- 提示你确认是否开始升级
- 关闭可能干扰升级的服务(如 NetworkManager、snapd)
- 更新软件源列表
- 下载所有新软件包
- 解包并配置
执行过程中会弹出几个交互式对话框,几乎都是"是否保留现有配置文件"之类的选择。我的建议是:
- 对于被修改过的配置文件,选择保留现有版本(通常默认就是 N),因为旧配置大概率在目标版本里还是兼容的
- 对于新增的配置文件,选择使用新版本
- 对于服务重启确认,选择 Yes
还有一个对话框询问你是否要删除无用的软件包,这里可以选择 Yes,因为很多旧包在新版本里已经不被依赖了,留着反而容易造成依赖混乱。
升级过程结束后,系统会提示重启。此刻不要犹豫,直接重启。
3.3 升级到 22.04 后的验证清单
重启完成后,第一步是确认系统版本和内核:
bash复制lsb_release -a
uname -r
正常情况下你应该看到:
code复制Distributor ID: Ubuntu
Description: Ubuntu 22.04.4 LTS
Release: 22.04
Codename: jammy
内核版本应该是 5.15.x。
接下来检查几类关键内容:
bash复制# 网络是否正常
ip addr
ping -c 4 8.8.8.8
# DNS 解析是否正常
getent hosts github.com
# 包管理器是否正常
apt update
apt -f install -y
# 服务是否都起来了
systemctl --failed
ss -lntp
这一步很重要:如果在 22.04 阶段服务就不正常,一定要先解决掉再继续升级 24.04,不要带着故障继续往上升级,否则问题会被放大。我当时在 22.04 阶段就发现 Nginx 的配置还兼容,但有个 PHP-FPM 版本从 7.4 升到了 8.1,部分旧代码报了一堆 deprecation 警告,算是提前暴露了问题。
4. 升级前驱动与第三方软件的兼容性处理
4.1 NVIDIA 驱动的处理(如果适用)
如果你的机器装了 NVIDIA 显卡驱动,跨版本升级前必须先处理驱动,否则升级后大概率会遇到驱动模块编译失败、内核模块不加载、图形界面无法启动等问题。
升级前需要做的步骤:
bash复制# 确认当前驱动版本
nvidia-smi
# 记录驱动版本号
# 例如:Driver Version: 535.129.03
# 卸载现有驱动
apt purge nvidia-* -y
apt autoremove -y
卸载后在升级到 22.04/24.04 后重新安装适配新系统的驱动版本:
bash复制# 推荐使用官方提供的驱动安装方式
ubuntu-drivers devices
apt install nvidia-driver-545 # 根据实际推荐的版本
注意:不同内核版本的 NVIDIA 驱动模块需要重新编译,如果你升级内核后没有重新安装驱动,
nvidia-smi会报Unable to determine the device handle,此时只能重装。所以最简单的做法就是升级前清理干净,升级后再按新系统重新安装。
4.2 Docker 的兼容性处理
Docker 本身在 Ubuntu 大版本升级后通常不会有太大问题,但要注意两点:
- 容器镜像和容器配置:升级系统不会影响现有的容器和镜像,因为数据都在
/var/lib/docker下,不会被动到 - Docker 服务在升级过程中的行为:
do-release-upgrade会自动停止 Docker 服务,升级完成重启后会重新启动
如果你用的是 Docker 官方源安装的 Docker Engine(通过 apt install docker-ce),升级过程可能会遇到 docker-ce 包在目标版本没有对应版本的情况。这时候你需要手动修改源配置中的版本代号:
bash复制# /etc/apt/sources.list.d/docker.list
# 将 focal 改为 jammy(对应 22.04)或 noble(对应 24.04)
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable
修改后执行 apt update && apt install docker-ce -y 就能继续使用 Docker。如果升级过程中 Docker 源不匹配导致 apt update 报错,最简单的临时处理是先把 Docker 源注释掉,等系统升级完成后再重新配置。
4.3 Python 环境和虚拟环境
Ubuntu 20.04 默认 Python 是 3.8,22.04 是 3.10,24.04 是 3.12。如果你系统里有直接依赖系统 Python 的脚本或服务,升级后必须测试一遍。
我这次升级前机器上装了不少 Python 脚本,还有一些第三方库。处理方式是这样的:
bash复制# 升级前将当前 Python 包列表导出来
pip3 list --format=freeze > /root/backup/pip-packages.txt
# 升级完成后在新 Python 版本下重新安装(仅针对必需的包)
pip3 install -r /root/backup/pip-packages.txt
注意:跨版本升级不会卸载旧 Python 版本,Ubuntu 的替代机制(update-alternatives)会把你 python3 的默认版本切到新版,但系统里可能还留着旧版本。有些软件依赖旧版本 Python 反而更稳定,不用强求全部迁移。
4.4 搜狗输入法等桌面环境相关组件
升级前在桌面环境遇到搜狗输入法无法输入中文的问题,很多用户都有类似的经历。原因通常是搜狗输入法依赖的 fcitx 框架在 Ubuntu 22.04/24.04 上默认变成了 fcitx5,而搜狗输入法目前主要支持 fcitx4。
处理方法:
bash复制# 查看当前输入法框架
im-config -m
# 卸载已有的搜狗输入法
dpkg -l | grep sogou
dpkg -P sogoupinyin
# 如果要继续使用搜狗输入法,先安装 fcitx 框架
apt install fcitx -y
# 然后从官网下载适配新系统的 deb 包重新安装
# 下载后执行
sudo dpkg -i sogoupinyin_*.deb
sudo apt -f install -y
升级后桌面环境如果出现无法输入中文、输入法候选框不显示等问题,优先检查环境变量 GTK_IM_MODULE 和 QT_IM_MODULE 是否指向了你当前使用的输入法框架。
5. 第二段升级:从 22.04 到 24.04
5.1 再次执行升级前的检查
在 22.04 稳定运行一段时间后,就可以着手第二段升级了。步骤和第一段几乎一样,但有几个额外的检查项:
bash复制# 查看当前内核版本
uname -r
# 期望看到 5.15.x
# 检查是否有遗留的未清理包
dpkg -l | grep ^rc
# 检查是否有 held 状态的包
apt-mark showhold
# 检查是否有 EOL(停止维护)的组件
ubuntu-support-status
如果没有特殊需求,不要手动 hold 任何软件包,否则升级过程中 APT 依赖解析可能失败。
5.2 从 22.04 到 24.04 的升级执行
跟第一段一样的操作:
bash复制apt update
apt full-upgrade -y
reboot
apt install update-manager-core -y
do-release-upgrade
升级到 24.04 时,遇到了一个小坑值得在这里记录一下:升级过程中出现了两个需要交互确认的配置界面。
一个是对 sshd_config 的询问:系统升级后 OpenSSH 的默认配置有所变化,需要确认是否保留现有配置。这个选择"保留现有"即可,除非你明确知道新配置对你的服务器是必要的。
另一个是新版 systemd 的配置询问,同样选择保留现有。
5.3 24.04 升级完成后的状态验证
升级完成后重点验证以下内容:
bash复制# 系统版本
lsb_release -a
# 期望看到 24.04.1 LTS, noble
# 内核版本
uname -r
# 期望看到 6.8.x
# 包管理器状态
apt update
apt -f install -y
# 服务状态
systemctl --failed
# 网络状态
ip addr
ping -c 4 223.5.5.5
# 关键服务检查
systemctl status sshd
systemctl status docker
# 端口监听状态
ss -lntp | grep -E "80|443|3306"
我在这次验证中遇到的第一件事是:Nginx 服务的 worker process failed to bind() address already in use。因为系统升级后 Nginx 的 socket 文件路径没变,但旧的 Nginx master 进程在升级前的重启中没有被完全关闭,导致新启动的 Nginx 进程无法绑定端口。
处理方法:
bash复制# 查看 Nginx 进程
ps aux | grep nginx
# 杀掉残留的 master 进程
kill -QUIT <master_pid>
systemctl start nginx
systemctl status nginx
这个问题的根因是升级脚本在切换 systemd 服务时,旧进程的退出信号没有正确传递到服务管理器的进程组里,属于升级中的偶发状态。如果你也遇到类似情况,不要急着重装服务,先排查进程和 socket 占用。
5.4 内核版本切换策略
升级到 24.04 后,系统默认会使用新内核 6.8.x,但旧内核(5.15.x 和 5.4.x)仍然会保留在系统里,方便回滚。
查看系统当前可用内核:
bash复制dpkg -l | grep linux-image
如果你想强制指定某个内核启动,可以修改:
bash复制# 查看当前默认内核
grep GRUB_DEFAULT /etc/default/grub
# 如果要保持旧内核启动(不推荐,除非有兼容性问题)
# 修改 /etc/default/grub 里的 GRUB_DEFAULT 为旧内核的菜单项
# 然后执行 update-grub
一般来说不需要手动设置,让 GRUB 默认使用最新内核即可。只有在新内核下驱动或服务出现问题时,才需要回退到旧内核排查。
6. 升级过程中遇到的常见问题和完整的排查链路
6.1 do-release-upgrade 提示没有新版本可用
这是一个很常见的问题,很多人升级前检查系统版本和源后,执行 do-release-upgrade 会得到 "No new release found"。
排查步骤:
bash复制# 确认 /etc/update-manager/release-upgrades 的配置
cat /etc/update-manager/release-upgrades
# Prompt 的值必须是 lts 或 normal 至少之一
# 检查源文件是否正常
apt update
# 尝试手动指定目标版本
do-release-upgrade -d
如果你的系统是在 20.04 发布后很久才装的,UCF(Ubuntu Configuration Framework)可能在初始化时把版本信息写错了。可以尝试:
bash复制sudo update-manager -c
如果还是不行,检查 /var/lib/ubuntu-release-upgrader/release-upgrade-available 文件,清空它后重试。
6.2 apt 依赖解析失败:需要安装无法安全安装的软件包
升级过程中最常见的报错是:
code复制E: Unable to correct problems, you have held broken packages.
或
code复制Could not calculate the upgrade
这是升级中最麻烦的一类问题。排查思路:
bash复制# 查看具体的 broken 包
sudo apt policy <包名>
# 查看依赖关系
sudo apt-cache depends <包名>
# 检查是否是因为版本号冲突
sudo apt-cache policy libc6
常见的处理手段包括:
- 手动卸载冲突的第三方包(前提是你知道它影响什么)
- 检查
/etc/apt/preferences.d/下是否有自定义的 apt 优先级 - 删除
/var/lib/dpkg/status中可疑的残留记录(这个操作风险很高,不推荐新手做)
我当时遇到的报错是因为一个旧内核模块没有被清理干净,导致新内核包在解包时冲突。解决方式是手动把旧内核相关的第三方模块包全部 apt purge 掉,再重新执行升级。
6.3 ssh 连接在升级过程中断开
do-release-upgrade 在升级过程中会重启网络服务和 OpenSSH 服务。如果你使用 SSH 远程连接,升级过程中连接会断掉。虽然有时升级脚本会自动重启 SSH 服务,但网络状态不稳定时很容易卡住。
解决方案有两个:
- 在执行升级前,先用
screen或tmux开启一个持久会话,然后在里面执行do-release-upgrade。这样即使 SSH 连接断了,升级进程也能继续在后台运行,重新连接后可以恢复会话查看进度。
bash复制apt install tmux -y
tmux new -s upgrade
do-release-upgrade
断开后重连:
bash复制tmux attach -t upgrade
- 在升级前确保服务器有带外管理(如 IPMI、iDRAC)或者物理访问权限,万一升级过程卡死在某个交互对话框,还可以直接接到服务器上处理。
6.4 升级后网络无法使用
升级完成后如果网络不可用,最常见的原因是网络管理服务冲突。
在 Ubuntu 24.04 上,netplan 和 NetworkManager 的交互逻辑和 20.04 有所变化。
bash复制# 检查网络服务状态
systemctl status systemd-networkd
systemctl status NetworkManager
# 查看 netplan 配置
cat /etc/netplan/*.yaml
# 尝试重启网络服务
systemctl restart systemd-networkd
我遇到过一种情况:升级后 DHCP 分配不到地址,原因是 /etc/netplan/ 下的配置文件里的 renderer 字段从 networkd 变成了 NetworkManager,导致 systemd-networkd 没有接管接口。把 renderer 改回 networkd 并 netplan apply 后就恢复了。
6.5 升级后图形界面黑屏
如果你升级的是桌面版 Ubuntu,升级后可能会黑屏或者停留在登录界面不停循环。原因通常是显卡驱动在升级过程中被移除或者卸载了。
排查和修复:
bash复制# 在 GRUB 菜单中选择 Advanced options for Ubuntu
# 进入 recovery mode
# 在 recovery 菜单中选择 root shell
# 重新安装显卡驱动
ubuntu-drivers devices
apt install nvidia-driver-545 # 或者其他推荐的驱动
reboot
如果驱动没有异常,可能是显示管理器(GDM)的问题:
bash复制systemctl status gdm3
journalctl -u gdm3 -b
这种情况下重启 GDM 或者重新安装 gdm3 包通常能解决:
bash复制apt reinstall gdm3 -y
systemctl enable gdm3
reboot
6.6 升级后部分服务启动失败
服务启动失败的排查一般遵循这个链路:
bash复制# 1. 查看服务状态
systemctl status <service-name>
# 2. 查看完整日志(journal 里的日志按时间倒序)
journalctl -u <service-name> -n 100 --no-pager
# 3. 检查依赖的服务
systemctl list-dependencies <service-name>
# 4. 尝试手动启动并观察错误
systemctl start <service-name>
这次升级后我发现一个普通用户服务启动失败,原因是新版 systemd 在服务文件的 User= 字段上有更严格的检查,不允许指定 root 用户(除非显式声明)。解决方法是在 /etc/systemd/system/ 下覆盖对应服务文件,添加 User=root 并 systemctl daemon-reload。
6.7 系统时间漂移问题
升级后偶尔会出现时间不对的情况,通常是 chrony 或 systemd-timesyncd 在处理旧配置时出了偏差。检查方法:
bash复制timedatectl status
# 确认 NTP synchronized: yes
如果不是同步状态:
bash复制systemctl restart systemd-timesyncd
timedatectl set-ntp true
6.8 旧的 Python 虚拟环境失效
升级前创建的 Python venv 是绑定到旧的 Python 版本路径的,比如 /usr/bin/python3.8,升级后系统默认 Python 变成 3.12,这些 venv 里的 pip 和包会指向不存在的解释器。
处理方式很简单:
bash复制# 查看 venv 里的解释器
ls -la <venv>/bin/python*
# 删除后重建
rm -rf <venv>
python3 -m venv <venv>
# 或者保留旧 Python 版本的情况下重新创建 venv
/usr/bin/python3.10 -m venv <venv>
建议在升级前把 Python 项目用的依赖版本都记录好,升级后统一重建虚拟环境并安装所需包。
7. 升级完成后的收尾工作与系统精调
7.1 清理不再使用的旧内核和旧包
升级完成后系统里可能残留多个版本的内核和大量不再需要的旧包,清理这些内容能释放不少磁盘空间,也让系统的后续维护更清爽。
bash复制# 查看当前已安装内核
dpkg -l | grep linux-image
# 删除旧内核(找到版本号较旧的条目,逐个删除)
apt purge linux-image-5.4.0-xxx linux-image-5.15.0-xxx
# 清理无用的依赖
apt autoremove --purge -y
# 清理所有已下载的包缓存
apt clean
注意:删除旧内核前至少要保留当前正在运行的内核,否则一旦新内核出错,系统可能无法启动。我习惯保留最近两个版本的内核作为应急备用。
7.2 更新 GRUB 配置
内核变更后需要重新生成 GRUB 引导配置:
bash复制update-grub
确认 GRUB 里能识别到最新内核,并且旧的恢复内核条目也在。
7.3 检查 snap 包的状态
Ubuntu 24.04 上 snap 的使用更广泛了。升级后检查一下 snap 包的状态:
bash复制snap list
snap refresh
如果快照包版本过旧或者结构不兼容,可能需要卸载重新安装。这里涉及安全说明中提到的内容比较敏感,我只提示一点:如果 snap 包在升级后无法正常工作,通常只能通过 snap remove 后重新安装来解决。
7.4 配置文件合并检查
升级过程中 UCF(Ubuntu Configuration Framework)会生成一些 .ucf-old 或 .ucf-new 文件,你需要检查这些文件,确认哪些配置需要手动合并:
bash复制# 找到系统中的 ucft 文件
find /etc -name "*.ucf-*" -type f
# 常见的重要配置逐一确认
# /etc/ssh/sshd_config
# /etc/default/grub
# /etc/nginx/nginx.conf
如果某个服务升级后行为异常,先看它的 .ucf-old 文件,里面可能保留了旧版本的行为配置。
7.5 网络服务和防火墙规则校验
升级后防火墙规则(UFW 或 iptables)通常不会自动改变,但有些网络相关服务(如 Docker 创建的 iptables 链)可能因为服务启动顺序问题而出现异常。
bash复制# 查看 ufw 状态
ufw status
# 查看当前 iptables 规则
iptables -L -n -v
# 检查 Docker 的 iptables 链是否需要重建
systemctl restart docker
7.6 更新系统到最新补丁
升级到新版本后,系统通常不是最新的维护版本(比如 24.04.0),需要先更新到最新的维护版本:
bash复制apt update
apt full-upgrade -y
reboot
我这次升级完成后系统从 24.04.0 自动更新到了 24.04.1,内核也从 6.8.0-31 更新到了 6.8.0-45。注意如果升级过程中系统提示需要重启,务必立即重启而不是继续干活。
7.7 监控系统日志
升级后的头几天里,建议每天检查一次系统日志,避免隐患积累:
bash复制# 检查系统错误日志
journalctl -p err -b
# 查看系统启动耗时
systemd-analyze
# 查看关键服务的启动耗时
systemd-analyze blame | head -20
# 查看磁盘使用情况
df -h
我在升级后第三天发现有一个 cron 任务在报错,原因是 cron 里用的 Python 脚本路径指向了旧 Python 版本,而这个版本的 Python 可以被删除了。调整了 cron 脚本的 shebang 后问题解决。
7.8 业务验证
系统层面的收尾做完后,不要忘记重新跑一遍业务功能测试。我的验证清单包括:
- 内部 Web 服务能否正常访问
- 数据库连接是否正常
- 定时任务是否按预期执行
- 备份脚本能否正常跑通
- 日志采集和监控是否恢复数据上报
- Docker 容器能否正常启动和访问
如果某个测试项失败,按照之前的方法排查,不要侥幸认为升级完成就万事大吉。
8. 升级后的总结和给后续使用者的几点实操建议
这次从 Ubuntu 20.04 升级到 24.04 的整个流程走完,踩了一些坑,也学到不少东西。整理几个对后来人有实用价值的建议:
第一,两段式升级并不是浪费时间。 看起来好像做了两次升级,比直接跳版本多花很多时间,但每段升级的依赖变化范围更小,甚至升级过程中的错误提示都更容易定位。我在测试环境里尝试直接跳版本时遇到的那些问题,在两段式升级中几乎没有出现过。
第二,升级前做一次磁盘快照或者整机备份,心理压力会小很多。 即使升级失败,也有后悔药可以吃,你可以在备份基础上恢复系统,不会带来灾难性后果。我是因为机器上数据量不大,所以只是做了备份目录和数据库 dump,如果你的机器是生产环境,强烈建议使用云平台快照或虚拟机克隆。
第三,第三方源的处理顺序很重要。 在升级前就要把不兼容的 PPA 源注释掉,否则升级过程中 apt update 就会报错。我对第三方源的策略是:升级前全部禁用,升级完成后逐个恢复。这样虽然多了一些手动配置工作量,但能确保升级过程的 APT 状态始终干净。
第四,升级过程中如果遇到交互式对话框,不要盲目选"是"或"否"。 认真读一下每一个对话框的内容,尤其是关于配置文件替换的那几个,一旦选错,可能就要手动修复配置,比重新处理还要麻烦。
第五,升级后先别急着删除旧内核。 新内核跑一周没出问题再清理不迟,旧内核是你在新内核出问题时的应急方案。我的测试环境里,新内核在某一版 .0 版本上有过 KVM 虚拟化性能异常的情况,回退到旧内核后系统立刻恢复正常,这为我排查问题争取了很多时间。
第六,升级过程会默认关闭一些不重要服务,升级完成后需要手动确认它们是否应该恢复自启动。 我在升级后才发现某个内部监控代理被系统升级脚本停掉了,导致监控数据缺失了几天,别看这些小事,升级后巡检时往往就是这些不起眼的组件最容易出问题。
Ubuntu 20.04 升级到 24.04 这件事本身并不复杂,复杂的是你机器上运行的各种服务和依赖它们的软件。把升级前准备做足、升级中保持耐心、升级后认真巡检,这套流程基本可以覆盖绝大多数跨版本升级场景。希望这篇记录能帮到你。
