You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
13 KiB
Markdown

---
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...)