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
362 lines
13 KiB
Markdown
10 months ago
|
---
|
||
|
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...)
|