--- layout: default --- ## Preliminari In più casi dovremo eseguire uno script su tutte i nodi, per farlo possiamo utilizzare il seguente script `runsetup.sh`: ```bash #!/bin/bash # Our custom function file=$1 cust_func(){ echo "I am ${url}" scp $file root@$url:/root/$file ssh root@$url chmod +x /root/$file NUMBER=$(echo $url | tr -dc '0-9') ssh root@$url /root/$file $NUMBER } while IFS= read -r url do cust_func "$url $file" & done < list.txt wait echo "All commands have been run." ``` seguito dal nome `script.sh` che vogliamo eseguire su tutte le macchine, e.g., ```bash ./runsetup.sh script.sh ``` ## Script di configurazione iniziale del nodo Script `runsetup.sh` utilizzato per installare le macchine: ```bash #!/bin/bash mkdir /scratch chown -R rock:rock /home/rock # Don't ask for anything export DEBIAN_FRONTEND=noninteractive # Cambia il fuso orario timedatectl set-timezone Europe/Rome # Fixa la chiave pubblica delle repository (da https://forum.radxa.com/t/gpg-error-with-ubuntu-server-20-04/13392) wget -O - apt.radxa.com/focal-stable/public.key | sudo apt-key add - # Repository aggiuntive add-apt-repository ppa:gluster/glusterfs-7 -y # Update & Upgrade apt update -y && apt upgrade -y # Install required packages apt -y install build-essential gcc openmpi-bin openmpi-common libopenmpi-dev glusterfs-server slurm python3-pip valgrind tree git curl man-db mc parallel neovim unrar atool ``` e che può essere eseguito come: ```bash ./runsetup.sh script.sh ``` ## Personalizzare la shell di login sul Nodo 0 Possiamo personalizzare il messaggio che appare al login sul nodo zero creando il seguente script `/etc/update-motd.d/05-info`: ```bash #! /usr/bin/env bash export TERM=xterm-256color # Basic info HOSTNAME=$(uname -n) ROOT=$(df -Ph | grep mmcblk0p5 | awk '{print $4}' | tr -d '\n') IFS=. read -r s _ < /proc/uptime; d=$((s / 60 / 60 / 24)); h=$((s / 60 / 60 % 24)); m=$((s / 60 % 60)); [ "$d" = 0 ] || UPTIME="${UPTIME}${d}d "; [ "$h" = 0 ] || UPTIME="${UPTIME}${h}h "; [ "$m" = 0 ] || UPTIME="${UPTIME}${m}m "; UPTIME="${UPTIME:-0m}" KERNEL=$(uname -r) RAID=$(lsblk -b -n -d | awk '$NF!~/sd[a-z]$/ && $NF!~/md[0-9]+$/ && !/loop/ {sum+=$4} END {printf "%.0f", sum/2/1024/1024/1024}') TEMP_BIG="$(paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | column -s $'\t' -t | sed 's/\(.\)..$/.\1°C'/ | head -1| cut -d' ' -f3 )" TEMP_LITTLE="$(paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | column -s $'\t' -t | sed 's/\(.\)..$/.\1°C/'| tail -1| cut -d' ' -f3 )" # System load MEMORY1=`free -t -m | grep Total | awk '{print $3" MB";}'` MEMORY2=`free -t -m | grep "Mem" | awk '{print $2" MB";}'` LOAD1=`cat /proc/loadavg | awk {'print $1'}` LOAD5=`cat /proc/loadavg | awk {'print $2'}` LOAD15=`cat /proc/loadavg | awk {'print $3'}` echo "$(tput setaf 1)=================================================== _______________________ _______ _______ _______ _ ( ____ \__ __( ____ ( ____ ( ____ ( ____ ( ) | ( \/ ) ( | ( \/ ( \/ ( \/ ( \// | (_____ | | | (__ | (__ | (__ | (__ (_____ ) | | | __) | __) | __) | __) ) | | | | ( | ( | ( | ( /\____) | | | | (____/\ ) | ) | (____/ \_______) )_( (_______// |/ (_______/ $(tput setaf 2) =================================================== - Hostname............: $HOSTNAME - Disk Space..........: $ROOT remaining - RAID Space..........: $RAID GB remaining $(tput setaf 4)=================================================== - CPU usage...........: $LOAD1, $LOAD5, $LOAD15 (1, 5, 15 min) - Memory used.........: $MEMORY1 / $MEMORY2 $(tput setaf 5)=================================================== - Temperature big.....: $TEMP_BIG - Temperature little..: $TEMP_LITTLE $(tput setaf 3)=================================================== - Kernel..............: $KERNEL - Uptime..............: $UPTIME $(tput sgr0)===================================================" ``` ## `dnsmasq` e rete interna `dnsmasq` è un *software libero* che fornisce funzionalità di memorizzazione nella cache DNS (Domain Name System), un server DHCP (Dynamic Host Configuration Protocol), router advertisement e funzionalità di avvio di rete, destinato a reti di computer di piccole dimensioni. Nel nostro caso è utilizzato come server DHCP per assegnare gli indirizzi ai nodi del cluster sulla rete interna (NAT) e offrire un servizio di DNS (nodi raggiungibili tramite il loro nome e non tramite il loro indirizzo IP). ### Configurazione dnsmasq Per lanciare questo servizio è necessario liberare la porta 53 da eventuali servizi che la occupino già, su Ubuntu questo vuol dire disabilitare `systemd-resolved`. ```bash sudo systemctl disable --now systemd-resolved sudo apt install dnsmasq ``` impostare nel suo file di configurazione la funzione di DHCP de-commentando la riga `dhcp-range` nel file `/etc/dnsmasq.conf`, e finalmente lanciare il servizio: ```bash sudo systemctl enable --now dnsmasq ``` ### Configurazione rete interna (NAT) Per avere il funzionamento del nostro **guarded Beowulf**, abbiamo bisogno che il **nodo 0**, nodo di accesso, sia equipaggiato di due schede di rete. Una sarà connessa verso l'esterno, rendendo quindi il nodo un *frontend* per gli utenti, l'altra verso tutti i nodi del cluster. Dal punto di vista operativo, questo vuol dire che un *pacchetto* in arrivo dall'esterno dovrà essere tradotto di indirizzo per raggiugere i nodi interni della rete. Nell'ambito delle reti questa funzione è svolta dal **network address translation** (NAT), ovvero il meccanismo che permette proprio di modificare l'indirizzo IP dei pacchetti in transito attraverso un genrico apparato di rete - il nostro *nodo 0* - all'interno di una comunicazione in corso tra un utente e gli altri nodi del cluster. Su Ubuntu questo può essere fatto tramite il programma `iptables`: ```bash sudo apt install iptables echo "1" | sudo tee /proc/sys/net/ipv4/ip_forward cd /etc/sysctl.d/ echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/10-ip-forwarding.conf ``` In `/etc/network/interfaces`, per configurare permanentemente l'IP statico della macchina all'interno della LAN, l'IP pubblico e per creare la NAT del cluster: ```interfaces auto eth0 iface eth0 inet static address 192.168.0.2 netmask 255.255.255.0 auto enxd03745888a34 iface enxd03745888a34 inet static address 131.114.10.121 netmask 255.255.255.0 gateway 131.114.10.1 post-up /usr/sbin/iptables -t nat -A POSTROUTING -o enxd03745888a34 -s 192.168.0.0/24 -j MASQUERADE ``` Infine: ```bash sudo systemctl restart dnsmasq sudo reboot ``` Dobbiamo inoltre comunicare il DNS a tutti i nodi in modo che possano risolvere le connessioni tra loro, ad esempio creando lo script `fixdns.sh`: ```bash sudo echo "nameserver 192.168.0.2" >> /etc/resolvconf/resolv.conf.d/head sudo ln -sf /run/resolvconf/resolv.conf /etc/resolv.conf sudo resolvconf -u ``` ed eseguendo ```bash ./runsetup.sh fixdns.sh ``` ## GlusterFS Creiamo la cartella che conterrà le home condivise in **tutti i nodi** e attiviamo il servizio GlusterFS: ```bash sudo mkdir /data${i} systemctl enable --now glusterd ``` Per installare GlusterFS dobbiamo per prima cosa permettere le connessioni dagli altri nodi attraverso il Firewall: ```bash for i in {1..20}; do sudo iptables -I INPUT -p all -s steffe$i -j ACCEPT; done; ``` Ora dobbiamo far riconoscere i nodi tra di loro ```bash sudo gluster peer probe steffe0 for i in {1..20}; do sudo gluster peer probe steffe${i}; done; ``` e creare il volume condiviso: ```bash sudo gluster volume create data replica 3 transport tcp steffe0:/data0 steffe1:/data1 steffe2:/data2 steffe3:/data3 steffe4:/data4 steffe5:/data5 steffe6:/data6 steffe7:/data7 steffe8:/data8 steffe9:/data9 steffe10:/data10 steffe11:/data11 steffe12:/data12 steffe13:/data13 steffe14:/data14 steffe15:/data15 steffe16:/data16 steffe17:/data17 steffe18:/data18 steffe19:/data19 steffe20:/data20 force sudo gluster volume start data sudo gluster volume info ``` Possiamo quindi montare i dischi facendo ```bash mkdir -p /mnt/data mount -t glusterfs steffe0:data /mnt/data ``` (da mettere poi in `/etc/fstab` come `steffe0:/data /mnt/data glusterfs defaults,_netdev 0 0`) ## Slurm Workload Manager Slurm Workload Manager, precedentemente noto come Simple Linux Utility for Resource Management (SLURM), o semplicemente **Slurm**, è un job scheduler gratuito e open source per kernel Linux e Unix-like, utilizzato da molti dei supercomputer e cluster di computer del mondo. Fornisce tre funzioni fondamentali: - assegnazione di accesso esclusivo e/o non esclusivo ai *nodi* di calcolo agli utenti per un certo periodo di tempo in modo che possano eseguire i loro *job*, - fornire un framework per l'**avvio**, l'**esecuzione** e il **monitoraggio** dei *job* che contengono (in genere) istruzioni parallele di tipo MPI sull'insieme di nodi allocati, - arbitrare la "contesa" per le risorse gestendo una coda di lavori in sospeso. Per prima cosa dobbiamo installare *Slurm* su tutti i nodi del cluster ```bash sudo apt-get update -y sudo apt-get install slurmd slurmctld -y ``` Generare un file di configurazione mediante il [configuratore online](https://slurm.schedmd.com/configurator.html) e inserirne il contenuto in ```bash /etc/slurm/slurm.conf ``` Al termine della configurazione avviare il servizio: ```bash sudo systemctl enable --now slurmctld sudo systemctl enable --now slurmd ``` ### Raid Per controllare lo stato del raid, utilizzare ``` cat /proc/mdstat ``` ### NFS Sul control node: ``` sudo apt install nfs-kernel-server ``` Configurare `/etc/exports` come desiderato, ad esempio ``` /mnt/raid steffe1(rw,sync,no_root_squash,no_subtree_check) ... ``` e poi `sudo systemctl restart nfs-kernel-server.service` Sui compute nodes: ``` mkdir -p /mnt/raid mount -t nfs steffe0:/mnt/raid /mnt/raid ``` (da mettere poi in `/etc/fstab` come `steffe0:/mnt/raid/ /mnt/raid nfs auto,nofail,noatime,nolock,intr,tcp,actimeo=1800 0 0`) ### Creazione utenti Affinché un programma possa essere lanciato su tutti i nodi è necessario che l'**utente** sia disponibile su ciascuno di essi, il seguente script si occupa di replicare l'utente ovunque sia necessario: ```bash #!/bin/bash # # Add a SLURM user to the Steffè cluster # A good place for this script is in: # /usr/local/bin/cluster-users set -e cluster_hosts="steffe1 steffe2 steffe3 steffe4 steffe5 steffe6 steffe7 steffe8 steffe9 steffe10 steffe11 steffe12 steffe13 steffe14 steffe15 steffe16 steffe17 steffe18 steffe19 steffe20" function help { echo "Usage: $0 COMMAND username" echo "" echo "Examples: " echo " -) $0 --add utente" echo " -) $0 --delete utente" } function add_user { if [ "$1" == "" ]; then echo "Specify a valid username for the new user" exit 1 fi if [ "$2" != "" ]; then echo "Unsupported option specified" exit 1 fi sudo mkdir -p /mnt/raid/home sudo adduser --home=/mnt/raid/home/$1 $1 # We obtain the UID of the new user, as the last line at the end # of passwd userid=$(grep $1 /etc/passwd | tail -n1 | cut -d ':' -f3) for h in ${cluster_hosts}; do echo -n "Creating the user $1 on $h ... " ssh root@${h} useradd -u ${userid} $1 echo "done" done } function del_user { if [ "$1" == "" ]; then echo "Specify a valid username to delete" exit 1 fi if [ "$2" != "" ]; then echo "Unsupported option specified" exit 1 fi echo -n "This command will remove the user $1, proceed? [yn]: " read ans if [ "$ans" != "y" ]; then echo "Exiting" exit 0 fi sudo userdel -f $1 for h in ${cluster_hosts}; do echo -n "Deleting the user $1 on $h ... " ssh root@${h} userdel -f $1 echo "done" done echo "Note: the home directory /mnt/raid/home/$1 has been preserved," echo " you may wish to delete that as well." } if [ "$1" == "--add" ]; then add_user $2 exit 0 fi if [ "$1" == "--delete" ]; then del_user $2 exit 0 fi help ``` ## Assicurarsi che tutto funzioni al riavvio del Cluster 1. Montare RAID sul control node _se_ non l'ha fatto in automatico (ovvero spegnere e riaccendere il case dei dischi dal power button, fa tutto `/etc/fstab`) 2. Riavviare glusterd sui compute nodes (sicuramente non si sono avviati tutti prima del control node): [da `rock`]: `./runsetup.sh mountgluster.sh`. Se `/mnt/data` non funziona da `steffe0`, riavviare il servizio `mnt-data.mount` (eventualmente anche sulle altre macchine, sta già in `mountgluster.sh`). 3. Rimettere su i nodi (in modo che vadano tutti da DOWN ad IDLE nell'output di `sinfo`): ``` for i in {1..20}; do sudo scontrol update nodename=steffe$i state=idle; done ``` 4. riavviare `nfs-kernel-server.service` su `steffe0` (se `steffe0` si accende prima degli altri non riesce a risolvere gli hostname all'avvio) e poi rimontare dappertutto con `./runsetup.sh mount-raid-nfs.sh` (TODO {anche per gluster} trovare un modo di far funzionare gli FSTAB all'avvio...)