Convert Raspberry Pi Ubuntu to iSCSI btrfs root
This is to move root file system of Raspberry Pi Ubuntu OS to iSCSI LUN and convert it to btrfs file system
Pros
- Cheaper than using small SD card
- Backup and restore easy, only need to backup 150MB boot partition on SD card
- Able to perform snapshot at LUN level or OS level (btrfs)
- Should be Faster
Steps
Install iscsi packages
apt install open-iscsi
systemctl enable open-iscsi
systemctl start open-iscsi
systemctl enable iscsid
systemctl start iscsid
Configure iscsi
Edit /etc/iscsi/initiatorname.iscsi
, update following line
InitiatorName=<YOUR_INITIATOR_NAME>
Note: The YOUR_INITIATOR_NAME is the iSCSI client name
Edit /etc/iscsi/iscsid.conf
, update following lines
node.session.auth.authmethod = CHAP
node.session.auth.username = <YOUR_USERNAME>
node.session.auth.password = <YOUR_PASSWORD>
# iscsiadm --mode discovery --type sendtargets --portal <YOUR_TARGET_IP>
# iscsiadm --mode node --targetname <YOUR_TARGET_NAME> --portal <YOUR_TARGET_IP> --login
Note: If can not login, restart iscsid
and try again.
systemctl restart iscsid
Identify block device
Use lsblk
command to identify device file, normally should be /dev/sda
.
Partitioning
Creating two partitions using fdisk, the first partition is to prepare following for future used, such as
- Network boot
- UEFI iSCSI boot
- SD card backup
Partition /dev/sda1: vfat, 2GB
Partition /dev/sda2: for root filesystem
Create filesystems
mkfs.vfat /dev/sda1
mkfs.btrfs /dev/sda2
Identify UUID for root filesystem
blkid /dev/sda2
Update initramfs
This is to enable ubuntu load iscsi driver during boot
touch /etc/iscsi/iscsi.initramfs
update-initramfs -v -k $(uname -r) -c
Duplicate files
mount /dev/sda2 /mnt
rsync -avhP --exclude /boot/firmware --exclude /proc --exclude /sys --exclude /dev --exclude /mnt / /mnt/
mkdir /mnt/{dev,proc,sys,boot/firmware,mnt}
Modify /etc/fstab
in LUN
Note: Don't modify the file in /etc
, it will not be used during iSCSI boot.
vi /mnt/etc/fstab
Change root mounting to
UUID=<YOUR_DEV_UUID> / btrfs defaults 1 1
Modify /boot/firmware/cmdline.txt
First create a backup of this file
cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.sav
Change the content of /boot/firmware/cmdline.txt
Note: Beware of rootfstype=btrfs
net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 rootfstype=btrfs elevator=deadline rootwait fixrtc ip=dhcp root=UUID=<YOUR_DEV_UUID> ISCSI_INITIATOR=<YOUR_INITIATOR_NAME> ISCSI_TARGET_NAME=<YOUR_TARGET_NAME> ISCSI_TARGET_IP=<YOUR_TARGET_IP> ISCSI_TARGET_PORT=3260 ISCSI_USERNAME=<YOUR_USERNAME> ISCSI_PASSWORD=<YOUR_PASSWORD> rw
Note: Root partition can also be identified by label if assigned one, see next topic
Reboot
umount /mnt
reboot
Use LABEL for root
Using label instead of UUID for root filesystem.
Assign a label
For mounted filesystem
sudo btrfs filesystem label <mountpoint> <newlabel>
For not mounted filesystem
sudo btrfs filesystem label <device> <newlabel>
Change /etc/fstab
LABEL=<newlabel> / btrfs defaults 1 1
Change /boot/fireware/cmdline.txt
... root=LABEL=<newlabel> ...
Use Static IP
To use static IP for iSCSI connection, the ip definition in cmdline.txt needs to be changed to
ip=192.168.1.200::192.168.1.1:255.255.255.0:rpi:eth0:off
This will create an IP 192.168.1.200 on interface eth0 as below.
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether dc:a6:32:ef:07:0f brd ff:ff:ff:ff:ff:ff
inet 192.168.1.200/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.1.23/24 brd 192.168.1.255 scope global secondary dynamic eth0
valid_lft 43036sec preferred_lft 43036sec
inet6 fe80::dea6:32ff:feef:70f/64 scope link
valid_lft forever preferred_lft forever
One way to just maintain one IP is, disabling OS IP address.
Reboot
Other cmdline.txt format
I tried following format, but failed. I think it maybe work if no partition in iSCSI LUN
root=iscsi:[<username>:<password>[:<reverse>:<password>]@][<servername>]:[<protocol>]:[<port>][:[<iscsi_iface_name>]:[<netdev_name>]]:[<LUN>]:<targetname>
Use UUID is better, because there is no need to worry about LUN id and partition as UUID is unique ideitifier.
To specfic UUID, following format can be used according to kernel parameters, but it doesn't work too.
root=UUID=<UUID>
netroot=iscsi:[<username>:<password>[:<reverse>:<password>]@][<servername>]:[<protocol>]:[<port>][:[<iscsi_iface_name>]:[<netdev_name>]]:[<LUN>]:<targetname>
I also tried rd.*
format, such as rd.iscsi.initiator
, etc., they are new format to replace old format ISCSI_INITIATOR, etc., but also not failed. I think the dracut.cmdline
version used by ubuntu in raspberry pi is old. Maybe should try grub2
used in Fedora OS for raspberry pi, or uefi
used in Windows 10.
Backup and restore using pre-backup data
Backup data into iSCSI LUN partition 1
First create vfat in iSCSI LUN as partition 1, then backup /boot/fireware
data into that partition
mkfs.vfat /dev/sda1
mount /dev/sda1 /mnt
cp /boot/firmware/. /mnt
umount /mnt
Restore to an empty SD card
Create partition in new SSD as type c
, which W95 FAT32 (LBA), with Boot flag.
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 2048 1050623 1048576 512M c W95 FAT32 (LBA)
Format SD card and give label as system-boot
, the LABEL is defined in /etc/fstab
, it can be changed to UUID if needed.
mkfs.vfat -n system-boot /dev/sdb1
mount /dev/sdb1 /mnt
cp -a <backup_filesystem> /mnt
umount /mnt
Make sure system reported correct LABEL on the newly created vfat filesystem, using blkid
command to verify.
Troubleshooting
iscsi_tcp missing
If following error occurred, install package linux-modules-extra
.
libkmod: ERROR ../libkmod/libkmod-module.c:838 kmod_module_insert_module: could not find module by name='iscsi_tcp'
Please read post Missing iSCSI module in Ubuntu 20.10
Reboot error
If failed to boot, initram command prompt will appear. In this case, following commands can be used to recover back the booting.
mkdir /mnt
mount /dev/mmcblk0p1 /mnt
cd /mnt
cp cmdline.txt.sav cmdline.txt
cd /
umount /mnt
reboot
Note: the umount
is very important, otherwise, the changes wouldn't be saved.
There are very minimum commands can be used, such as no vi
. So let it boots into previous status, then troubleshooting from there.
References
dracut kernel command line options
Kernel command line parameters
introduction to boot time parameters of the Linux kernel
Raspberry Pi 4 UEFI Boot
RPi cmdline.txt
RPi config.txt
kernel-parameters.txt
The config.txt file
Raspberry Pi iSCSI Root on Ubuntu 20.04
btrfs root filesystem on raspbian
[Howto] booting from iSCSI
Ubuntu Server 20.10 on Raspberry Pi 4: installation guide with USB Boot (no SD card) and full disk encryption (excluding /boot) using btrfs-inside-luks and auto-apt snapshots with Timeshift
Raspberry Pi 4 - Ubuntu 20.04 w/Btrfs root
dracut.cmdline(7) — Linux manual page