Superkompjuter u VirtualBox-u (SLURM) – deo III

Nakon što smo u prvom delu ovog bloga, pod nazivom Instalacija HPC klastera – priprema, objasnili instalaciju operativnog sistema, i svih ostalih komponenti neophodnih za jedan HPC klaster, dolazimo i do najbitnijeg dela. Čak i ukoliko ima ssh, nfs, najbolji operativni sistem, i najbržu mrežu, ni jedan HPC klaster ne može da funkcioniše bez raspoređivača posla. Svaki klaster gubi ulogu ukoliko nema neki raspoređivač posla, makar on bio i trivijalan, mora omogućavati korisniku da pokreće jedan program na većem broju računara. U daljem tekstu biće opisan postupak instalacije SLURM raspoređivača kao i način korišćenja.

Slurm raspoređivač posla

U prethodnom blogu smo uspešno povezali tri računara, postavili jedan računar kao HeadNode, a ostale kao Compute Node-ove, podesili smo mrežu, podesili im Network File Sysstem i obezbedili Passwordless SSH. Sada ćemo ovom klasteru instalirati raspoređivač posla, i time ga učiniti funkcionalnim za upotrebu i pokretanje paralelnih poslova.

Konfiguracija sistema

Pre nego što počnemo sa instalacijom Munge servisa, instaliraćemo MariaDB bazu podataka. Mi tu bazu ni u kom trenutku nećemo konkretno koristiti, ali je neophodna za instaliranje SLURM raspoređivača.

yum install mariadb-server mariadb-devel -y

Sada ćemo kreirati globalne usere koji će biti zajednički za svaki Node u sistemu. Zato, pre nego što krenemo u instalaciju bilo SLURM-a bilo Munge servisa na svakom node-u sistema uradićemo sledeće:

export MUNGEUSER=911 groupadd -g $MUNGEUSER munge useradd -m -c "MUNGE Uid 'N' Gid Emporium" -d /var/lib/munge -u $MUNGEUSER -g munge -s /sbin/nologin munge export SLURMUSER=912 groupadd -g $SLURMUSER slurm useradd -m -c "SLURM workload manager" -d /var/lib/slurm -u $SLURMUSER -g slurm -s /bin/bash slurm 

U slučaju da već postoje grupe koje imaju GID 911 i 912, možemo pokušati sa nekim drugim brojem između 500 i 1000. Sve grupe sa svojim GID možemo izlistati pozivom komande groups.

Munge instalacija

Munge predstavlja servis za autentifikaciju zadužen za kreiranje i validiranje kredencijala. Dizajniran je za HPC klastere, i omogućava veliku skalabilnost. A praktično, Munge omogućava jednom procesu da identifikuje UID ili GID nekog drugog procesa na istom ili drugom node-u iz grupe node-ova koji imaju zajedničke korisnike i grupe. Dakle baš ono što nam treba za razmenu procesa i informacija između node-ova, čega će često biti kod našeg klastera.

Sada krećemo sa instalacijom Munge servisa.

Za početak ćemo preuzeti sve neophodne pakete. yum install munge munge-libs munge-devel -y

Kako bismo bili sigurni da su paketi koje preuzimamo poslednje verzije istih, pre ove komande poželjno bi bilo preuzeti poslednju verziju epel repozitorijuma.

yum install epel-release

Obe komande izvršićemo na svim node-ovima.

Kako bismo nastavili potrebno je da generišemo ključ koji će služiti za autentifikaciju među procesima, što i jeste svrha ovog servisa, kao što smo i naveli nedavno. Kreiranje ključa vršiće se isključivo na serveru, on će kasnije te ključeve podeliti ostalim čvorovima u sistemu. Prvo moramo preuzeti rng alat.

yum install rng-tools -y rngd -r /dev/urandom

Nakon toga kreiraćemo ključ

/usr/sbin/create-munge-key -r dd if=/dev/urandom bs=1 count=1024 > /etc/munge/munge.key chown munge: /etc/munge/munge.key chmod 400 /etc/munge/munge.key

Sledeći deo podrazmeva podelu klučeva ostalim korisnicima. Prilikom podele javnog ključa kod instalacije Passwordless ssh koristili smo NFS kako bismo omogućili svim korisnicima da dobiju javni ključ. Sada ćemo koristiti scp. Kako bismo iskoristili ssh koji smo konfigurisali u nekom od prethodnih koraka, sada ćemo koristiti upravo alat koji je zasnovan na ssh protokolu. Scp ili Secure Copy

scp /etc/munge/munge.key root@Node1:/etc/munge scp /etc/munge/munge.key root@Node2:/etc/munge

Prvi argument komande scp predstavlja lokaciju sa koje želimo da kopiramo sadržaj, dok drugi argument predstavlja odredište.

Sada moramo na dva compute čvora, promeniti prava pristupa.

chown -R munge: /etc/munge/ /var/log/munge/ chmod 0700 /etc/munge/ /var/log/munge/

I nakon toga konačno pokrenuti munge servis.

systemctl enable munge
systemctl start munge

Sada je Munge servis startovan i u funkciji je.

SLURM instalacija

SLURM predstavlja raspoređivač koji je, kao i Munge, skalabilan i može se primenjivati i kod manjih i kod većih Linux sistema. Osnovne tri funkcije SLURM-a jesu alociranje resursa, odnosno u našem slučaju compute node-ova, pružanje framework-a za startovanje, pokretanje, praćenje i prekidanje paralelnih poslova, i konačno, vođenje evidencije o redu poslova, i dodeljivanje istih node-ovima u zavisnosti od njihovih resursa.

Na slici, možemo videti da SLURM predstavlja centralni deo našeg HPC klastera. Zadužen je za upravljanje resursima i kontrolu poslova, što kao što smo i pomenuli malopre jesu njegove osnovne funkcije.

Za početak moramo skinuti sve pakete koji su neophodni za instalaciju. Pošto smo prilikom instalacije Munge servisa preuzeli i najnoviju verziju EPEL repozitorijuma, možemo biti sigurni da preuzimamo najnovije verzije paketa.

yum install openssl openssl-devel pam-devel numactl numactl-devel hwloc hwloc-devel lua lua-devel readline-devel rrdtool-devel ncurses-devel man2html libibmad libibumad -y

Sada ćemo preuzeti poslednju verziju SLURM-a. Paket koji preuzimamo smestićemo u neki deljeni direktorijum. Iskoristićemo baš direktorijum koji smo pravili prilikom testiranja NFS-a. Ono što moramo dodatno da uradimo jeste instalacija rpmbuilda. Rpmbuild je alat koji u stvari vrši instalaciju samog SLURM-a.

Dakle, prvo ćemo preuzeti i instalirati rpmbuild.

yum install rpm-build

Nakon toga preuzećemo u poslednju aktuelnu verziju SLURM-a. Preteći zvaničnu dokumentaciju SLURM-a možemo uočiti da je to verzija 17.02.7.

Prvo se pozicionirajmo u deljeni direktorijum u koji želimo da preuzmemo SLURM

cd /nfsshare

A nakon toga i preuzmimo SLURM.

wget http://www.schedmd.com/download/latest/slurm-15.08.9.tar.bz2

i izvršimo build.

rpmbuild -ta slurm-17.02.7.tar.bz2

Dva odgovora koja možemo dobiti po pokretanju ove komande jesu da je uspešno izvršena ili da je došlo do greške. Ukoliko je došlo do greške instaliraćemo još jedan paket, koji se zove cpanm.

yum install cpanm

I sada ponovo pokrenimo rpmbuild -ta slurm-17.02.7.tar.bz2.

Ukoliko u direktorijumu /root/rpmbuild/RPMS/x86_64 postoje određeni rpms-ovi, znači da je rpmbuild uspešno završio svoj posao. Kako bi svi čvorovi imali rpms-ove neophodne za instalaciju SLURM-a unutar našeg /nfsshare direktorijuma kreiraćemo slurm-17.02 direktorijum u okviru koga ćemo smestiti sve ove rpms-ove. Pošto je direktorijum /nfsshare deljen, biće i svi njegovi poddirektorijumi.

Sada ćemo kopirati sve rpms-ove iz direktorijuma /root/rpmbuild/RMPS/x86_64.

Pozicionirajmo se i direktorijum /root/rpmbuild/RPMS/x86_64cd /root/rpmbuild/RPMS/x86_64

I sada ćemo kopirati sve neophodne rpms-ove

cp slurm-17.02.7-1.el7.centos.x86_64.rpm slurm-devel-17.02.7-1.el7.centos.x86_64.rpm slurm-munge-17.02.7-1.el7.centos.x86_64.rpm slurm-perlapi-17.02.7-1.el7.centos.x86_64.rpm slurm-plugins-17.02.7-1.el7.centos.x86_64.rpm slurm-torque-17.02.7-1.el7.centos.x86_64.rpm slurm-sql-17.02.7-1.el7.centos.x86_64.rpm slurm-contribs-17.02.7-1.el7.centos.x86_64.rpm slurm-pam_slurm-17.02.7-1.el7.centos.x86_64.rpm slurm-openlava-17.02.7-1.el7.centos.x86_64.rpm slurm-lua-17.02.7-1.el7.centos.x86_64.rpm /nfsshare/slurm-17.02

Sada, pošto svaki čvor vidi ove rpms-ove, na svakom ćemo morati i da ih instaliramo. Na sva tri čvora pokrenućemo komandu.

yum --nogpgcheck localinstall slurm-17.02.7-1.el7.centos.x86_64.rpm slurm-devel-17.02.7-1.el7.centos.x86_64.rpm slurm-munge-17.02.7-1.el7.centos.x86_64.rpm slurm-perlapi-17.02.7-1.el7.centos.x86_64.rpm slurm-plugins-17.02.7-1.el7.centos.x86_64.rpm slurm-torque-17.02.7-1.el7.centos.x86_64.rpm slurm-sql-17.02.7-1.el7.centos.x86_64.rpm slurm-contribs-17.02.7-1.el7.centos.x86_64.rpm slurm-pam_slurm-17.02.7-1.el7.centos.x86_64.rpm slurm-openlava-17.02.7-1.el7.centos.x86_64.rpm slurm-lua-17.02.7-1.el7.centos.x86_64.rpm

Konfigurisanje SLURM-a

Ono što moramo uraditi pre nego što pokrenemo čak i najtrivijalniji primer paralelnog programa jeste konfigurisanje SLURM-a. Za konfiguraciju samog slurma zadužen je konfiguracioni fajl slurm.conf. On će biti smešten u direktorijum /etc/slurm/ na svakom od čvorova, i ono što treba napomenuti jeste da mora biti isti na svakom čvoru. Ukoliko nije takva situacija, SLURM neće raditi. Za početak datoteku slurm.conf ćemo kreirati na HeadNode-u a zatim je podeliti ostalima.

Na adresi http://slurm.schedmd.com/configurator.easy.html možemo pronaći formu za kreiranje ovakvog jednog fajla. Kada potvrdimo kreiranje datoteke, dobićemo konfiguracioni fajl kakav smo želeli.

Ono što je bitno navesti prilikom kreiranja konfiguracionog fajla jeste hostname svih mašina koje učestvuju u sistemu, bile one glavni čvor ili compute čvor. Opciono je da li ćemo navesti adrese svih čvorova sistema, ali poželjno je postaviti i to. Moramo kreirati datoteku slurm.conf u direktorijumu /etc/slurm i time postaviti konfiguracionu datoteku kojom ćemo definisati ponašanje SLURM-a.

Dakle, vi /etc/slurm/slurm.conf.

Prekopiraćemo ceo sadržaj koji smo preuzeli, pri čemu možemo izvršiti izmene po želji. Primer konfiguracionog fajla koji ćemo mi koristiti dat je u nastavku.

# slurm.conf file generated by configurator easy.html. # Put this file on all nodes of your cluster. # See the slurm.conf man page for more information. # ControlMachine=HeadNode ControlAddr=10.0.0.1 # #MailProg=/bin/mail MpiDefault=none #MpiParams=ports=#-# ProctrackType=proctrack/pgid ReturnToService=2 SlurmctldPidFile=/var/run/slurmctld.pid SlurmctldPort=6817 SlurmdPidFile=/var/run/slurmd.pid SlurmdPort=6818 SlurmdSpoolDir=/var/spool/slurmd SlurmUser=slurm #SlurmdUser=root StateSaveLocation=/var/spool/slurmctld SwitchType=switch/none TaskPlugin=task/none # # # TIMERS #KillWait=30 #MinJobAge=300 #SlurmctldTimeout=120 #SlurmdTimeout=300 # # # SCHEDULING FastSchedule=1 SchedulerType=sched/backfill #SchedulerPort=7321 SelectType=select/linear # # # LOGGING AND ACCOUNTING AccountingStorageType=accounting_storage/none ClusterName=kdcluster #JobAcctGatherFrequency=30 JobAcctGatherType=jobacct_gather/none #SlurmctldDebug=3 SlurmctldLogFile=/var/log/slurmctld.log #SlurmdDebug=3 SlurmdLogFile=/var/log/slurmd.log # # # COMPUTE NODES NodeName=Node1 NodeAddr=10.0.0.2 CPUs=1 State=UNKNOWN NodeName=Node2 NodeAddr=10.0.0.3 CPUs=1 State=UNKNOWN PartitionName=debug Nodes=Node[1,2] Default=YES MaxTime=INFINITE State=UP 

Sada moramo konfiguraciju podeliti i ostalim čvorovima sistema. Na glavnom čvoru pokrenućemo sledeće komande

scp /etc/slurm/slurm.conf root@Node1/etc/slurm/slurm.conf scp /etc/slurm/slurm.conf root@Node2/etc/slurm/slurm.conf

Moramo izvršiti i ostala podešavanja na čvorovima i kreirati neophodne fajlove.

Na serveru ćemo kreirati log fajlove, kako bismo lakše pratili rad našeg SLURM sistema i reagovali ukoliko dođe do greške.

mkdir /var/spool/slurmctld chown slurm: /var/spool/slurmctld chmod 755 /var/spool/slurmctld touch /var/log/slurmctld.log chown slurm: /var/log/slurmctld.log touch /var/log/slurm_jobacct.log /var/log/slurm_jobcomp.log chown slurm: /var/log/slurm_jobacct.log /var/log/slurm_jobcomp.log

Sada ćemo slična podešavanja izvršiti i na ostalim čvorovima.

mkdir /var/spool/slurmd chown slurm: /var/spool/slurmd chmod 755 /var/spool/slurmd touch /var/log/slurmd.log chown slurm: /var/log/slurmd.log

Ono što se može primetiti jeste da nisu isti nazivi niti broj log fajlova na HeadNode-u i na ostalim čvorovima. Razlog leži upravo u tome što će na HeadNode-u biti pokrenut jedan servis, servis controller, odnosno slurmctld, a na Compute čvorovima klijent servis, odnosno slurmd.

Kako bi nam SLURM uspešno radio moramo stopirati firewall na compute node-ovima, i omogućiti pojedine portove koje SLURM koristi na HeadNode-u

systemctl stop firewalld
systemctl disable firewalld

firewall-cmd --permanent --zone=internal --add-port=6817/udp firewall-cmd --permanent --zone=internal --add-port=6817/tcp firewall-cmd --permanent --zone=internal --add-port=6818/udp firewall-cmd --permanent --zone=internal --add-port=6818/tcp firewall-cmd --permanent --zone=internal --add-port=7321/udp firewall-cmd --permanent --zone=internal --add-port=7321/tcp firewall-cmd --reload

Sada ćemo konačno startovati servise.

Na HeadNode-u

systemctl enable slurmctld.service
systemctl start slurmctld.service
systemctl status slurmctld.service

i na ostalim čvorovima

systemctl enable slurmd.service
systemctl start slurmd.service
systemctl status slurmd.service

Moramo biti posebno pažljivi jer kao što se da primetiti ne startuje se isti servis na svim čvorovima.

Ukoliko prilikom startovanja servisa naiđemo na neki problem možemo svakog trenutka proveriti sistemske logove.

Ha klijenskim cvorovima tail /var/log/slurmd.log

Na serverskom cvoru tail /var/log/slurmctld.log

Kao što smo pomenuli u zavisnosti od toga koji čvor proveravamo razlikovaće nam se log fajlovi.

Prilikom startovanja slurmctld servisa na HeadNode-u prvi put vrlo verovatno će doći do greške, a razlog te greške jeste nedostatk odgovarajućeg pid fajla. rešenje jeste njegovo kreiranje.

cd /var/run/
touch slurmctld.pid

Komanda scontrol show nodes nam daje spisak svih compute node-ova. Ukoliko su, u našem slučaju dva čvora, u stanju IDLE, možemo pokrenuti posao.

Najtrivijalniji posao koji možemo pokrenuti jeste

srun -N2 /bin/hostname

Poslovi se naravno pokreću na kontrolnom čvoru, u našem slučaju HeadNode-u, i odgovor koji bismo trebali da dobijemo jeste

Node1 Node2

Redosled ispisa ne mora biti isti prilikom svakog narednog pokretanja

Na adresi http://www.sdsc.edu/~hocks/FG/PBS.slurm.htm možemo videti SLURM komande, kao i razliku u odnosu na pbs/Torque komande.

OpenMPI

OpenMPI predstavalja Message Passing Interface(otuda MPI). Koristi se za razmenjivanje poruka programa u izvršavanju i stoga je pogodna za pisanje paralelnih programa. Bez MPI-a, u našem slučaju OpenMPI-a naš klaster ne bi mogao da dostigne svoj pun potencijal.

Za početak ćemo sa adrese https://www.open-mpi.org/software/ompi/v2.1/ preuzeti poslednju verziju OpenMPI-a koristeći HeadNode. Preuzetu datoteku smestićemo u deljeni direktorijum. Neka to kao i u prethodnom slučaju bude direktorijum /nfsshare. I zatim pokrenuti komandu za ekstrakciju.

tar -xvf openmpi-2.1.1.tar.gz

Nakon toga instaliraćemo neophodne C kompajlere na sva tri čvora

yum install gcc gcc-c++ kernel-devel -y

U deljenom direktorijumu /nfsshare ćemo kreirati direktorijum u koji ćemo smestiti već iskompajlirane openmpi biblioteke i pakete.

mkdir /nfsshare/ompii

Sada ćemo pokrenuti instalaciju.

cd /nfsshare/openmpi-2.1.1
./configure --prefix=/nfsshare/ompii

Nakon toga pokrenućemo još dve komande

make
make install

Trenutno nećemo biti u mogućnoosti da koristimo ni jednu mpi komandu, razlog ovoga jeste što ne postoji globalna promenljiva koja će čuvati podatke o tome gde se nalaze komande mpi-a. Ta promenljiva već postoji na svim Linux sistemima i naziva se PATH, i toj promenljivoj, koja već sadrži niz nekih vrednosti, moraćemo da dodamo još jednu a to je putanja do naših MPI komandi. Postoje tri načina da se tako nešto uradi.

Prvi podrazumeva pozivanje komande export PATH=/nfsshare/ompii/bin:$PATH

Na ovaj način mi smo izvršili konkatenaciju naše putanje, sa putanjama koje već postoje u promenljivoj PATH. A nakon toga moramo izvršiti i komandu source ~/.bashrc. Ovo se mora izvršiti na svakom računaru za svakog korisnika. Jasno nam je da ovakav način nije pogodan, i stoga ga nećemo uzeti u razmatranje.

Drugi način podrazumeva dodavanje linije export PATH=/nfsshare/ompii/bin:$PATH na sam kraj datoteke ~/.bashrc. Ovo se mora izvršiti na svim mašinama, i nakon toga se mora ponovo učitati datoteka ~/.bashrcsource ~/.bashrc. Shvatićete, dosta bolje rešenje.

I treći način koji ćemo mi koristiti, jeste izmena datoteke /etc/profile. U ovu datoteku smestićemo putanju do naših MPI komandi

pathmunge /nfsshare/ompii/bin

Ova datoteka se mora na isti način izmeniti na svim čvorovima. Nakon toga izvršićemo reboot sistema. Kada se sistem podigne pozivanjem komande which mpirun na bilo kom od računara dobićemo odgovor koji predstavlja putanju do naših MPI komandi

/nfsshare/ompii/bin/mpirun

Sada možemo pokrenuti neki program

salloc -N 2 sh

mpirun mpiapp

Na ovaj način pokrenuli smo program na dva čvora od kojih će svaki dodatno pokrenuti po jedan proces. Mi smo, u konfiguracionom fajlu definisali da će svaki čvor imati po jedan procesor i stoga je to u redu, problem se javlja kada poželimo da pokrenemo više od dva procesa. Ukoliko, sa ovakvim stanjem konfiguracije i sistema pokušamo nešto poput salloc -N 4 sh sistem će nas obavestiti kako nemamo dovoljno resursa. Stoga, pristupamo izmeni odgovarajućeg konfiguracionog fajla, ukoliko u konfiguracionom fajlu navedemo da nam broj CPUs-a bude veći od jedan, navedemo broj Socketa, CoresPerSocket i ThreadsPerCore, pri čemu mora važiti da je num(Socket)num(CoresPerSocket)num(ThreadsPerCore)=num(CPU) rešićemo problem i sebi obezbediti maksimalan broj procesa koji možemo pokrenuti, u vrednostu od max=CPU(Node1)+CPU(Node2). Primeri izmenjenog konfiguracionog fajla dat je u nastavku.

Osim toga, gledajući trenutnu konfiguraciju, mi ne možemo uticati na prioritet i na sam odabir narednog posla. Kako bismo to promenili moraćemo da promenimo deo koji se tiče algoritma izbora narednog posla, ukoliko ne podesimo ništa ostaće već postojeća podešavanja, a ona kažu da se posao bira metodom „priority/basic“, promenom tog metoda možemo uticati na odabir narednih poslova. Ukoliko postavimo da metod bude „priority/multifactor“ obezbedićemo da na odabir narednog posla utiču same vrednosti posla, kao što su ko ga je pokrenuo, previđeno vreme izvršavanja i ostalo. Ove vrednosti biće pomnožene sa odgovarajućim koeficijentima koje mi definišemo u konfiguracionom fajlu, i na taj način mi sami dajemo važnost određenim osobinama posla. Stoga ćemo dodatno izmeniti konfiguracioni fajl, kako zbog potrebe pokretanja posla na većem broju procesora, tako i zbog samog prioriteta posla.

# slurm.conf file generated by configurator easy.html. # Put this file on all nodes of your cluster. # See the slurm.conf man page for more information. # ControlMachine=HeadNode ControlAddr=10.0.0.1 # #MailProg=/bin/mail MpiDefault=none #MpiParams=ports=#-# ProctrackType=proctrack/pgid ReturnToService=2 SlurmctldPidFile=/var/run/slurmctld.pid SlurmctldPort=6817 SlurmdPidFile=/var/run/slurmd.pid SlurmdPort=6818 SlurmdSpoolDir=/var/spool/slurmd SlurmUser=slurm #SlurmdUser=root StateSaveLocation=/var/spool/slurmctld SwitchType=switch/none TaskPlugin=task/none # # # TIMERS #KillWait=30 #MinJobAge=300 #SlurmctldTimeout=120 #SlurmdTimeout=300 # # # SCHEDULING FastSchedule=1 SchedulerType=sched/backfill #SchedulerPort=7321 SelectType=select/linear # #JOB PRIORITY PriorityFlags= SMALL_RELATIVE_TO_TIME PriorityType=priority/multifactor PriorityDecayHalfLide=14-0 PriorityCalcPeriod=5 PriorityMaxAge=14-0 PriorityUsageResetPeriod=NONE PriorityWeightAge=10000 PriorityWeightFairshare=10000 PriorityWeightJobSize=100000 PriorityWeightPosition=0; PriorityWeightQOS=100000 # # LOGGING AND ACCOUNTING AccountingStorageType=accounting_storage/none ClusterName=kdcluster #JobAcctGatherFrequency=30 JobAcctGatherType=jobacct_gather/none #SlurmctldDebug=3 SlurmctldLogFile=/var/log/slurmctld.log #SlurmdDebug=3 SlurmdLogFile=/var/log/slurmd.log # # # COMPUTE NODES NodeName=Node1 NodeAddr=10.0.0.2 Sockets=2 CPUs=8 CoresPerSocket=4 ThreadsPerCore=1 State=UNKNOWN NodeName=Node2 NodeAddr=10.0.0.3 Sockets=2 CPUs=8 CoresPerSocket=4 ThreadsPerCore=1 State=UNKNOWN PartitionName=debug Nodes=Node[1,2] Default=YES MaxTime=INFINITE State=UP 

Konačno, uspeli smo da prikažemo ceo put kreiranje klaster, od instaliranja operativnog sistema, pa sve do pokretanja mpi programa. Koristili smo softver koji je u velikoj meri skalabilan i stoga se ovo može primeti i na sisteme sa dosta većim brojem računara.

Literatura

  • https://www.slothparadise.com/blog/
  • https://www.centos.org
  • https://slurm.schedmd.com/