树莓派关闭自动resize根文件系统(首次启动)

在使用 Raspberry Pi树莓派4b运行64位Ubuntu 时,你会发现当系统启动时,会自动把根文件系统扩展成占用整个磁盘系统。

这对我部署 GlusterCeph 不利,因为我需要自定义文件系统,准备独立的存储卷给存储服务使用。

备注

可能首次镜像安装以后,需要删除掉 /.first_boot 标记文件,避免第一次启动自动扩展文件系统。

在 Ubuntu for Raspbery Pi 系统中,采用 关闭cloud-init 方法禁止 cloud-init 就可以关闭自动扩展,或者修改 cloud-init 配置关闭自动扩展。

注意,本文实践是在 树莓派(Raspberry Pi)快速起步 基础上完成,也就是说,我是将磁盘挂载到一个已经运行 Raspbery Pi OS(Raspbian) 的树莓派上,通过 chroot 实现切换到磁盘上操作系统进行修订的(以便能够修改磁盘的系统 initramfs ):

挂载树莓派Linux分区
mount /dev/sda2 /mnt
mount /dev/sda1 /mnt/boot/firmware
采用 chroot 方式切换到树莓派系统
mount -t proc proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --make-rslave /mnt/sys
mount --rbind /dev /mnt/dev
mount --make-rslave /mnt/dev

chroot /mnt /bin/bash
source /etc/profile
export PS1="(chroot) $PS1"

resize逻辑

备注

树莓派的首次启动自动调整分区和文件系统大小的方法已经做过多次修改:

  • 早期的树莓派是通过 /boot/cmdline.txt 来调用 /usr/lib/raspi-config/init_resize.sh 脚本调整的

  • 现代树莓派基于Debian 12,采用了 initramfs 脚本调整分区(此时文件系统不挂载),然后挂载文件系统后,通过 /etc/init.d/resize2fs_once 再完成 在线扩展 EXT4 根文件系统

树莓派的resize步骤分为分区resize和文件系统resize,但是分布在不同的脚本中

resize分区

  • 分区resize是由 initramfs 调用脚本 /usr/share/initramfs-tools/scripts/local-premount/firstboot

initramfs 调用 /usr/share/initramfs-tools/scripts/local-premount/firstboot 脚本实现分区resize
#!/bin/sh

set -e

case "${1}" in
  prereqs)
    exit 0
    ;;
esac

if ! grep -q firstboot /proc/cmdline; then
  exit 0
fi

get_variables () {
  set +e # This function does not work as intended with -e
  local_device_setup "$ROOT" "root file system"
  set -e
  ROOT_PART_NAME="$(lsblk -no kname "$DEV")"

  ROOT_DEV_NAME="$(lsblk -no pkname "$DEV")"
  ROOT_DEV="/dev/$ROOT_DEV_NAME"

  ROOT_PART_NUM=$(cat "/sys/block/$ROOT_DEV_NAME/$ROOT_PART_NAME/partition")

  ROOT_DEV_SIZE=$(cat "/sys/block/$ROOT_DEV_NAME/size")
  TARGET_END="$((ROOT_DEV_SIZE - 1))"
  if [ "$TARGET_END" -gt 4294967295 ]; then
    TARGET_END=4294967295
  fi
}

do_resize () {
  if ! parted -m "$ROOT_DEV" u s resizepart "$ROOT_PART_NUM" "$TARGET_END"; then
    FAIL_REASON="Partition table resize of the root partition ($DEV) failed\n$FAIL_REASON"
    return 1
  fi

  wait_for_udev 10
  resize2fs -f -p "$DEV"
  RET="$?"
  if [ "$RET" -ne 0 ]; then
    FAIL_REASON="Root partition resize failed\n$FAIL_REASON"
  fi

  return "$RET"
}

. /scripts/functions
. /scripts/local

log_begin_msg "Resizing root filesystem...\n\nDepending on storage size and speed, this may take a while."

get_variables
do_resize

log_end_msg

exit 0

所以修订 firstboot 脚本 TARGET_END 变量指定自己期望扩展的大小即可

注意,由于是 initramfs 调用脚本,所以需要通过 initramfs-tools 工具重新制作 initramfs 镜像

resize文件系统

  • 文件系统resize是由 /etc/init.d/resize2fs_once 完成,如其文件名,这个脚本只在首次启动时调用一次,并且执行后会把自己从系统中删除(以确保不再执行):

#!/bin/sh
### BEGIN INIT INFO
# Provides:          resize2fs_once
# Required-Start:
# Required-Stop:
# Default-Start: 3
# Default-Stop:
# Short-Description: Resize the root filesystem to fill partition
# Description:
### END INIT INFO
. /lib/lsb/init-functions
case "$1" in
  start)
    log_daemon_msg "Starting resize2fs_once"
    ROOT_DEV=$(findmnt / -o source -n) &&
    resize2fs $ROOT_DEV &&
    update-rc.d resize2fs_once remove &&
    rm /etc/init.d/resize2fs_once &&
    log_end_msg $?
    ;;
  *)
    echo "Usage: $0 start" >&2
    exit 3
    ;;
esac

修改

我在 边缘云计算架构(旧版) 部署时,规划给树莓派工作节点1T存储空间:

  • 128G空间用于操作系统

  • 剩余空间(大约850G)用于构建 Ceph 存储,并作为部署 Kubernetes 的底层分布式存储

按照计划,修订分区调整脚本,将 TARGET_END 设定为固定值

那么这个固定值该设置为多少呢?

嘿嘿,我实际上是使用 parted分区工具 工具,实际为磁盘划分了一个大约128GB空间分区,然后记录下 /sys/block/sda/sda3/size 来获得这个数值的。

实践的脚本修改如下:

修改分区调整大小为固定128GB
...
get_variables () {
  ...
  ROOT_DEV_SIZE=$(cat "/sys/block/$ROOT_DEV_NAME/size")

  #TARGET_END="$((ROOT_DEV_SIZE - 1))"
  # Set static size about 128GB, the value is get from test
  TARGET_END=244592640
  if [ "$TARGET_END" -gt 4294967295 ]; then
    TARGET_END=4294967295
  fi
}
...
  • 执行 update-initramfs (系统默认没有安装 Dracut ) :

执行 update-initramfs 创建新的 initramfs
update-initramfs -c -k $(uname -r)

备注

参考 How can I use an init ramdisk (initramfs) on boot up Raspberry Pi? ,我使用 update-initramfs 生成新的 initramfs

此外, Using an initramfs on the RPi 也可以采用 mkinitramfs

mkinitramfs -o /boot/initramfs-$(uname -r)

参考