This issue has come up a few times on Discord. The question can be summarised like this:
My existing IOTstack installation is running out of space on my primary drive. I have another drive. How do I move the "volumes" directory to the new drive?
This example is based on a Raspberry Pi 4 which is booting from a 500GB USB3 SSD. I will show you how to use a 32GB USB3 "thumb drive" as the secondary drive and move ~/IOTstack/volumes onto it.
Don't get hung up on the details of my hardware. The principles are the same, regardless of whether:
- the "primary" is an SD card, SSD or anything else.
- the "secondary" is a thumb drive, SSD or anything else.
Before you attach the secondary drive to your Raspberry Pi, list your existing drives:
$ lsblk
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 256M 0 part /boot
└─sda2 8:2 0 465.5G 0 part /
Now, attach the second drive and repeat the command:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 256M 0 part /boot
└─sda2 8:2 0 465.5G 0 part /
sdb 8:16 1 28.7G 0 disk
└─sdb1 8:17 1 28.7G 0 part
Because "sdb" and "sdb1" only appeared after attaching the new drive, it should be self-evident that those elements represent the secondary drive.
Notes:
-
There are no guarantees that your own system will use "sdb" and "sdb1" when you attach a new drive. If your system uses different identifiers, you will need to substitute those throughout the remainder of this gist.
-
It is really important that you pay attention and make sure that you have identified your secondary drive correctly. Don't guess. If you make a mistake at this point, you could easily destroy all the data on your primary drive.
Each entry in the "NAME" column implies a "/dev/" prefix so, in this example:
- the secondary drive physical disk is: /dev/sdb
- the secondary drive logical volume: /dev/sdb1
- the absence of anything in the "MOUNTPOINT" column to the right of "sdb1" means the secondary drive did not auto-mount.
Note:
-
If the "MOUNTPOINT" column to the right of "sdb1" is not empty, you will need to unmount that drive:
$ sudo umount /dev/sdb1
You now need to prepare the secondary drive for use by Raspbian. Be very careful with the following commands. Double-check each command before you hit return.
$ sudo parted /dev/sdb mklabel gpt
$ sudo parted -a opt /dev/sdb mkpart primary ext4 0% 100%
$ sudo mkfs -t ext4 /dev/sdb1
$ sudo e2label /dev/sdb1 IOTstackVolumes
$ sudo partprobe
Take down your running IOTstack:
$ cd ~/IOTstack
$ docker-compose down
Rename the existing ./volumes subdirectory to get it out of the way
$ sudo mv ./volumes ./volumes.old
Create a new (empty) ./volumes subdirectory. This will become the mount-point for the secondary drive:
$ sudo mkdir ./volumes
$ sudo mount LABEL=IOTstackVolumes ./volumes
Assuming the volume mounts without error, try creating a file inside it:
$ sudo touch ./volumes/testfile
$ ls -l ./volumes/testfile
-rw-r--r-- 1 root root 0 Mar 23 22:26 ./volumes/testfile
If the file shows up, unmount the volume and try again:
$ sudo umount ./volumes
$ ls -l ./volumes/testfile
ls: cannot access './volumes/testfile': No such file or directory
In this case, the file should not show up because the volumes directory should be empty.
You need to tell Raspbian to auto-mount the secondary drive on each boot. You do that by editing the file:
/etc/fstab
Start by making a backup of the existing file:
$ sudo cp /etc/fstab /etc/fstab.bak
Then list the file you are going to edit:
$ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=7f8f5227-01 /boot vfat defaults 0 2
PARTUUID=7f8f5227-02 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
The layout of the default file is a little messy and harder to understand than it should be. It's probably a good idea to clean it up by adding spaces (not tabs) to align everything. The line you need to add looks like this:
LABEL=IOTstackVolumes /home/pi/IOTstack/volumes ext4 defaults 0 2
Use sudo and your favourite text editor (eg vi or nano) to edit /etc/fstab so that the final result looks something like this:
proc /proc proc defaults 0 0
PARTUUID=1801318c-01 /boot vfat defaults 0 2
PARTUUID=1801318c-02 / ext4 defaults,noatime 0 1
LABEL=IOTstackVolumes /home/pi/IOTstack/volumes ext4 defaults 0 2
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
From left to right, the fstab fields are:
- An identifier for the file system to be mounted. The earlier
e2labelcommand gave the secondary disk a label of "IOTstackVolumes" so that is what we will use here. We could also use the drive's UUID or PARTUUID but a label is more informative. Using an identifier rather than a device path means that the disk will still mount correctly, even if it appears on a different physical USB port. - Where the file system should be mounted. The secondary disk is going to be used for IOTstack volumes data so that is where it should be mounted. Note that
fstabis processed byrootso an absolute path is required. - The type of the file system (
ext4effectively means "Linux Native"). - The mount options. Defaults are appropriate.
- The "0" means "don't dump the file system".
- The priority order for running
fsckat boot time.
Save your work and then reboot:
$ sudo reboot
Immediately after the reboot, make sure that the volume has mounted correctly:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 256M 0 part /boot
└─sda2 8:2 0 465.5G 0 part /
sdb 8:16 1 28.7G 0 disk
└─sdb1 8:17 1 28.7G 0 part /home/pi/IOTstack/volumes
If you see the correct mount-point, it means the fstab has done its work and the secondary disk has mounted as expected. You should also be able to see the test file you created earlier:
$ cd ~/IOTstack/volumes
$ ls -l testfile
-rw-r--r-- 1 root root 0 Mar 23 22:26 testfile
You can remove that file:
$ sudo rm testfile
You have two choices:
-
EITHER: copy the existing data to the new drive:
$ cd ~/IOTstack $ sudo cp -a ./volumes.old/* ./volumesThis approach has the advantage of being non-destructive. If anything goes wrong with the copy, you still have the existing data and can start over. The disadvantage is that no space is freed-up on your primary drive, and you will have to remember to come back later and delete the old data.
-
OR: move the existing data to the new drive:
$ cd ~/IOTstack $ sudo mv ./volumes.old/* ./volumesBecause the target folder is on a different physical drive, the
mvis actually implemented as a copy followed by a remove.
Whichever option you choose, at some future time you should clean up the old folder:
$ cd ~/IOTstack
$ sudo rm -rf ./volumes.old
There is no need to edit your compose file. As far as docker-compose is concerned, the ./volumes folder is in the right place. Just bring up your stack as usual:
$ docker-compose up -d
If you have been in the habit of doing any of the following:
- Renaming or erasing
~/IOTstack - Renaming or erasing
~/IOTstack/volumes
you are not going to be able to do that. The absolute path to the /home/pi/IOTstack/volumes mount-point must remain where it is.
Instead of making ~/IOTstack/volumes the mount point for a second drive, you could move the goal-posts slightly and make ~/IOTstack the mount point. That way your your entire IOTstack structure would be on your secondary drive.