Featured image of post Preparing a Test Environment for RustFS

Preparing a Test Environment for RustFS

How I automate some of the steps involved in creating an environment to test application functionality.

How to quickly build an environment on your own hardware to test the performance of an application running in a multi-node environment with more disk resources.

RustFS - open-source, S3-compatible high-performance object storage system supporting migration and coexistence with other S3-compatible platforms such as MinIO and Ceph.

What do we want?

What do we want to achieve?

The goal is to install a RustFS cluster, technically called a Multiple Node Multiple Disk Installation (MNMD). I assumed we needed 8 virtual machines, each with 8 disks for data (including the OS disk, that’s 9).

For daily testing, I virtualize using

Base

The names rust2* and rustfs2* are identical and are used interchangeably.

You can download a pre-installed Linux image ready to run, or you can spend a few minutes manually installing it. My choice is Debian 13.7, the latest stable release, Trixie.

To avoid duplicating this process of installing a fresh OS eight times, it reuses the once-performed installation and clones it. It uses zfs rather unusually on the virtual machine, so it must be installed on the base machine. Alternatively, you can use parted and also prepare attached disk image files to create the file system.

Also you can use virt-clone. I used a rather crude method: copying an image of the base disk, creating a base configuration by virsh dumpxml, editing the XML files (example sed), and finally deploying define a virtual machine virsh define. The base image is rust20, and I create eight similar machines from it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
              ┌──────┐              
  ┌──────┐    │rust28│    ┌──────┐  
  │rust21│    └──┬───┘    │rust27│  
  └──────┤       │        ├──────┘  
         └───┬───┴────┬───┘         
 ┌──────┐    │┌──────┐│    ┌──────┐ 
 │rust22┼────┤│rust20│├────┤rust26│ 
 └──────┘    │└──────┘│    └──────┘ 
         ┌───┴────┬───┴───┐         
  ┌──────┤        │       ├──────┐  
  │rust23│    ┌───┴──┐    │rust25│  
  └──────┘    │rust24│    └──────┘  
              └──────┘              

W przykładach k to zmienna oznaczająca numer komputera i zawiera się w przedziale {1..8}, stąd nazwy nodów to kolejno rustfs21, rustfs22 aż do rustfs28.

Wykorzystane listy, kleją numer dysku z jego nazwą w systemie. Dysk vda już dyskiem systemowym, więc kolejny rozpoczyna się od b.

1
2
dyskitarget=( "b" "c" "d" "e" "f" "g" "h" "i")
dyskinumerki=("1" "2" "3" "4" "5" "6" "7" "8")

Dodatkowe dyski utworzyłem za pomocą qemu-img

1
2
3
for i in "${!dyskinumerki[@]}" ; do 
  printf "qemu-img create -f qcow2 rustfs2${k}.%s.qcow2 8G \n" "${dyskinumerki[i]}"
done

Przypiąłem je do maszyny

1
2
3
4
5
6
7
8
for i in "${!dyskitarget[@]}" ; do
  printf "virsh attach-disk rustfs2${k} 
  --target vd%s 
  --source rustfs2${k}.%s.qcow2 
  --subdriver qcow2 
  --config \n"
  "${dyskitarget[i]}" "${dyskinumerki[i]}"
done

Każda wirtualka powinna już mieć osiem dysków.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Schemat (poglądowy)             
podłaczenia dysków  ┌──────────┐
 ┌┐ ┌───┐  ┌───┐  ┌─┴─┐  ┌───┐ │
 │└─┤vdb│  │vdd│  │vdf│  │vdh│ │
 │  └───┘ ┌┴───┘  └───┘  └─┬─┘ │
 └────────┼───┐  ┌─────────┘   │
┌───────┐ │  ┌┴──┴──┐ ┌────────┘
│  ┌───┐│ └──┤rust2▒├─┘┌──────┐ 
│  │   ││  ┌─┴──┬┬──┴──┘     ┌┘ 
│ ┌┴──┐││ ┌┴──┐ ││┌───┐   ┌──┴┐ 
│ │vdc│└┘ │vde│ │││vdg├─┐ │vdi│ 
│ └───┘   └───┘ ││└───┘ │ └───┘ 
└───────────────┘└──────┘       

Po zaimportwaniu wymaganej liczby wirtualek każdą z nich czyszczę pod nową instalację. Do tego virt-sysprep nadaje się idealnie. Domyślnie przy pełnym przygotowaniu usuwa też klucze publiczne dla każdego użytkownika (także dla roota), ale jest przełącznik -ssh-userdir, który temu zapobiega.

1
2
3
4
virt-sysprep \
  -d rustfs2${k} \
  --hostname rustfs2${k} \
  --operations defaults,-ssh-userdir

Oczywiście możemy tego nie stosować, ale będzie się to wiązało z ponownym wrzuceniem naszych kluczy publicznych (ręcznie albo używając automatyzacji np. ansible a to już dodatkowe zbędne kroki - w końcu to środowisko testowe, ma być szybko.

Pierwsze uruchomienie

Poleceniem lsblk sprawdzamy czy są dostępne dyski, powinno to tak wyglądać:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
root@rust20:~# lsblk 
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sr0     11:0    1 1024M  1 rom  
vda    254:0    0    8G  0 disk 
└─vda1 254:1    0    8G  0 part /
vdb    254:16   0    8G  0 disk 
vdc    254:32   0    8G  0 disk 
vdd    254:48   0    8G  0 disk 
vde    254:64   0    8G  0 disk 
vdf    254:80   0    8G  0 disk 
vdg    254:96   0    8G  0 disk 
vdh    254:112  0    8G  0 disk 
vdi    254:128  0    8G  0 disk 

Tworzymy punkty montowania, tworzymy pule per 1 dysk i w każdej zakładamy po jednym systemie plików. Tutaj i={b..i}.

1
2
3
mkdir -p /z/vd${i}
zpool create -f -m none -o ashift=12 vd${i} /dev/vd${i}
zfs create -o mountpoint=/z/vd${i}/vd${i} vd${i}/vd${i}

Sprawdzamy poleceniami czy zakładanie zakończyło się sukcesem:

  • zpool list
  • zfs list
  • lsblk
  • df -h
  • mount

Tożsamość w sieci ;)

Dla pełniejszej integracji należy dopisać nowe maszyny do DNSa i DHCP jako wpisy statyczne.

W CoreDNS dopisałem

1
2
3
4
5
6
7
8
rust28 IN A 172.30.197.28
rust27 IN A 172.30.197.27
rust26 IN A 172.30.197.26
rust25 IN A 172.30.197.25
rust24 IN A 172.30.197.24
rust23 IN A 172.30.197.23
rust22 IN A 172.30.197.22
rust21 IN A 172.30.197.21

W MikroTik

1
2
3
4
5
6
7
8
9
/ip dhcp-server lease
add address=172.30.197.21 client-id=ff:9:16:21:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:21:00 server=dhcp0
add address=172.30.197.22 client-id=ff:9:16:22:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:22:00 server=dhcp0
add address=172.30.197.23 client-id=ff:9:16:23:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:23:00 server=dhcp0
add address=172.30.197.24 client-id=ff:9:16:24:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:24:00 server=dhcp0
add address=172.30.197.25 client-id=ff:9:16:25:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:25:00 server=dhcp0
add address=172.30.197.26 client-id=ff:9:16:26:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:26:00 server=dhcp0
add address=172.30.197.27 client-id=ff:9:16:27:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:27:00 server=dhcp0
add address=172.30.197.28 client-id=ff:9:16:28:0:0:1:0:1:xx:xx:xc:xx:52:26:9:16:20:0 mac-address=52:26:09:16:28:00 server=dhcp0

Finalnie powinniśmy otrzymać odpowiedź

1
2
$ dig +short rust21.bigdatalinux.com @172.30.199.209
172.30.197.21

Usunięcie środowiska

W celu całkowitego usunięcia i ponownego zbudowania piaskownicy trzeba zatrzymać maszyny, uusunąć je listy maszyn wirtualnych wraz z ich zasobami dyskowymi, usunąc ich pliki konfiguracyjne xml.

1
2
3
virsh destroy rustfs2${k} --graceful --remove-logs
virsh undefine rustfs2${k} --managed-save --remove-all-storage --delete-storage-volume-snapshots --snapshots-metadata
rm -rf rustfs2${k}.?.qcow2 rustfs2${k}.xml

Jak działa RustFS?

TODO

Artykuł opisujący działanie aplikacji na reaktywowanym blogu BigDataPassion

comments powered by Disqus
© 2026 BigDataLinux Built with Hugo | Theme Stack designed by Jimmy