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

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

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

备注

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

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

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 Atlas 存储,并作为部署 Kubernetes Atlas 的底层分布式存储

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

参考