Uvod
Kontejner je standardna jedinica softvera koja pakira kod i sve njegove ovisnosti tako da se aplikacija može brzo i pouzdano pokretati u različitim okruženjima. Oni "sjede" na fizičkom serveru i njegovom operacijskom sustavu i s njim dijele kernel. Slični su virtualnim strojevima (eng. virtual machines ) utoliko što su također virtualizirani sustavi.
Međutim, za razliku od virtualnih strojeva koji sadrže cijele operacijske sustave i sve ovisnosti koje im trebaju za izvršavanje zadanih operacija (te su zbog toga zahtjevne za resurse), kontejeri s hostom dijele kernel, te u sebi sadržavaju samo aplikacije, njihove ovisnosti i potrebne knjižnice (eng. library).
Slika 1: Hipervizor sjedi na fizičkom stroju i omogućuje kreiranje virtualnih strojeva. Svaki virtualni stroj ima svoj operacijski sustav, i zauzima određene resurse potrebne za pokretanje odvojenih OS-a. S druge strane, kontejneri su povezani s operacijskim sustavom fizičkog računala dijeleći njegov kernel i odvojene su samo aplikacije i njihove ovisnosti. Zbog toga kontejneri troše značajno manje resursa od virtualnih strojeva.
Apptainer
Apptainer je jedno od kontejnerskih rješenja. Glavna svojstva su mu:
- mobilnost
- reproducibilnost
- korisnička sloboda
- podrška za HPC
Mobilnost računanja omogućuje da se workflow definira u kontejneru za koji korisnik može biti siguran da će se moći izvršavati na različitim strojevima, neovisno o operacijskom sustavu (dok god je Linux) i infrastrukturi. Mobilnost je osigurana time što se Apptainer kontejneri spremaju u slike (eng. image) koje su jedna datoteka koja obuhvaća sve datoteke u kontejneru. Slike se mogu izgraditi kao read-only (zadano ponašanje) čime se osigurava dosljednost u ponovnom korištenju.
Korisnička sloboda se odnosi na mogućnost korisnika da unutar kontejnera instaliraju aplikacije s poželjnim verzijama i knjižnicama, neovisno o stanju na poslužitelju na kojem će taj kontejner kasnije pokretati. Dopremanjem kontejnera na bilo koji resurs, korisnici mogu koristiti aplikacije koje god žele.
Apptainer je kompatibilan s HPC-om. Podržava InfiniBand, ima podršku za MPI, radi bez problema s većinom raspoređivača poslova te ima podršku i za rad s GPU-ovima.
Korisnik unutar Apptainer kontejnera je isti onaj koji je i izvan kontejnera te ima jednake ovlasti unutar i izvan kontejnera. Ako se kontejner koristi na klasteru, korisnik ne može unutar kontejnera napredovati do root ovlasti te nema opasnosti da nehotično (ili namjerno) napravi štetu sustavu. Ako korisnik mora mijenjati kontejner, morat će to raditi na lokalnom računalu, na kojem ima root ovlasti, pa promijenjeni kontejner ponovno dopremiti na klaster.
Apptainer je vrlo jednostavan za korištenje. Koristi se kao bilo koja druga aplikacija (ne pokreće se servis kao npr. u slučaju Dockera - zato dobro radi s raspoređivačima poslova!).
Ima svega nekoliko osnovnih naredbi:
-
build
: naredba za izgradnju kontejnera -
exec
: naredba za izvršavanje naredbe u kontejneru -
inspect
: naredba za gledanje labela, runscripti, test scripti te varijabli okoline -
pull
: naredba za povlačenje slika sa Singularity ili Docker Huba -
run
: naredba za pokretanje slike kao izvršne datoteke -
shell
: naredba za pokretanje ljuske u kontejneru
Izgradnja kontejnera
build
može kreirati kontejnere u dva različita formata:
- image - temeljen na SquashFSu u formatu read-only
- sandbox - u formi direktorija, pogodni za interaktivnu modifikaciju kontejnera opcijom
--writable
Osim izgradnje, naredbom build
može se konvertirati između image i sandbox formata, ili izgraditi kontejnere iz Apptainer recepta zvanih definition files.
Izgradnja kontejnera iz Apptainer recepta preporuča se, jer tako osigurava dosljednost u ponovnom korištenju (svi koraci izgradnje kontejnera su sadržani u Apptainer receptu koji je vidljiv u kontejneru).
Apptainer recept se sastoji od dva glavna dijela:
Zaglavlje je obvezan dio recepta, dok su sekcije opcionalne. U zaglavlju se definira bazni OS koji se želi instalirati u kontejneru, a u sekcijama se navode svi ostali koraci koje želimo iskoristiti prilikom izgradnje kontejnera (npr. kopirati datoteke, instalirati softver, kreirati varijable okoline i sl.)
Slika 2: Workflow za izradu i korištenje kontejnera. Slika je preuzeta
sa stranice Singularitya; preteča Apptaineru koja funkcionira
na identičan način.
Apptainer recepti
Header
U headeru se definira bazni operacijski sustav koji će se koristiti u kontejneru. Osnovne ključne riječi su:
Bootstrap
- referencira tip baze koji će se koristitiFrom
- ime kontejnera (ili referenca na layere u slučaju Dockera) koji će se koristiti
Tip Bootstrap
baze može biti na primjer:
shub
- za slike koje su na Singularity Hubudocker
- za slike na Docker Hubulocalimage
- za slike spremljeno lokalno
Primjer za bazu shub
:
Bootstrap: shub From: vsoch/hello-world
Više informacija o Apptainer receptima dostupno je na službenim stranicama.
Sections
Nakon zaglavlja, izgradnja i namještanje okoline kontejnera zapisuje se u poglavljima. Neka od najvažnijh su:
- %files - dostavljanje datoteka u kontejner
- %post - izvršavanje komandi unutar kontejnera tijekom izgradnje
- %environment - definicija varijabli okoline unutar kontejnera tijekom izvršavanja (nakon njegove izgradnje)
- %runscript - zadane naredbe koje se izvršavaju korištenjem
apptainer run ...
ili direktnim izvršavanjem kontejnera
Primjer recepta sa službenih stranica napisan ispod u sebi će:
- izgraditi osnovni operativni sustav Ubuntu v22.04
- dostaviti datoteku
hello_world.txt
unutar kontejnera u/my_data/hello_world.txt
- osvježiti apt repozitorije i instalirati aplikacije
cowsay
ilolcat
- uključiti izvršne datotke
cowsay
ilolcat
iz/usr/games
u korisničku okolinu - definirati izvršnu naredbu
date | cowsay | lolcat
kao zadanu - definirati autora kontejnera
BootStrap: library From: ubuntu:22.04 %files hello_world.txt /my_data/hello_world.txt %post apt-get -y update apt-get -y install cowsay lolcat %environment export LC_ALL=C export PATH=/usr/games:$PATH %runscript date | cowsay | lolcat %labels Author GodloveD
Navedeni recept (npr. apptainer.def
) možemo izgraditi u image naredbom build
:
# izgradnja imagea korištenjem naredbe build [korisnik@kompjuter:~] $ apptainer build apptainer.sif apptainer.def ... INFO: Creating SIF file... INFO: Build complete: apptainer.sif # ispis detalja datoteke [korisnik@kompjuter:~] $ ls -l apptainer.sif -rwxr-xr-x 1 marko marko 83701760 svi 25 10:41 apptainer.sif
Korištenje javnih repozitorija
Proces izgradnje i nadogradnje kontejnera može se ubrzati korištenjem javnih repozitorija koji sadrže već testirane recepte (što je uostalom i svrha kontejnera) koji se mogu koristiti u receptima ili pri izgradnji sandbox kontejnera.
Neki od poznatijih repozitorija su:
- hub.docker.com - najpoznatija meka za kontejnere i obično prvi rezultat Google upita
- condaforge - kontejneri s već pripremljenim upraviteljima paketa conda
- Nvidia NGC - posvećeno svim aplikacijama koje koriste CUDU
- biocontainers.pro - posvećeno bioinformatici
Izgradnja na Supeku
U slučaju da niste u mogućnosti izgraditi kontejner na svojem osobnom računalu, pružamo mogućnost izgradnje kontejnera na pristupnom poslužitelju login-gpu.hpc.srce.hr
Pri izgradnji, treba pripaziti na sljedeće:
- graditi u direktoriju
/scratch
, koji nije dio Lustre dijeljenog datotečnog sustava - prebaciti kreirani image nazad u vaš korisnički direktorij, jer u protivnom neće biti vidljiv izvan pristupnog čvora
login-gpu.hpc.srce.hr
- nakon izgradnje obrisati sve kreirane datoteke
- pri sandbox izgradnji koristiti opciju fakeroot (jer korisnici nemaju sudo ovlasti)
Primjer sandbox izgradnje s dodatnim knjižnicama korištenjem Ubuntu v20.04 operativnog sustava:
# login na pristupni poslužitelj gpu [korisnik@kompjuter ~]$ ssh korisnik@login-gpu.hpc.srce.hr Last login: Wed May 24 09:23:06 2023 from x.x.x.x # pomicanje u /scratch i kreiranje direktorija za izgradnju [korisnik@x3000c0s27b0n0 ~]$ cd /scratch [korisnik@x3000c0s27b0n0 scratch]$ mkdir ${USER}-apptainer [korisnik@x3000c0s27b0n0 scratch]$ cd ${USER}-apptainer # izgradnja sandbox verzije [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ apptainer build ubuntu_20.04_sandbox docker://ubuntu:20.04 [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ apptainer shell --writable --fakeroot ubuntu_20.04_sandbox Apptainer> ... Apptainer> ... dodatne komande za izgradnju kontejnera ... Apptainer> ... Apptainer> exit # mijenjanje sanboxa u image, prebacivanje u korisnički i [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ apptainer build ubuntu_20.04.sif ubuntu_20.04_sandbox [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ mv ubuntu_20.04.sif ~ [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ cd ~ # brisanje direktorija za izgradnju [korisnik@x3000c0s27b0n0 korisnik-apptainer]$ rm -rf /scratch/${USER}-apptainer
Korištenje kontejnera
Kada jednom imamo gotov kontejner, postoji nekoliko naredbi za interagiranje s njim:
shell
- pokretanje korisničke ljuskeexec
- pokretanje naredberun
- pokretanje zadane naredbe
Naredbom shell
pokreće se ljuska unutar kontejnera, te se interagira s kontejnerom kao da je pokrenuta ljuska na malom virtualnom stroju.
# otvaranje ljuske [korisnik@kompjuter:~] $ singularity shell apptainer.sif ... # izvršavanje komande unutar kontejnera Apptainer> date | cowsay _______________________________ < Thu May 25 10:59:05 CEST 2023 > ------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || # izlaženje iz ljuske u kontejneru Apptainer> exit # izvršavanje iste komande izvan kontejnera [korisnik@kompjuter:~] $ date | cowsay bash: cowsay: command not found
Naredbom exec
izvršava se naredba unutar kontejnera:
# izvršavanje naredbe cowsay unutar kontejnera [korisnik@kompjuter:~] $ date | singularity exec apptainer.sif cowsay ... < čet, 25.05.2023. 11:05:46 CEST > -- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
Naredbom run
pokreće se kontejner pozivanjem runscripte definirane u Apptainer receptu.
# izvršavanje komandom run [korisnik@kompjuter:~] $ singularity run apptainer.sif ... < čet, 25.05.2023. 11:05:46 CEST > -- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || # direktno izvršavanje [korisnik@kompjuter:~] $ ./apptainer.sif ... < čet, 25.05.2023. 11:06:05 CEST > -- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
Podnošenje kontejnera na Supeku
U slučaju da se koristi Apptainer kontejner na Supeku, podnošenje poslova je jednako kao i u slučaju aplikacija koje su instalirane direktno na klasteru.
Na primjer, ako želimo pokrenuti kontejner apptainer.sif
nakon što ga dopremimo na Supek, minimalna skripta PBS apptainer-test.sh
bit će:
#!/bin/bash #PBS -N apptainer-test apptainer run apptainer.sif
Koju možemo podnijeti na sljedeći način i provjeriti njen izlaz nakon malo vremena:
# podnošenje skripte apptainer-test.sh [korisnik@x3000c0s25b0n0:~] $ qsub apptainer-test.sh # nakon par sekundi provjerimo sadržaj direktorija [korisnik@x3000c0s25b0n0:~] $ ls -l apptainer-test* -rw------- 1 mkvakic hpc 75 May 25 11:31 apptainer-test.e10537 -rw------- 1 mkvakic hpc 229 May 25 11:31 apptainer-test.o10537 -rw-r--r-- 1 mkvakic hpc 63 May 25 11:31 apptainer-test.sh # ispišemo sadržaj standardnog izlaza [korisnik@x3000c0s25b0n0:~] $ cat apptainer-test.o10537 _________________________________ < Thu May 25 09:31:17 Europe 2023 > --------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
MPI aplikacije u kontejneru
Apptainer podržava paralelizaciju i širenje na više čvorova korištenjem MPI standarda na dva načina:
- hybrid model - izvršavanje korištenjem MPI implementacije u kontejneru
- bind model - izvršavanje korištenjem MPI implementacije izvan kontejnera
Pri tom aplikacija koja koristi MPI mora biti ABI kompatibilna (MPICH verzija v3.1 nadalje). Način na koji se to inače postiže je dopremanjem knjižnice libmpi.so.12
putem varijable okoliša LD_LIBRARY_PATH
prije poziva aplikacije:
# postavljanje LD_LIBRARY_PATH [korisnik@kompjuter] $ export LD_LIBRARY_PATH=/putanja/do/libmpi.so.12:$LD_LIBRARY_PATH # izvršavanje aplikacijom mpiexec [korisnik@kompjuter] $ mpiexec -np 10 ./moja_ABI_kompatibilna_MPI_aplikacija
U slučaju kontejnera, varijable okoliša se uglavnom nasljeđuju od računala s kojeg se pokreće, no u ovom slučaju potrebno je dodatno namjestiti okolinu što se može učiniti na dva načina:
- korištenjem
--env
ili--env-file
opcije pri pokretanju kontejnera - namještanjem
APPTAINERENV_*
varijable okoliša prije pozivanja kontejnera
Na Supeku je potrebno je koristiti bind model, zbog knjižnica koje osiguravaju integraciju sa sustavom za upravljanje PBS i mrežom Slingshot. Moduli koji osiguravaju spajanje definicijom varijabli okoliša CRAY_LD_LIBRARY_PATH
i LD_LIBRARY_PATH
su:
-
cray-pals
- integracija s PBS-om cray-mpich-abi
- dostavljanje ABI kompatibilnih knjižnicacray-pmi
- knjižnica za spajanje s Crayevim sučeljem za pokretanje paralelnih programalibfabric
- mrežni API za spajanje na Slinghot
Dodatno, pri pozivu se moraju spojiti odgovarajući direktoriji u kontejner:
/opt
- putanja za knjižnice Cray/run
- putanja za PBS/usr/lib64
- putanja za sistemske knjižnice
Pri podnošenju posla na Crayu, to se može učiniti na sljedeći način (primjerice, u skripti PBS mpi-test.sh
) :
#!/bin/bash #PBS -N mpi-test #PBS -l select=2:ncpus=1 #PBS -l place=scatter # dopremanje modula module load PrgEnv-gnu module load cray-mpich-abi module load cray-pals module load cray-pmi module load libfabric # namještanje okolišne varijable LD_LIBRARY_PATH u kontejneru: # # 1) CRAY_LD_LIBRARY_PATH - Cray knjižnice iz /opt # 2) LD_LIBRARY_PATH - sistemske knjižnice iz /usr/lib64 # 3) \$LD_LIBRARY_PATH - očuvanje varijable ako već postoji u kontejneru # 4) /opt/cray/pe/pals/1.2.3/lib - putanja za PALS servis # APPTAINERENV_LD_LIBRARY_PATH="${CRAY_LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}:\$LD_LIBRARY_PATH:/opt/cray/pe/pals/1.2.3/lib" # izvršavanje kontejnera mpi-test.sif s aplikacijom mpiexec modula cray-pals mpiexec \ singularity exec \ --bind /opt \ --bind /run \ --bind /usr/lib64 \ mpi4py-install.sif \ /myapp/mpi-test
Gdje je su recept za izgradnju kontejnera mpi-test.sif
i aplikacija mpi-test.c
:
Osnovni operativni sustav kontejnera
Zbog bind model spajanja, potrebno je koristiti operativne sustave koji su slični operativnom sustavu Supeka Red Hat Enterprise Linux 8.6.
Neki od mogućih su:
Grafički procesori i CUDA
Apptainer pruža podršku za izvršavanje na grafičikim procesorima ako su aplikacije i kontejneri namijenjeni za njihovo korištenje.
Ova mogućnost jednostavno se ostvaruje korištenjem opcije --nv
pri izvršavanju kontejnera komandama exec
ili run
.
Ispod se nalazi primjer izgradnje kontejnera PyTorch v1.13.1 za duboko učenje i njegovo testiranje na pristupnom poslužitelju s grafičkim čvorovima:
# spajanje na pristupni poslužitelj [korisnik@kompjuter:~] $ ssh mkvakic@login-gpu.hpc.srce.hr # izgradnja pytorch kontejnera [korisnik@x3000c0s27b0n0:~] $ apptainer build pytorch_1.13.1.sif docker://pytorch/pytorch:1.13.1-cuda11.6-cudnn8-runtime # print raznih informacija [korisnik@x3000c0s27b0n0:~] $ apptainer run --nv ./pytorch_1.13.1.sif python -c "import torch; print('Is cuda available?:', torch.cuda.is_available())" Is cuda available?: True [korisnik@x3000c0s27b0n0:~] $ apptainer run --nv ./pytorch_1.13.1.sif python -c "import torch; print('Device count:', torch.cuda.device_count())" Device count: 1 [korisnik@x3000c0s27b0n0:~] $ apptainer run --nv ./pytorch_1.13.1.sif python -c "import torch; print('Current device:', torch.cuda.current_device())" Current device: 0 [korisnik@x3000c0s27b0n0:~] $ apptainer run --nv ./pytorch_1.13.1.sif python -c "import torch; print('Device name:', torch.cuda.get_device_name(0))" Device name: NVIDIA A100-PCIE-40GB