Vous arrivez sur un cluster de calcul. C'est nouveau (pour vous hein ! La plate-forme elle, n'a pas été mise à jour depuis 15 ans, elle en a donc vu d'autres...), mais ce n'est pas une raison pour y mettre le même bordel que celui qui règne dans votre ordinateur sous Windaube.
Voici un tuto complet sur un usage raisonné et raisonnable des ressources mises à votre disposition.
PS : Il ne s'agit pas d'un tuto sur le bruteforcing de clé WPA sur un cluster de calcul.
Sommaire
Règles de base
Connexion
Comme pour tous les serveurs, la connexion se fait via le protocole SSH. Ce protocole de connexion peut imposer un échange de clés de chiffrement en début de connexion empêchant l'espionnage des communications (chiffrement asymétrique). (Oui, c'est paradoxal : vous chiffrez vos scripts tout pourris et pas vos mails).
Vous devez donc générer votre couple de clés privée/publique ; Par défaut, l'outil ssh-keygen
créera une paire de clés RSA de 2048 bits, parfaite pour la plupart des utilisations.
MValls@kali:/home/MValls/.ssh$ ssh-keygen -f ~/.ssh/id_rsa_mon_cluster
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Your identification has been saved with the new passphrase.
-t
: spécifie le type d'algorithme utilisé-f
: spécifie le nom et le chemin des clés générées
PS 1 : Donnez une passphrase à vos clés ! Ne pas mettre de passphrase sur des clés d'identification est stupide et dangereux (autant ne pas en utiliser) !
PS 2 : Changement de mot de passe sur une clé ssh :
ssh-keygen -p -f ~/.ssh/id_rsa_mon_cluster
PS 3 : Il est possible que le cluster refuse les clés DSA (SSH2) pourtant plus sûres que les clés RSA (SSH1)*(cf note plus bas); Dans ce cas faites :
ssh-keygen -t rsa -f ~/.ssh/id_rsa_mon_cluster
À propos des clés DSA et RSA
Lors de la rédaction de cet article en 2016, les clés DSA étaient supposées plus sûres. Il s'avère que c'est toujours le cas par rapport aux clés RSA de tailles identiques. Or même si la norme DSA semble autoriser des clés dépassant cette robustesse (FIPS 186-3 vs FIPS 186-2 ?), ssh-keygen
ne le permet pas et fige la taille de la clé à 1024 bits. Dès 2013 cette robustesse a été jugée trop faible et en passe d'être cassable.
Les autres algorithmes ECDSA et Ed25519 (dans une moindre mesure), sont suspectés d'être backdoorés par la NSA.
La robustesse de ECDSA, Ed25519 et DSA est de plus dépendante de la fiabilité du générateur de nombres aléatoires de la machine ; chose que vous n'avez aucun moyen d'auditer simplement.
Par conséquent l’utilisation des clés DSA a été dépréciée depuis OpenSSH 7 pour cause de faille de sécurité. ssh-keygen
génère dorénavant une paire de clés RSA (SSH2) de 2048 bits.
Voir stackexchange - rsa-vs-dsa-for-ssh-authentication-keys.
Envoi de la clé publique
L'utilitaire ssh-keygen
génère 2 fichiers :
~/.ssh/id_rsa_mon_cluster # clé privée SECRETE
~/.ssh/id_rsa_mon_cluster.pub # clé publique PUBLIQUE
La clé publique est celle que vous devez partager/renseigner sur l'interface web de votre service. Copiez TOUT le retour de cette commande :
cat ~/.ssh/id_rsa_mon_cluster.pub
Si le service n'est pas doté d'une interface en ligne, envoyez la clé via cette commande :
ssh-copy-id -i ~/.ssh/id_rsa_mon_cluster <username>@<hostname>
La clé sera ajoutée dans une entrée du fichier distant ~/.ssh/authorized_keys
.
Connexion et usage de la clé SSH
La connexion proprement dite se fait comme ceci :
ssh -i ~/.ssh/id_rsa_mon_cluster login@mon.cluster.org
-i
: Spécifie la clé à utiliser au cas où vous en auriez plusieurs
Envoi de fichiers
Renseignez vous sur la localisation de l'espace disque qui vous est réservé. En général vous avez au moins un dossier dédié aux calculs et un dossier dédié au stockage ! Ça parait anodin mais l'un supporte de nombreuses opérations d'I/O, tandis que l'autre offre un débit de transfert digne d'une disquette 3.5" ! En bref, faites attention à l'endroit où vous mettez vos cochonneries !
Ex: /home/genouest/<your-group>/<your-login>
(backup) vs /omaha-beach/<your-login>
(rapidité ++)
L'envoi se fait selon le protocole SCP.
scp -p -i ~/.ssh/id_rsa_mon_cluster login@mon.cluster.org:/home/genouest/<your-group>/<your-login>/scripts_R_degueulasses/20150420_results.tar.bz2 20150420_results.tar.bz2
Concrètement, au centre vous avez le serveur sur lequel vous vous connectez : login@mon.cluster.org
; À sa droite immédiate vous avez les répertoires distants; À l'extrême droite vous mettez le répertoire local (où vos fichiers doivent arriver); À l'extrême gauche vous mettez le répertoire local (à partir duquel vos fichiers seront envoyés).
Résumé:
scp <départ> login@mon.cluster.org:<distant> <arrivée>
Oui, la commande est longue ! Voir le paragraphe suivant.
Note: La commande scp risque d'échouer si votre ~/.bashrc
sur le cluster essaie d'initialiser des environnements automatiquement alors que c'est interdit sur le serveur frontal.
Afin d'éviter ce désagrément, veillez à faire apparaitre les lignes suivantes en haut de votre ~/.bashrc
:
# If not running interactively, don't do anything
[[ $- == *i* ]] || return
Une alternative serait de déplacer les lignes problématiques dans le fichier ~/.bash_profile
Source: Stackoverflow
Simplifiez vous la vie !
Faites des alias dans votre ~/.bashrc
!
Ex:
alias 'cluster'='ssh -i ~/.ssh/id_rsa_mon_cluster login@mon.cluster.org'
Utilisez un agent ssh pour stocker la passphrase en mémoire, et éviter de l'entrer 10 fois par heure :
$ ssh-add ~/.ssh/id_rsa_mon_cluster
Identity added: /home/MValls/.ssh/id_rsa_mon_cluster (/home/MValls/.ssh/id_rsa_mon_cluster)
En cas d'erreur Could not open a connection to your authentication agent.
:
$ eval `ssh-agent -s`
$ #ou
$ eval $(ssh-agent)
Explications :
The idea of this problem is that ssh-add needs SSH_AUTH_SOCK and SSH_AGENT_PID environment variables to be set with current ssh-agent sock file path and pid number.Source: Stackoverflow. (Le socket se trouve dans un dossier du type
/tmp/ssh-kjmxRb2764/agent.2764
.)
Les nœuds et les queues
Lorsque vous vous connectez à un serveur de type cluster vous êtes accueillis par un serveur frontal. Ce serveur n'est pas dédié aux calculs; il permet juste aux utilisateurs de rejoindre un nœud de la grappe ! Si vous balancez vos tâches sur le frontal, la DSI va vite vous envoyer des mots d'amour !
Le cluster sur lequel je prends exemple utilise l'outil Sun Grid Engine (SGE) (Encore un de ces nombreux outils développés par Sun et phagocytés par l'ogre Oracle).
Rejoignez donc instantanément un nœud :
qrsh
Note : Exécuter qrsh ou qsub sur une tâche, vous libère du frontal.
-l h=<nom_du_noeud>
: Rejoindre un nœud particulier.
Lister les nœuds, leurs caractéristiques et utilisations
Listons les nœuds avec qhost
:
$ qhost
HOSTNAME ARCH NCPU NSOC NCOR NTHR LOAD MEMTOT MEMUSE SWAPTO SWAPUS
----------------------------------------------------------------------------------------------
global - - - - - - - - - -
cl1n022 lx-amd64 80 4 40 80 272.3 504.7G 26.6G 4.0G 23.9M
cl1n023 lx-amd64 80 4 40 80 331.8 504.7G 33.2G 4.0G 33.1M
cl1n027 lx-amd64 40 2 20 40 3.69 252.0G 48.7G 15.6G 34.7M
cl1n028 lx-amd64 40 2 20 40 11.67 252.0G 5.9G 15.6G 169.2M
cl1n030 lx-amd64 56 2 28 56 72.56 757.0G 30.1G 6.8G 8.3M
cl1n031 lx-amd64 48 2 24 48 42.70 504.5G 12.4G 11.7G 52.7M
cl1n032 lx-amd64 48 2 24 48 102.9 504.5G 30.3G 11.7G 16.9M
Ici, le nœud cl1n030
possède 757Go de mémoire (dont 30.1Go utilisés), 28 processeurs physiques "donc" 56 coeurs virtuels. Sa charge CPU LOAD
est de 72.56.
Comment interpréter la charge d'un processeur ?
La charge représente le nombre de processus en train d'utiliser ou en train d'attendre le processeur plus, sous la majorité des systèmes, le nombre de processus bloqués.
Source : Wikipédia.*
Par conséquent sur notre nœud une charge supérieure à 56 peut être considérée comme problématique. Toutefois, une charge élevée ne veut pas forcément dire que le processeur est occupé à 100%; il peut tout à fait attendre des processus faisant gérant beaucoup d'entrées/sorties bloquantes (accès disque/requêtes sur le réseau).
Pour savoir vraiment ce qu'il en est, la commande top
peut être utilisée.
Utilisation de la commande top
.
$ top
top - 17:02:32 up 96 days, 23:23, 0 users, load average: 81.70, 79.39, 77.59
Tasks: 1119 total, 10 running, 1109 sleeping, 0 stopped, 0 zombie
Cpu(s): 93.1%us, 1.8%sy, 0.0%ni, 5.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Signification des abréviations :
us: user cpu time (or) % CPU time spent in user space
sy: system cpu time (or) % CPU time spent in kernel space
ni: user nice cpu time (or) % CPU time spent on low priority processes
id: idle cpu time (or) % CPU time spent idle
wa: io wait cpu time (or) % CPU time spent in wait (on disk)
hi: hardware irq (or) % CPU time spent servicing/handling hardware interrupts
si: software irq (or) % CPU time spent servicing/handling software interrupts
st: steal time - - % CPU time in involuntary wait by virtual cpu while hypervisor is servicing another processor (or) % CPU time stolen from a virtual machine
Voir les explications sur la signification des temps user/sys: optimiser son code python.
Signification des status des processus (extrait de man ps
) :
D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent
Listons les tâches en cours sur chaque nœud qhost -u '*'
ou qstat -u '*'
:
$ qhost -u '*'
HOSTNAME ARCH NCPU NSOC NCOR NTHR LOAD MEMTOT MEMUSE SWAPTO SWAPUS
----------------------------------------------------------------------------------------------
job-ID prior name user state submit/start at queue master ja-task-ID
----------------------------------------------------------------------------------------------
cl1n030 lx-amd64 56 2 28 56 76.97 757.0G 26.3G 6.8G 8.3M
5314480 0.50034 evilDocker mvalls r 01/26/2017 18:38:08 all.q@cl1n MASTER
5314482 0.50034 useleStask esnowden r 01/26/2017 18:38:53 all.q@cl1n MASTER
5315793 0.61000 wallBuild dtrump r 01/31/2017 11:31:19 all.q@cl1n MASTER
Ici, 3 utilisateurs (mvalls, esnowden, dtrump) se partagent le noeud cl1n016
; leurs tâches respectives se nomment 5314480, 5314482, 5315793; elles ont pour priorité 0.50034, 0.50034 et 0.61000.
On remarque que la tâche de dtrump a une priorité supérieure; cela signifie que les ressources lui sont allouées en priorité (les autres tâches sont probablement en suspens).
Lister les queues
Les queues :
- sont des files où les jobs s'exécutent, pas là où ils attendent,
- regroupent plusieurs hosts => des grappes,
- fournissent des
slots
; en général 1 slot = 1 coeur de CPU, - peuvent être explicitement sélectionnées ou non (auquel cas la queue par défaut sera utilisée).
$ qconf -sql
all.q
galaxy.q
web
Afficher les caractéristiques d'une queue :
$ qconf -sq all.q
qname all.q
pe_list make mpi
slots 1,[cl1n023.genouest.org=80],[cl1n022.genouest.org=80]...
Lister les environnements parallèles
Les environnements parallèles sont des environnements de programmation adaptés aux clusters de calcul. On peut citer Message Passing Interface (MPI) pour les machines à mémoire distribuée, et OpenMP pour les machines à mémoire partagée.
Source : Environnements parallèles.
$ qconf -spl
make
mpi
La commande suivante affichera plus d'information pour chaque environnement (dont le nombre de slots disponibles) :
$ qconf -sp make
pe_name make
slots 150
user_lists NONE
xuser_lists NONE
start_proc_args /data1/sge/mpi/startmpi.sh $pe_hostfile
stop_proc_args /data1/sge/mpi/stopmpi.sh
allocation_rule $pe_slots
control_slaves TRUE
job_is_first_task FALSE
urgency_slots min
accounting_summary TRUE
Utiliser un environnement parallèle se fait via le paramètre -pe make <nb_cpu>
de qsub
vu plus loin.
PS:
- Multicores jobs : Jobs using several cores on a single machine
- Parallel Jobs : Jobs composed of cooperating tasks that must all be executed at the same time, often with requirements about how the tasks are distributed across the resources. Note that not just any program can run in parallel, it must be programmed as such and compiled against a particular MPI library.
Les tâches
Charger un environnement de travail
Pour utiliser le moindre outil, le moindre interpréteur Python, vous devez charger l'environnement pré-configuré sur le serveur. Là encore, consultez la doc de la plate-forme. C'est cet environnement que vous devrez mentionner dans votre script (cf plus bas).
Note : Le système d'environnement n'est pas universel; renseignez-vous !
Exemple de localisation des envs :
/softs/local/env/env*
Exemple du chargement d'un environnement dinopython :
. /softs/local/env/envpython-2.7.sh # bash syntax
Le script
Les tâches sont configurées/encapsulées dans un script .sh
. Voici sa syntaxe. Vous y remarquerez un en-tête avec des directives débutant par #$
(préfixe modifiable via l'option -C prefix
); il s'agit de la configuration de la tâche. Les paramètres sont décrits ci-après. Notez que ces paramètres peuvent être spécifiés dans un script comme ci-dessous ou directement après la commande qsub
décrite plus bas.
#! /bin/bash
#$ -S /bin/bash
#$ -M <votre-adresse>@mail.fr
#$ -N nom_du_script
#$ -m bea
# Initialisation environnement
. /local/env/envncbi.sh
# Le calcul proprement dit
blastall -p blastx -d genbank -i seq.fasta
Paramètres :
-S
: Le shell à utiliser-M
: Adresse mail-m b|e|a|s|n
: Expédition d'un mail- au début (b),
- à la fin (e),
- à l’arrêt (a),
- à la suspension (s),
- pas du tout (n),
- à la folie.
-N
: Nom de la tâche-cwd
:Lancement du script dans le répertoire courant-i
: Fichier d’entrée de la tâche-j y[es]|n[o]
: Fusion de la sortie d’erreur avec la sortie standard-o
: Fichier de sortie de la tâche (cf-j
)-verify
: Contrôle la tâche qui sera soumise
-pe make <nb_cpu>
: Chargement d'un environnement parallèle en spécifiant le nombre de CPU requis/demandés.-q <file_attente>
: Soumission en spécifiant le nom de la file d'attente censée exécuter le script.
Options de -l
(à séparer par une ,
:
h=<nom_du_noeud>
: Rejoindre un nœud particulier.h_vmem=10G
: Maximum de mémoire allouée à la tâche par slot demandé (le programme sera tué en cas de dépassement).mem_free=5G
: Demander 5Go de mémoire immédiatement.
Note : Exécuter qrsh ou qsub sur une tâche, vous libère du frontal. Inutile donc d'appeler qrsh dans le script.
Cas particulier des environnements virtuels Python
Pour charger un environnement virtuel Python (vous devriez toujours en utiliser pour assurer entre autres la reproductibilité de votre travail et vous éviter des prises de têtes), (voir Environnements virtuels Python), vous devrez inclure ces lignes dans le script avant d'appeler votre programme :
# Chargement de python 2
. /softs/local/env/envpython-2.7.sh
WORKON_HOME=~/.virtualenvs
source ~/.local/bin/virtualenvwrapper.sh
workon my_virtual_env
my_command
Soumission d'une tâche
$ qsub script.sh
your job <jobid> (script.sh) has been submitted
Suppression d'une tâche
qdel <identifiant_tache>
-u <login>
: Suppression de toutes les tâches d'un utilisateur
Obtenir des informations sur les tâches lancées
$ qstat -j <jobid>
==============================================================
job_number: 5314477
exec_file: job_scripts/5314477
submission_time: Thu Jan 26 18:37:06 2017
owner: dtrump
sge_o_home: /home/dtrump
sge_o_log_name: dtrump
sge_o_path: /local/python/2.7/bin:/usr/local/sge/bin/lx-amd64:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
sge_o_shell: /bin/bash
sge_o_workdir: /home/dtrump
sge_o_host: cl1n017
account: sge
cwd: /home/dtrump
merge: y
mail_options: abes
mail_list: donald.trump@elysee.fr
notify: FALSE
job_name: wallBuild
jobshare: 0
shell_list: NONE:/bin/bash
env_list:
script_file: script_cluster_temp.sh
usage 1: cpu=22:01:25:18, mem=9951300.14892 GBs, io=0.00743, vmem=17.301G, maxvmem=18.127G
Paramètres :
-u <login>
: Affichage des tâches lancées par un utilisateur.-j job_identifier_list
: Affichage de la totalité des informations relatives à une tâche.
À vérifier:
- job_number : Identifiant unique affiché lors de la confirmation de la soumission,
- job_name : Nom du script de la tâche,
- owner: Propriétaire de la tâche,
- État de la tâche (r = running, etc.),
- submission_time : Heure de soumission,
- Nom de la file faisant tourner la tâche,
Obtenir des informations sur les tâches arrêtées
$ qacct -j <jobid>
hostname cl1n024
exit_status 137
cpu 1067.180
mem 543.745
io 0.007
iow 0.000
maxvmem 11.137G
À vérifier :
- maxvmem < limite spécifiée
- exit_status != 137 (SIGKILL)
- hostname : état du noeud
Références
- University of Texas at Austin - SGE tutorial.
- Bioinformatics.mdc-berlin.de - Sun Grid Engine for beginners - How to use interactive sessions with qrsh.
- Bioinformatics.mdc-berlin.de - Resource and queues.
- Doc - Cluster GenOuest Bioinformatics Platform.
- Wikipédia - Oracle Grid Engine.
- Wikipédia - Load average.
- Understanding load average.
- Stackexchange - top: usage CPU.
- SGE - Submit a job.
- stackexchange - rsa-vs-dsa-for-ssh-authentication-keys.
Natir
Je m'insurge, cet article est parsemé de fautes et d'approximations (comme ce commentaire est (NDLR: était) parsemé de fautes c'est dire), dans l'ordre :
Bon 2 erreurs c'est pas beaucoup mais il faut faire attention quand on fait de la vulgarisation
Lex
En effet, SCP n'est pas interactif alors que SFTP l'est. SFTP est juste du FTP sur du SSH, mais SCP utilise tout de même le protocole SSH (de manière plus optimisée que SFTP; il fait moins de choses mais les fait mieux).
Merci pour les précisions, j'ai corrigé cette confusion. Toutefois, il ne s'agit pas de vulgarisation ici, mais bien d'une documentation pragmatique à connaître.