Running blockchain nodes at scale quickly turns into a storage management problem.
In this guide, Iβll walk through a real-world migration of a BSC testnet dataset (~243GB) to a new disk β without breaking the node β and share key lessons learned.
π Initial Situation
Inside the VM:
/dev/vdb1 β /node-data (6.3T disk, almost full)
Breakdown:
- Mainnet: ~5.8TB
- Testnet: ~243GB
Problem:
Disk usage: 100%
Free space: ~41GB β οΈ
π Risk: node crash, DB corruption, sync failure
π― Goal
- Move testnet data to a new disk
- Keep mainnet untouched
- Avoid complex Docker changes
- Minimize downtime
ποΈ Architecture Before
vdb (6.3T)
βββ /node-data
βββ mainnet (~5.8T)
βββ testnet (~243G)
π Architecture After
vdb β mainnet
vdc β testnet
/bsc-testnet β real mount
/node-data/testnet β bind mount β /bsc-testnet
Docker still uses:
/node-data/testnet:/bsc/node
π No container config change needed.
β‘ Step-by-Step Migration
1οΈβ£ Attach new disk (on host)
qemu-img create -f qcow2 /path/bsc-testnet.qcow2 400G
virsh attach-disk bsc \
/path/bsc-testnet.qcow2 \
vdc \
--targetbus virtio \
--subdriver qcow2 \
--persistent
2οΈβ£ Prepare disk (inside VM)
Skip partitioning (simpler):
mkfs.ext4 /dev/vdc
mkdir /bsc-testnet
mount /dev/vdc /bsc-testnet
3οΈβ£ Copy data
rsync -avh /node-data/testnet/ /bsc-testnet/
4οΈβ£ Switch using bind mount (no Docker change)
docker stop testnet
mv /node-data/testnet /node-data/testnet-old
mkdir /node-data/testnet
mount --bind /bsc-testnet /node-data/testnet
docker start testnet
5οΈβ£ Cleanup (after verification)
rm -rf /node-data/testnet-old
6οΈβ£ Make persistent
Edit /etc/fstab:
UUID=<vdc-uuid> /bsc-testnet ext4 defaults 0 0
/bsc-testnet /node-data/testnet none bind 0 0
Test:
mount -a
π₯ Key Lessons Learned
1οΈβ£ You donβt need to touch Docker
Instead of:
- editing volumes
- recreating containers
π Just move the filesystem underneath
This is safer and faster.
2οΈβ£ Bind mounts are extremely powerful
/node-data/testnet β /bsc-testnet
Acts like:
- transparent redirect
- zero config change
- instant rollback
3οΈβ£ βtarget is busyβ = you are inside the directory
Classic mistake:
umount /node-data/testnet
β target is busy
Cause:
cwd = /node-data/testnet
Fix:
cd /
4οΈβ£ Duplicate mounts can happen easily
Running mount --bind multiple times creates stacked mounts.
Check with:
mount | grep testnet
findmnt /node-data/testnet
Fix:
umount /node-data/testnet (repeat until gone)
5οΈβ£ Never unmount while container is running
Even if it βworksβ:
- DB writes can fail
- corruption risk
- node may resync from scratch
π Always:
docker stop β umount β remount β start
6οΈβ£ Partitioning is optional
For dedicated disks:
mkfs.ext4 /dev/vdc
is simpler than:
fdisk β /dev/vdc1
7οΈβ£ Blockchain nodes will ALWAYS outgrow your disk
After migration:
mainnet still ~92% full
π This is temporary relief.
You must plan:
- disk expansion (
qemu-img resize) - or data rebalancing
π Results
After migration:
- Freed ~243GB on main disk
- Isolated IO between mainnet/testnet
- No Docker reconfiguration
- Minimal downtime (~1β2 minutes)
π§ Final Takeaway
The key mindset shift:
Donβt move applications β move the filesystem underneath them.
This approach:
- reduces risk
- simplifies operations
- scales better for large datasets (TBs)
π Whatβs Next
For production-grade setups:
- Separate disks per chain
- Use
virsh blockcopyfor live migration - Implement storage balancing strategy across NVMe pools
Top comments (0)