距离4月21日 Ubuntu 22.04 正式发布越来越近,为了家里的各种 Ubuntu 设备能够安心升级,我决定提前体验接近完成的测试版。

本文提到的升级方式适用于 Desktop 桌面版和 Server 版。

升级前的准备

不论是 Desktop 桌面版,还是 Server 服务器版本的 Ubuntu,在升级前,我们都需要做几件事:

  1. 系统中的用户数据备份。
  2. 将系统中的软件包升级到最新,并根据实际需求情况,重启系统,让升级后的软件包生效。
  3. 解锁被 apt-mark 锁定的软件,允许软件在系统发行版升级的过程中升级为和新系统兼容的版本。
  4. 清理系统内核,留出足够多的空间,安装新的内核。
  5. 当然,因为现在新版系统还未正式发布,所以我们还需要解锁系统升级限制。

接下来,我们就来聊聊如何完成这些前置准备。

数据备份:打包和快速复制

数据备份的方式有很多种,不考虑商业软件、安装非系统自带软件的前提下,我推荐你使用 rsync 以及 tar 来完成快速的备份。

相比较使用各种压缩参数,直接使用 tar cf 可以将目录结构保持,并转化为一个单一文件,方便我们进行后续的文件备份和转移,而不必纠结目标分区的文件格式、权限归属等问题。而且,当我们的目录中有比较多的小文件的时候,这样做,可以极大提升备份数据的速度。

比如下面的命令,我们就会把目录中的文件打包为一个后缀为 tar 的文件,通常我们会叫这个过程为“打个tar包(tarball)”。

tar cf demo.soulteary.com.tar demo.soulteary.com

实际生产过程中,我们会有非常多类似下面的结构的目录。

board.black.com
board.data.black.com
cache.black.com
carbon.black.com
certs.black.com

如果我们希望将上面的目录分别打包为 tarball,一条一条命令执行显然比较麻烦,有没有偷懒的方式呢?显然是有的。

find . -maxdepth 1 -type d -name '*.*' | xargs -I {} tar cf {}.tar {}

相比较使用 ls,我们可能误打包一些内容 ,直接使用 find 可以限制我们要打包内容的类型为目录,目标名称的命名方式要满足 *.*

如果你的数据量非常少,当然也可以考虑放弃打包,直接进行数据拷贝操作。

相比较直接使用 scp 等命令,我更推荐使用 rsync,将我们的文件完整的从“出发地”快递到“目的地”,rsync 除了支持不同分区目录之间的数据备份外,也支持跨设备的完整内容复制:

# 本地跨分区/目录进行备份
rsync -rv --copy-links /data-need-backup /disk2/data-backup
# 将本地数据备份至其他设备
rsync -rv --copy-links /data-need-backup soulteary@10.11.12.13:/data-backup

如果你使用 Docker,你可以选择参考《提升 Docker Desktop For macOS 磁盘使用率》一文中提到的系统中的 Docker 镜像批量保存方案:

docker images | sed '1d' | grep -v '<none>' | awk '{print "docker save " $1 ":" $2 " -o " $3 ".tar"}' | bash

或者,你希望保存的 Docker 镜像文件名可读性更高一些,可以选择使用下面的脚本:

#!/bin/bash
IMAGES_LIST=($(docker  images   | sed  '1d' | awk  '{print $1}'))
IMAGES_NM_LIST=($(docker  images   | sed  '1d' | awk  '{print $1"-"$2}'| awk -F/ '{print $NF}'))
IMAGES_NUM=${#IMAGES_LIST[*]}

for((i=0;i<$IMAGES_NUM;i++))
do
  docker save "${IMAGES_LIST[$i]}"  -o "${IMAGES_NM_LIST[$i]}".tar.gz 
done

好啦,数据备份就聊到这里。

升级系统中的软件

为了升级到更新的系统版本,我们需要使用下面的命令,将系统中的软件包升级到当前系统最新的版本:

apt update && apt upgrade -y

如果我们已经将软件升级到新版,将会看到类似下面的日志:

Hit:1 http://cache.black.com/cn.archive.ubuntu.com/ubuntu focal InRelease
Hit:2 http://cache.black.com/cn.archive.ubuntu.com/ubuntu focal-updates InRelease
Hit:3 http://cache.black.com/cn.archive.ubuntu.com/ubuntu focal-backports InRelease
Hit:4 http://cache.black.com/cn.archive.ubuntu.com/ubuntu focal-security InRelease
Hit:5 http://cache.black.com/mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu focal InRelease
Reading package lists... Done
Building dependency tree       
Reading state information... Done
All packages are up to date.
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
  eatmydata libeatmydata1 libfwupdplugin1 python3-importlib-metadata python3-jinja2
  python3-json-pointer python3-jsonpatch python3-jsonschema python3-markupsafe
  python3-more-itertools python3-pyrsistent python3-zipp
Use 'apt autoremove' to remove them.

0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

如果你愿意的话,你可以使用 apt autoremove 来卸载系统中不再使用的软件。如果你现在懒得操作的话,问题也不大,因为在系统完成升级后,我们还需要清理一遍,所以可以稍后再做处理。

(系统升级过程中,也会询问我们是否要清理,所以大可不必进行额外操作。)

解锁被锁定的软件

有的时候,为了软件长时间运行稳定,我们不得已会锁定一些软件包,比如 docker 等。但是在系统升级的过程中,一般建议将这些软件包都“解锁”,避免升级到新系统之后,发生不兼容的问题。

apt-mark showhold

批量解锁我们锁定的软件很简单,只需要一条命令:

apt-mark showhold | xargs -I {} apt-mark unhold {}

命令执行完毕,你将能够看到类似下面的日志:

Canceled hold on docker-ce.
Canceled hold on software-name.
Canceled hold on software-name-2.
...

清理不再需要的内核

如果你有单独划分 /boot 分区的话,这里推荐你在升级之前针对启动分区进行清理,释放一些空间,让新内核能够顺利的进行安装。下面的内容在 《AMD 4750u 及 5800u 笔记本安装 Ubuntu 20.04》一文中曾提到过。

想要清理内核,我们首先要知道我们安装过哪些内核:

dpkg --get-selections | grep linux-image

在命令执行完毕后,我们将能够看到类似下面的结果:

linux-image-5.13.0-37-generic			install
linux-image-5.13.0-39-generic			install
linux-image-5.15.0-25-generic			install
linux-image-generic				install
linux-image-generic-hwe-22.04			install
linux-image-unsigned-5.11.10-051110-generic	install
linux-image-5.13.0-35-generic			deinstall

这里我们可以将系统标记为 deinstall 和我们不再需要的老版本的内核一律删除,只保留两到三个我们认为会使用到内核即可。

apt-get purge linux-image-5.13.0-37 linux-image-5.13.0-35

当完成内核清理之后,记得使用 update-grub 重新生成 Grub 系统启动内核列表:

update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-xxx-generic
Found initrd image: /boot/initrd.img-xxx-generic
...
done

解锁系统升级限制

因为目前正式版的 Ubuntu 22.04 还未 Release,所以我们只能通过变更 /etc/update-manager/release-upgrades 升级版本锁定,安装还处于开发通道的 Ubuntu 22.04。

你可以使用下面的命令,一键完成 LTS 系统的“升级解锁”。

sed -i -e "s/Prompt=lts/Prompt=normal/" /etc/update-manager/release-upgrades

当以上操作都完成之后,我们开始进行系统升级。

升级 Ubuntu 20.04

我这里使用的是分步升级,先将系统升级到接近 Ubuntu 22.04 的 Ubuntu 21.10 ,再进行 Ubuntu 22.04 版本的升级。

将 Ubuntu 20.04 系统升级到 Ubuntu 21.10

相比较上面的一系列,看起来比较繁琐的操作,升级系统的操作其实十分简单。只需要执行 do-release-upgrade,就可以开启通往新版本的升级之路啦。

过程中,如果出现提示,可以一律使用下面的方式来解决:

  • 在命令行中输入 yyes 或者敲击回车确认
  • 在弹出的命令行 GUI 对话框中直接敲击回车,保持默认选项

当一切就绪之后,命令行中会提示我们升级完毕,要不要重启:

System upgrade is complete.

Restart required 

To finish the upgrade, a restart is required. 
If you select 'y' the system will be restarted. 

Continue [yN] y

这个时候,继续输入 y,让系统进行重启,第一阶段的系统升级就完毕啦。

将 Ubuntu 21.10 升级为 Ubuntu 22.04

再次登录系统后,会看到系统提示已经从 Ubuntu 20.04 变成了 Ubuntu 21.10:

Welcome to Ubuntu 21.10 (GNU/Linux 5.13.0-39-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

接下来我们来继续聊聊,如何升级 Ubuntu 22.04。

这里有一个小技巧,对于未完全开通 IPv6 的网络,强烈建议在升级之前,先禁用内核的 IPv6 功能,以防在升级过程中无法获取 Ubuntu 22.04 版本的软件包,导致升级过程死循环:

Failed to fetch 
http://cn.archive.ubuntu.com/ubuntu/pool/universe/f/fuse/libfuse2_2.9.9-5ubuntu3_amd64.deb 
Connection failed [IP: 91.189.91.38 80] 

Restoring original system state

Aborting
Reading package lists... Done    
Building dependency tree... Done 
Reading state information... Done
=== Command detached from window (Sun Apr 10 05:41:24 2022) ===
=== Command terminated with exit status 1 (Sun Apr 10 05:41:34 2022) ===

如果你的网络不支持 IPv6 ,而你恰好进入了系统升级过程,也不必害怕,在升级没有开始之前按下 x ,退出升级即可。

禁用 IPv6 功能,其实十分简单,只需要修改 /etc/default/grub 文件,在 GRUB_CMDLINE_LINUX_DEFAULT 中添加 ipv6.disable=1 即可。

举个例子,系统中原始的文件内容类似下面:

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="maybe-ubiquity"
GRUB_CMDLINE_LINUX=""

我们只需要在原始配置中加入 ipv6.disable=1 即可:

GRUB_CMDLINE_LINUX_DEFAULT="maybe-ubiquity ipv6.disable=1"

在完成文件内容修改之后,执行 update-grub && reboot 重新生成配置,并重启系统让配置生效。另外,因为海外服务器不是特别稳定,如果不是在云服务器执行升级,可以考虑使用清华源替换默认的 cn.archive.ubuntu.com 等软件源。

因为当前时间点 Ubuntu 22.04 还未正式发布,所以我们需要在升级命令后添加 -d 来安装还处于开发通道的系统。

do-release-upgrade -d

和上面升级系统一样,一路选择 yok,不一会系统升级就完成啦,再次登陆系统,可以看到我们已经处于 Ubuntu 22.04 环境下了:

Welcome to Ubuntu Jammy Jellyfish (development branch) (GNU/Linux 5.15.0-25-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

最后

在 Ubuntu 22.04 中,因为内核被默认升级到了 5.15,针对 AMD 处理器(包括 amdgpu)的支持好了不少,推荐使用 AMD Ryzen R5/R7 的小伙伴进行升级体验。

前一阵比较忙,2月份开始到现在又堆积了不少文章和草稿,希望在这个月,能够把堆积的内容挨着发布出来吧。

–EOF