如何在Ubuntu 18.04上缩小ZFS卷?

在使用ZFS的单个磁盘上进行安装时,我该如何缩小ZFS分区/池,以便可以向磁盘添加新的分区?我看到的其他指令表明要在池上设置volsize属性,但这样做会导致以下错误:无法为'rpool'设置属性:'volsize'不适用于此类型的数据集
$ zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
bpool  1.88G   196M  1.68G        -         -      -    10%  1.00x    ONLINE  -
rpool   228G  10.9G   217G        -         -     2%     4%  1.00x    ONLINE  -
2个回答

实际上,这是可以做到的。因为如果空间允许,可以从池中移除顶级vdev。所以关键在于:
1. add a temp disk/file vdev to the pool with smaller size, but is enough to hold all existing data (including snapshots etc)
2. remove the old vdev
3. possibly re-partition old vdev to smaller size, or replace with a smaller disk
4. add it back 
5. remove the temp disk.


所有文件应保持完整。
为了说明步骤:
1. 分配文件。
# fallocate -l 3G 3G_1.img
# fallocate -l 3G 3G_2.img
# fallocate -l 2G 2G_1.img
# fallocate -l 2G 2G_2.img

使用镜像创建具有两个3G文件的ZFS(我的目录是/var/snap/lxd/common/lxd/disks)。
# zpool create test3g mirror /var/snap/lxd/common/lxd/disks/3G_1.img /var/snap/lxd/common/lxd/disks/3G_2.img
# zpool status test3g
  pool: test3g
 state: ONLINE
  scan: none requested
config:

    NAME                                         STATE     READ WRITE CKSUM
    test3g                                       ONLINE       0     0     0
      mirror-0                                   ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/3G_1.img  ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/3G_2.img  ONLINE       0     0     0

errors: No known data errors
# zpool list test3g
NAME     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
test3g  2.75G   111K  2.75G        -         -     0%     0%  1.00x    ONLINE  -

你可以清楚地看到test3g池可用空间为2.75G,它是镜像的。
2. 让我们尝试在里面创建虚拟文件,以模拟您现有的数据。 这样您就可以在练习后验证您的数据是否完好无损。
# echo test > /test3g/test.txt
# cat /test3g/test.txt
test
#

现在附上另一面尺寸较小的镜子(例如2G)。
# zpool add test3g mirror /var/snap/lxd/common/lxd/disks/2G_1.img /var/snap/lxd/common/lxd/disks/2G_2.img
# zpool status test3g
  pool: test3g
 state: ONLINE
  scan: none requested
config:

    NAME                                         STATE     READ WRITE CKSUM
    test3g                                       ONLINE       0     0     0
      mirror-0                                   ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/3G_1.img  ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/3G_2.img  ONLINE       0     0     0
      mirror-1                                   ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/2G_1.img  ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/2G_2.img  ONLINE       0     0     0

errors: No known data errors
# zpool list test3g
NAME     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
test3g  4.62G   156K  4.62G        -         -     0%     0%  1.00x    ONLINE  -

现在我们有一个可用容量为4.62GB的条纹镜像。
4. 让我们移除之前的3G部分。
# zpool remove test3g mirror-0
# zpool status
  pool: default
 state: ONLINE
  scan: scrub repaired 0B in 0 days 00:06:45 with 0 errors on Fri May 21 15:20:30 2021
config:

    NAME                                            STATE     READ WRITE CKSUM
    default                                         ONLINE       0     0     0
      mirror-0                                      ONLINE       0     0     0
        /opt/lxc_image/default.img                  ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/default.img  ONLINE       0     0     0

errors: No known data errors

  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 0 days 00:00:10 with 0 errors on Tue May 18 19:42:56 2021
config:

    NAME                                         STATE     READ WRITE CKSUM
    tank                                         ONLINE       0     0     0
      mirror-0                                   ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/tank.img  ONLINE       0     0     0
        /nfs-dual/zfs-images/tank.img            ONLINE       0     0     0

errors: No known data errors

  pool: test3g
 state: ONLINE
  scan: none requested
remove: Removal of vdev 0 copied 102K in 0h0m, completed on Fri May 21 15:33:19 2021
    72 memory used for removed device mappings
config:

    NAME                                         STATE     READ WRITE CKSUM
    test3g                                       ONLINE       0     0     0
      mirror-1                                   ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/2G_1.img  ONLINE       0     0     0
        /var/snap/lxd/common/lxd/disks/2G_2.img  ONLINE       0     0     0

errors: No known data errors
# zpool list test3g
NAME     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
test3g  1.88G   142K  1.87G        -         -     0%     0%  1.00x    ONLINE  -

空间剩余1.87G。 注意,根据您的数据大小,可能需要很长时间,但会成功完成。 请查看上方的消息。
Removal of vdev 0 copied 102K in 0h0m, completed on Fri May 21 15:33:19 2021

你在技术上将zpool的大小从3G减小到2G,没有停机时间,也没有丢失数据。
5. 让我们验证数据是否仍然存在。
# cat /test3g/test.txt
test
#

当然可以。
请注意,只有最新版本的zfs支持此功能。具体效果可能因人而异。
谢谢 最好的祝福 Shilin

干得好,使用zpool add而不是zpool attach。据我所知,zpool add将新的磁盘添加为RAID-0(或者说是一堆磁盘,总容量相加),而zpool attach将新的磁盘作为RAID-1(镜像,总容量不变)进行连接。然后,通过zpool remove删除RAID-0的一部分,强制数据流向剩余部分。因此,实现了调整大小的目的。值得一提的是,如果数据大小大于zpool中剩余磁盘的容量,会提示“无法删除...:空间不足”错误。你根本无法使用zpool remove来删除它。感谢ZFS的设计,它非常安全可靠。 - midnite
在执行zpool remove之后,如何摆脱indirect-0?https://serverfault.com/q/1102923/237756 - midnite
从这种方法中有一个重要的限制,根据我在#zfs IRC频道上听到的,一旦你在周围“添加”或“删除”vdevs,ZFS会向池中添加一个功能标志,使其与“grub”不兼容。这个问题可能已经在后来的grub版本中修复了,但在进行移动之前,至少要先检查一下,或者在开发阶段进行测试。 - anarcat
我在zfs-2.1.5-1ubuntu6~22.04.1上遇到了unrecognized command 'status'unrecognized command 'add'的问题,我原以为这是比较新的版本。这是否意味着我需要更新?@Wu-Shilin,你使用的是哪个版本? - Cadoiz

一旦将磁盘添加到ZFS池中,默认情况下,ZFS会为其分配整个磁盘并使用EFI标签格式化磁盘以包含一个单独的大分区。这是推荐的方式。
如果您已经分配了整个磁盘,就无法缩小卷的大小。从技术上讲,您可以通过gparted或其他工具强制缩小它,但这会导致ZFS池出现问题,并且会丢失数据,因此不建议这样做。
您可以减小特定ZFS池的大小,并从空闲空间创建新的池。唯一可能释放一些空间的方法是将磁盘离线(希望您在ZFS池中有多个磁盘),重新格式化它,并将一部分空间用于所需的分区,剩余空间分配给ZFS分区,例如。当您将磁盘重新添加到ZFS池时,需要添加ZFS分区以供使用。这不是推荐的方式,但可以视为解决方法。 请自行承担风险。

1你可以在技术上通过gparted强制缩小它,但你并不是在强制缩小它,而是截断池("割掉它的脚"),所以"你可能会丢失数据"这句话非常低估了情况:数据丢失几乎是肯定的。至少在OpenZFS中没有推荐的方式来缩小一个分区。你需要创建一个新的池并迁移数据(通过发送/接收)。 - Valmiky Arquissandas
GParted(1.3.1)实际上在我的系统上不允许缩小分区。 - Cadoiz