EndeavourOS的一次硬盘迁移
因为硬盘有点坏了而且不够用了需要系统迁移,虽然我有自己的常用或者不常用的软件配置,但是从头开始配置真的是一件非常费劲的事情。并不是说有多麻烦,只是很费时间,况且还有很多系统库。所以直接迁移。但是保险起见,先使用虚拟机进行一遍操作。因为我之前就是在虚拟机里面装了一个和我外面宿主机一样的操作系统(EndeavourOS based on Arch) 用于提前更新,看会有哪些奇怪的问题(比如6.6版本内核因为虚拟机启动而卡死[没错,我在虚拟机里面还安装了虚拟机就是为了更好模拟一下我的实际宿主机环境]),没问题的话,再在宿主机上更新。这次刚好拿来做迁移的模拟。当然硬盘满了还有别的选择,比如使用RAID做磁盘阵列,主要是我是笔记本,虽然我有挺多硬盘但是我得带着走太麻烦。另一个方案是使用LVM做管理,这个我之前也有实践经历,因为上次k8s的worker需要扩容,我就给虚拟机多加了块硬盘,用lvm做了扩容,比较简单几行命令而已。但是我自己的笔记本我没有额外的接口了(我另一个硬盘装了Windows,得打游戏的,不能糟蹋😅),我不想每次带着电脑还得吊着个硬盘,所以只能进行迁移了。
VM准备ing
Disk
首先我先添加一个nvme协议的虚拟硬盘用于待会迁移。

待会为了让系统启动进入我的u盘(准备好了启动盘,方便迁移)。还需要添加一个硬盘,只不过需要加载的是物理磁盘。这里来说就是我插进去的U盘。当然根据不同的Linux发行版,细节操作可能不同。但是大差不差。因为现在很多Linux发行版都会在U盘插进来之后自动挂载。这会导致我的Vmware检测不到U盘,所以我的第一步就是要简单的umount一下,然后再在Vmware内添加(这里说一句Windows下的话貌似不用这么麻烦,但是Windows下我不用Vmware, 诶~,我用Hyper-V)。
# 找到u盘对应在/dev下的设备名
sudo fdisk -l

然后找到挂载点将其卸载。
# 找到挂载点
mount | grep /dev/sdb | awk '{print $3}' | xargs sudo umount
好了,现在再到vmware内使用这个u盘

最后启动的时候在对应的虚拟机右键打开菜单,Power -> Power on to Firmware 进入BIOS. 并且在BIOS内选择对应的u盘启动盘。因为我是安装了ventoy的U盘,所以我随便选一个进入就是了。

BIOS里面我选了最后一个,主要不是因为位置而是之前我在添加的时候物理设备的标号是(0:0),所以这里直接选了。还有就是我随便选了一个发行版。这里是Pop_OS!。不得不说Pop_OS!是我用过的比较舒服的发行版。之前用了大概快一年了。基于ubuntu,哪天养老了说不定会切换回去。好了废话不多说了,这里我就进入了启动盘了。

先安装一个tweaks,把右上角的最大化按钮搞出来😁。之后fdisk -l就能看到之前添加的nvme的80g硬盘和撞了系统分好区的硬盘了。
磁盘操作
先用fdisk把磁盘分区。
sudo fdisk /dev/nvme0n1
# 里面的命令忘记了可以用m来显示。
Command(m for help): g(创建gpt)
Command(m for help): n (创建分区)
# 然后设置一下大小...
下面是我小分了三个区,和之前老的分区形成对照。后面我重新安装一个系统用于和我自己的分区形成一个一比一的对照。这样对于我自己实际迁移更具有说服力。(其实最后还是要改)

# 查看一下刚刚保存(w)的情况
sudo fdisk -l | grep nvme
因为我之前用的文件系统是btrfs,所以这里也将磁盘格式化为btrfs。
sudo mkfs.btrfs /dev/nvme0n1p1 # / 以及 /home
sudo mkfs.vfat -F32 /dev/nvme0n1p3 # /boot/efi
sudo mkswap /dev/nvme0n1p2 # swap
文件同步
磁盘部分搞完,接下来就是同步文件过去了。文件迁移我直接用rsync。当然也可以用其他的软件,有很多比如clonezilla,redo,gparted,或者直接复制磁盘块的dd命令等等。主要是我不想用gui的程序以及我想试试rsync,并且rsync也支持增量同步,所以这里就直接使用rsync了。
先将格式化好的分区挂在到一个目录下,并且挂载好旧的文件系统
sudo mkdir -pv /mnt/{new_root,old_root,old_cache,new_cache,old_log,new_log} # 待会儿再用
# 挂载之前系统的根目录,-o 设置btrfs子卷
sudo mount -o subvol=@ /dev/sda3 /mnt/old_root
sudo mount -o subvol=@cache /dev/sda3 /mnt/old_cache
sudo mount -o subvol=@log /dev/sda3 /mnt/old_log
sudo mount /dev/sda4 /mnt/old_root/home # 挂载旧的/home
sudo mount /dev/sda2 /mnt/old_root/boot/efi # 挂载旧的efi目录
下面是我之前旧系统的fstab文件(举个例子)
UUID=C6C6-9153 /boot/efi vfat defaults,noatime 0 2
UUID=121bc654-4bf6-4e8a-908e-4a8c1901d52e / btrfs subvol=/@,defaults,noatime,compress=zstd 0 0
UUID=121bc654-4bf6-4e8a-908e-4a8c1901d52e /var/cache btrfs subvol=/@cache,defaults,noatime,compress=zstd 0 0
UUID=121bc654-4bf6-4e8a-908e-4a8c1901d52e /var/log btrfs subvol=/@log,defaults,noatime,compress=zstd 0 0
UUID=a419a3c2-fe21-4fad-bdd9-27663a86e283 /home btrfs defaults,noatime,compress=zstd 0 0
UUID=0770979f-a88a-4a85-954f-d0b038394d2f swap swap defaults 0 0
所以相比于其他文件系统需要处理好子卷问题。
继续挂载新磁盘的根分区到/mnt/new_root ,并且创建好子卷。创建好子卷之后重新挂载
sudo mount /dev/nvme0n1p2 /mnt/new_root
# 创建子卷,这里名字@是根据之前的fstab来的
sudo btrfs subvolume create /mnt/new_root/@
sudo btrfs subvolume create /mnt/new_root/@cache
sudo btrfs subvolume create /mnt/new_root/@log
# 卸载new_root并使用子卷重新挂载
sudo umount /mnt/new_root
sudo mount -o subvol=@ /dev/nvme0n1p2 /mnt/new_root
sudo mount -o subvol=@cache /dev/nvme0n1p2 /mnt/new_cache
sudo mount -o subvol=@log /dev/nvme0n1p2 /mnt/new_log
# 将/home 以及 /boot/efi进行挂载
sudo mkdir -pv /mnt/new_root/{home,boot/efi}
sudo mount /dev/nvme0n1p3 /mnt/new_root/home
sudo mount /dev/nvme0n1p1 /mnt/new_root/boot/efi
然后使用rsync来同步数据,简单写个脚本来处理。另外对于内部的efi以及home分区也需要进行同步。
#!/bin/bash
src_dir="$1"
dest_dir="$2"
sudo rsync --archive --one-file-system \
--inplace --hard-links --human-readable \
--numeric-ids --delete --acls --xattrs \
--sparse --itemize-changes --verbose --progress \
$src_dir $dest_dir
# /mnt/old_root/ /mnt/new_root/
# /mnt/old_root/home/ /mnt/new_root/home/
# /mnt/old_root/boot/efi/ /mnt/new_root/boot/efi/
因为目前我是在live usb的popos上,我也没挂载(待会再挂载)/dev,/proc,/sys等包含系统信息的目录,所以这里就不使用 --exclude这个flag来排除这些目录了。
现在可以挂载进去了。因为我在live环境里面所以需要将new_root作为新的root起点。下面是为系统相关目录创建在new_root中的访问点,这些目录为grub提供了相关系统信息。
for di in /dev /dev/pts /proc /sys/ /sys/firmware/efi/efivars; do
sudo mount --bind $i /mnt/new_root$i
done
chroot /mnt/new_root
这些目录为待会的grub-install提供文件系统,设备,硬件等信息。这里说下efi,因为要安装在ESP分区上的Grub,这里挂载的时候需要挂载/sys/firmware/efi/efivars 这个目录。这个目录包含了UEFI的固件。即efibootmgr会访问修改该录下的EFI变量。
修改/etc/fstab
系统启动要正确挂在主要看fstab文件。如果这个写错了,就找不到挂载点,进不去系统咯。使用blkid得到对应新硬盘分区的UUID,然后修改fstab。我先把获取UUID的命令放在一个shell脚本文件内,待会用的着。
#!/bin/bash
# File: guuid.sh
# 具体情况具体分析o,我自己是nvme
sudo fdisk -l | grep nvme | awk 'NR!=1{print $1;}' | xargs sudo blkid -s UUID
# 下面是输出结果
# /dev/nvme0n1p1: UUID="你需要的UUID"
# /dev/nvme0n1p2: UUID="你需要的UUID"
# /dev/nvme0n1p3: UUID="你需要的UUID"
这个命令先放在这儿,马上我们在vim的命令行模式内运行这个命令读取其结果,这样复制uuid更方便。
# 我忘了安装vim了
sudo apt install vim
# 我设置一下vim的配置,不然挺不习惯
sudo vim /root/.vimrc
set nu
set relativenumber
syntax on
inoremap jk <Esc>
set timeoutlen=150
好了可以开始编辑fstab了。

并且在最后加上一个tmpfs 的挂载项,这个其实也可以不用,主要是用于临时的一些文件存储,放在内存中,每次启动自动清除(我觉得挺好就保留了)。
# <file system> <mount point> <type> <options> <dump> <pass>
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
mode的话按照这么写就行,1作为sticky bit 让只有所有者和root才能删除重命名,其他三个7则让所有人在当前文件夹下可读可写可执行。
bootloader和initramfs
先查看一下老旧的/etc/default/grub文件内有没有什么错误的地方,因为生成grub.cfg文件依靠的是该文件
# GRUB boot loader configuration
GRUB_DEFAULT='0'
GRUB_TIMEOUT='5'
GRUB_DISTRIBUTOR='EndeavourOS'
GRUB_CMDLINE_LINUX_DEFAULT='nowatchdog nvme_load=YES loglevel=3 iommu=pt intel_iommu=on'
GRUB_CMDLINE_LINUX=""
删除掉之前的GRUB_CMDLINE_LINUX_DEFAULT内的resume(用于睡眠重启)这个参数,如果没改动的话,这个值指向原先硬盘的swap分区的UUID。这里的iommu相关的是我个人的内核参数,没必要参考。这个是我去年做kvm的硬件穿透留下的,忘记删掉了。
# 重新建立initramfs(我用的是dracut)
dracut-rebuild
# 更新grub.cfg用于启动时grub读取解析,当然硬件穿透的事情以后再说吧。
grub-mkconfig -o /boot/grub/grub.cfg
# 安装bootloader程序到指定文件夹(该文件夹已经挂载了相应的分区)
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
结束?
这样整个迁移就完成了。最后来打开试一下结果。在从固件启动中选择NVME协议的硬盘。接着启动之后查看当前挂载的是不是之前我们的新硬盘。

所以...结束了吗?🤔
Btrfs(Butter FS)
无论是使用rsync还是dd,貌似都忽略了一个问题。就是...我用的是btrfs。它的特性貌似没有很好地展现出来。如果我使用比如ext4的话,rsync和dd一样能做。那相比于btrfs中迁移时还需要考虑的子卷问题,岂不是显得其后者更加增加了维护人员(哪来什么维护人员,就一个系统,一个人,一次开机用N天😆)的心智负担?所以?
Cow 写时复制(🐮)
COW 即 copy-on-write。Btrfs文件系统底层使用这种机制。每次对文件的块写入新的数据,总是会开辟新的空间,复制并存储修改的块而不是在原有数据块上修改(not in place)。一旦数据写入完成,则修改文件元数据来表达文件的修改。这样的机制其实也实现了即使不使用日志,也可以保证原子性(how modern it is😁)。只有文件写入完成时才会更新元数据,要不没有写入,要不更新元数据。在默认情况下COW是开启的。至少对于我这种桌面用户来说没有特别明显的感觉。也没怎么遇到文件系统崩溃或者突然关机的情况。
对于普通桌面用户来说可能没有什么关系,但是btrfs对于同一个文件进行大量写入的场景并没有做针对性优化。也就是说可能btrfs对于数据库,虚拟机这类应用场景来说并不占优势。并且根据cow的原理,其实能看出,如果多次小的写入,不断添加新的小的数据块,也会造成数据的碎片化。而关闭COW可能有所减轻。(找个时间实验一下),但是有snapshot的特性,如果数据库数据有写入错误数据,那是不是可以从文件系统的级别进行回滚呢?
Subvolume & Snapshot 子卷和快照
我目前的分区是一个常见的linux分区格式,1T的空间,我给根目录开了一个100GB的分区,16GB作为swap分区,1G作为efi的存储。剩余则留给/home。一般来说只要我硬盘没问题,或者不把/home 所在的分区搞坏,其实我完全可以在/所在的分区下重装一个系统而不影响我在/home 的数据。
Subvolume
但是dddd,安装的很多程序,以及重要的一些配置都放在/ 相关目录下。所以这样说来,可能还是迁移会更具性价比。但是btrfs的另一个特性,似乎给了我另一个选择。也就是子卷(Subvolume)。子卷看起来像一个目录,创建之后可以像普通目录一样进行操作,也可以单独挂载,这有点像分区。
新建的btrfs也是一个子卷,只不过被叫做顶级子卷。所以对我有什么用?用处在于,其实子卷可以被挂载在同一个分区之下。不同于之前不同分区分别挂载。不同分区被分别挂载,相互隔离,如果我的/home 满了,但是/root 还有空间,也不会影响系统的正常启动(除非你自己配置了什么)。
对于两个不同的分区uuid是不同的。而如果将两个子卷挂载在同一个分区之下,显而易见是相同的uuid,但在fstab内会有两条记录。并且因为挂载在同一个分区下,二者容量都是该分区的最大容量。不过这个特点就见人见智了。相比于分区,没有了大小限制,如果/home满了,那表示/也是g。但是也算是能最大化磁盘利用(我现在就是有大概50G左右的/空间没用,但是/home快满了)。当然话说回来,要是了解的话,其实还可以使用quota(磁盘配额)来限制不同子卷乃至用户的可用容量。但是就从btrfs的wiki来看貌似这个特性还不是很稳定。
Snapshot
要是用过云服务器以及虚拟机的应该都对Snapshot有所耳闻。从字面意思上来说就是snap一下拍个照(shot),Android上还有个snapchat也蛮好玩...扯远了。对当前虚拟机或服务器创建snapshot,即保存当前,机器的状态,方便在未来或者什么时候可以返回到当前状态。下面是vmware内的snapshot的编辑页面。(注意看右下角的进度条,Saving state)

创建snapshot之后,我们可以回到当时创建的状态。这个是真的很有用,因为就我个人经历来看,快照操作减轻了系统在受到破坏到恢复这个过程的维护人员的受虐程度。可以看看我的daily-rice仓库,这个仓库是存放我的部分日常配置,以及一些note,里面记录了一次我在云服务器glibc升级失败的情况(CentOS-7真的挺难受的)。当时我没有做好备份(本来没啥数据,但是有个爬虫数据是需要的),以及没有创建快照。虽然这个例子不是很恰当,但是当能够回滚到上一个可用状态的时候,这真的很重要。
So,btrfs允许我们对于子卷创建snapshot,snapshot其实也是subvolume,但是snapshot与原有的subvolume共享数据(所以不是备份o~,失忆之后不要傻乎乎把数据删了只留个快照😅),这里包括文件的metadata。这个其实有点类似于浅拷贝,不同引用指向同一个数据,这也是为什么snapshot占用空间小以及正好仰仗cow的原因。所以在对某个子卷,比如/home子卷创建snapshot之后(比如我们这里叫做/home/home-snapshot),如果需要回滚到之前的状态,则简单编辑/etc/fstab即可(记得备份,防止手抖,这也是重要文件操作时必须注意的),将原先的指向/homesubvolume的地方改为/home/home-snapshot(可以通过名字指定也可以通过id指定)。如果要管理快照或者类似定时创建快照,shell脚本是没问题的,或者使用snapper,timeshift(但是timeshift只支持Ubuntu类型的布局,/在@,/home在@home)这类软件也不失为一个选择。
Send & Receive
btrfs下的send和receive两个子命令可以以数据流形式将一个snapshot传输到另一个文件系统下。并且支持增量复制。send会生成指令流用来描述两个快照之间的修改,而在接收端可以使用receive,将接收到的snapshot存储到对应的路径中。
使用Send和Receive备份
前情回顾,下面是我之前使用rsync迁移之后的系统的fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a device; this may
# be used with UUID= as a more robust way to name devices that works even if
# disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=0101-2AFB /boot/efi vfat fmask=0137,dmask=0027 0 2
UUID=943ea0e1-99b2-4a3f-919b-24826530cd3b / btrfs subvol=/@,noatime,compress=zstd 0 0
UUID=943ea0e1-99b2-4a3f-919b-24826530cd3b /var/cache btrfs subvol=/@cache,noatime,compress=zstd 0 0
UUID=943ea0e1-99b2-4a3f-919b-24826530cd3b /var/log btrfs subvol=/@log,noatime,compress=zstd 0 0
UUID=d3043bad-7697-4142-b51d-6ea3d00c3d14 /home btrfs noatime,compress=zstd 0 0
UUID=b1aaf9a3-fa05-49a4-bbeb-f86509b0b029 swap swap defaults 0 0
这次不这么玩,我不打算把/和/home分开,而是直接在根子卷下创建两个子卷分别放/和/home,再来一个esp分区放bootloader(grub),最后再开个swap分区。大概长下面的样子
| 子卷 | 分区 | 用处 |
|---|---|---|
| /@ | nvme0n1p2 | 根 |
| /@home | nvme0n1p2 | home |
| none | nvme0n1p1 | bootloader |
| none | nvme0n1p3 | swap |
整体流程差不多,只不过同步数据部分使用 btrfs send 和 btrfs receive。先来添加一个硬盘,这里我就直接添加一个100GB的。

接下来用cfdisk(tui好看一点)创建三个分区。


最后分区完成之后如下
Disk /dev/sdb: 100 GiB, 107374182400 bytes, 209715200 sectors
/dev/sdb1 2048 1026047 102400 500M EFI System
/dev/sdb2 1026048 207595519 206569472 98.5G Linux filesystem
/dev/sdb3 207595520 209715166 2779647 1G Linux swap
创建文件系统(格式化)以及挂载对应分区
# 当前我已经是root了,所以没有加sudo
mkfs.btrfs /dev/sdb2
mkfs.vfat -F32 /dev/sdb1
mkswap /dev/sdb3
mkdir -pv /mnt/new_root
mkdir -pv /mnt/old_{root,home}
mount /dev/sdb2 /mnt/new_root
# 挂载以前的分区
mount /dev/nvme0n1p2 /mnt/old_root
先创建snapshot,保证只读
btrfs subvolume snapshot -r /mnt/old_root/@ /mnt/old_root/@_snap
btrfs subvolume snapshot -r /mnt/old_root/@cache /mnt/old_root/@cache_snap
btrfs subvolume snapshot -r /mnt/old_root/@log /mnt/old_root/@log_snap
通过send和receive进行数据迁移。
btrfs send /mnt/old_root/@_snap/ | pv | btrfs receive /mnt/new_root
btrfs send /mnt/old_root/@cache_snap | pv | btrfs receive /mnt/new_root
btrfs send /mnt/old_root/@log_snap | pv | btrfs receive /mnt/new_root
其中用pv命令来查看管道内的流量。

# 重新创建子卷,删除之前的snapshot,让新的snapshot可写
btrfs subvolume snapshot /mnt/new_root/@_snap /mnt/new_root/@
btrfs subvolume delete /mnt/new_root/@_snap
btrfs subvolume snapshot /mnt/new_root/@cache_snap /mnt/new_root/@cache
btrfs subvolume delete /mnt/new_root/@cache_snap
btrfs subvolume snapshot /mnt/new_root/@log_snap/ /mnt/new_root/@log
btrfs subvolume delete /mnt/new_root/@log_snap
# 把cache和的东西放到@下对应的目录
# 用rsync同步一下这两个目录
# 这个命令我直接放在一个脚本里了,懒得每次打那么多参数,但是为了理解上清晰一点还是放在这。
rsync --archive --one-file-system \
--inplace --hard-links --human-readable \
--numeric-ids --delete --acls --xattrs \
--sparse --itemize-changes --verbose --progress \
@log/ @/var/log/
rsync --archive --one-file-system \
--inplace --hard-links --human-readable \
--numeric-ids --delete --acls --xattrs \
--sparse --itemize-changes --verbose --progress \
@cache/ @/var/cache
btrfs subvolume delete /mnt/new_root/@log
btrfs subvolume delete /mnt/new_root/@cache
经过上述操作,根目录也就做完了。还剩下home和grub需要处理。home的话,我按照上面的表格来。
# 挂载旧home
mount /dev/nvme0n1p3 /mnt/old_home
# 创建home的快照
btrfs subvolume snapshot -r /mnt/old_home /mnt/old_home/@home_snap
# 传输home的snapshot
btrfs send /mnt/old_home/@home_snap | pv | btrfs receive /mnt/new_root
btrfs subvolume snapshot /mnt/new_root/@home_snap/ /mnt/new_root/@home
btrfs subvolume delete /mnt/new_root/@home_snap
# 剩下的就是一些清理工作,清理old_root和old_home下的多余snapshot
这样整个home也就迁移过来了。
剩下的就是对grub的重建。这个和之前是一样的,重新使用子卷挂载new_root,并且挂载对应的esp分区,然后将对应的数据rsync过去(怎么还是要用rsync?grub在的文件系统是vfat32)。
umount /mnt/new_root
mount -o subvol=@ /dev/sdb2 /mnt/new_root
mkdir -pv /mnt/old_efi
mount /dev/nvme0n1p1 /mnt/old_efi
mount /dev/sdb1 /mnt/new_root/boot/efi
# 借用上面的rsync复制。
rsync --archive --one-file-system \
--inplace --hard-links --human-readable \
--numeric-ids --delete --acls --xattrs \
--sparse --itemize-changes --verbose --progress \
/mnt/old_efi /mnt/new_root/boot/efi
将必要的系统信息相关文件夹进行重新绑定挂载。
mount --bind /dev /mnt/new_root/dev
mount --bind /proc /mnt/new_root/proc
mount --bind /sys /mnt/new_root/sys
mount --bind /sys/firmware/efi/efivars /mnt/new_root/sys/firmware/efi/efivars
chroot进入/mnt/new_root并且修改/etc/fstab。修改的话根据实际情况(实事求是🐮)
chroot /mnt/new_root
# 因为分区和之前不同了,所以需要额外修改fstab,而不是直接替换uuid
blkid -s UUID | grep sdb >> /etc/fstab # 有点鲁莽
# 最后修改fstab
下面是修改完成的fstab
<file system> <mount point> <type> <options> <dump> <pass>
UUID=72CA-E07E /boot/efi vfat fmask=0137,dmask=0027 0 2
UUID=df43c09d-9cdb-4076-bc8f-974a0d599b1d / btrfs subvol=/@,noatime,compress=zstd 0 0
UUID=df43c09d-9cdb-4076-bc8f-974a0d599b1d /home btrfs subvol=/@home,noatime,compress=zstd 0 0
UUID=5b8c3cc1-e5af-4fe1-804f-0ab6d33f03b1 swap swap defaults 0 0
/和/home的UUID相同,但是挂载在两个子卷之下。剩下就是更新grub的配置了和重建initramfs,构建完成之后退出chroot。
重启选择新的迁移之后的硬盘试试。

所以...真的结束了吗?
其实还是有东西的,比如对磁盘,备份加密。太懒了,下次再说。
并且以上只是我在vmware内的操作结果,我还是需要实际操作,把我原来的数据迁移到新的硬盘上。从硬盘大小来看,估计得迁移一会儿。
结束!
整个实际迁移没有什么额外的“惊喜”,所以顺利完成,并且我对我自己的子卷布局进行了调整。这里就不放到外面来展示了。下面是迁移过程中的一个图和迁移完成之后的图。
正在发送

迁移完成

虽然迁移完成了,其实还有一点没做,也就是对于子卷的定期快照和备份,以及备份加密。所以加油咯,还是用snapper,timeshift还限制布局,挺难受的。还有一点就是整体流程其实不复杂,是完全可以使用shell脚本完成的。 还一个是要注意的,一些以来之前子卷布局的应用可能需要重装。这里我的docker的一些镜像需要重新pull一下。
-- 来自一位Linux爱好者
评论 (...)
加载中...