Rémy Dernat <remy.dernat@umontpellier.fr> v1.6, 2018-17-05

Singularity : les bonnes pratiques

En dehors de la fabrication de recettes, il n’y a pas encore de bonnes pratiques documentées sur le site de Singularity. Ce qui suit est donc basé sur ma propre expérience.

L’utilisateur pourra soit concocter ses propres formules soit demander au support HPC de l’aider pour que les performances soient au rendez-vous. On touche ici à un point critique. Certaines plateformes ne voudront pas que des images non optimisées tournent sur leur cluster. C’est le cas des centres de calcul évalués selon leur efficacité.

Le pipeline qui va en découler sera donc différent selon les cas. Dans le cas où l’administrateur de cluster laisse faire ses utilisateurs, on peut imaginer communiquer proprement et ouvertement sur la présence et l’utilisation de singularity. Dans le second cas, on ne communiquera pas trop sur les conteneurs et on limitera l’accès des utilisateurs à la commande (voir LIMIT CONTAINER OWNERS dans la configuration) et éventuellement aux dépôts d’images.

En combinant l’utilisation de singularity et des modulefiles, on pourra chaîner l’appel au module singularity puis à l’image elle-même (ça permet de voir l’image comme un exécutable classique (ce qu’elle est, mais l’appel à singularity est ainsi masqué, et le PATH/et autres variables d’environnement seront aussi correctement configurés); on peut même faire un lien symbolique dans un PATH qui portera le même nom que l’exécutable conteneurisé).

Pour les utilisateurs

La fabrication des recettes fait déjà l’objet de bonnes pratiques : http://singularity.lbl.gov/docs-recipes#best-practices-for-build-recipes

On peut rajouter à cette liste de bonnes pratiques qu’une section %test est pratique pour s’assurer de certaines choses (reproductibitité…​ ?); de même il faut user et abuser des %labels.

En effet, certaines informations sont très pratiques et permettent de retrouver facilement des recettes dans les dépôts. Nous pouvons donc rajouter ce type de %labels :

  • la version de Singularity utilisée pour le build,

  • le créateur, la/les personne(s) qui les a modifié (avec éventuellement un log de la modification),

  • la date de création et de mises à jour,

  • l’application principale et les éventuelles apps (elles ont elles-mêmes leur %applabels),

  • une URL vers la recette,

  • toute information que vous trouverez pertinente.

Dans le cas où un Dockerfile existe déjà, on se retrouve alors confronté au choix suivant :

  • convertir l’image Docker en image Singularity,

  • convertir la recette Dockerfile en recette Singularity (soit de manière automatique ou manuellement / en s’en inspirant)

Il est préférable de choisir la seconde option car ça permet de reprendre proprement ce qui est fait, sauf dans le cas où on ne souhaite ne maintenir qu’un Dockerfile.

Il faut également faire attention au champ "From" dans une recette; en effet, nous considèrerons que si on fait un "From", on fait confiance à la recette parente (sur le Docker-hub, on prendra soin de choisir des images étiquettées "officielles"), et si possible légères (busybox, alpine…​).

Bien entendu, on pense à versionner les recettes. Si on utilise un dépôt github, on pourra le coupler aisément au singularity-hub, pour faire des builds de conteneurs à chaque commit.

Pour les administrateurs

Vous aurez sûrement à reprendre les images des utilisateurs pour rajouter les spécificités de votre plateforme.

singularity inspect …​ permet déjà d’obtenir des informations sur l’image. Si vous avez fait un pull depuis le singularity-hub, vous pouvez aussi lire la recette dans le fichier /.singularity.d/Singularity du conteneur.

Il semblerait que l’outil "sregistry-cli" soit capable de récupérer le contenu de la recette lorsqu’il fait un inspect après avoir fait le pull. Par ailleurs, le singularity-hub permet d’explorer le contenu des images.

Dans le fichier de configuration de Singularity singularity.conf, vous allez sûrement rajouter un espace scratch local à chaque noeud à bind monter. Dans ce cas, pour que ça soit exploitable dans chaque image, il faut qu’un dossier parent existe correspondant au futur point de montage.

Ainsi une simple modification de recette pourrait s’exprimer ainsi :

r3.4.4-from-shub-nickjer.local.def

BootStrap: shub
From: nickjer/singularity-r:3.4.4

%post
mkdir /scratch

Bien entendu, vous pouvez imaginer des modifications bien plus complexes à rajouter en post-traitement dans une enième recette, puisqu’elles peuvent être chainées indéfiniment (à éviter).

Nous pouvons donc imaginer un premier type d’organisation avec le singularity-hub officiel pour des recettes publiques publiées sur github, puis un autre dépôt local, qui contient les recettes modifiées de ces images. Il faudra ensuite penser à une arborescence correcte si les images sont distrisbuées sur un dossier (ex: /dossier/partagé/version majeure de singularity/version mineure/nom de l’application/version majeure/version mineure/image). Cette méthode sera préférée si on souhaite limiter l’usage de Singularity sur la plateforme.

Dans le cas où on souhaite étendre au maximum l’utilisation de singularity, on préfèrera ne maintenir qu’un seul dépôt, public ou privé selon le besoin.

Les sregistry de Singularity répondent à ce besoin : https://github.com/singularityhub/sregistry Ils permettent une collaboration accrue entre les utilisateurs du dépôt. Il semblerait qu’il soit désormais possible de les relier entre eux pour former un réseau de confiance (voir ici). Cependant, il n’y a pas encore d’outil intégré aux sregistry pour lancer un build depuis un dépôt git (contrairement au singularity-hub officiel connecté à github).

Monitoring

Pour l’instant, il n’y a pas vraiment d’équivalent à un "docker ps", sauf dans le cadre des "instances" singularity (== tâches de fond / services). Cependant, il faut voir les conteneurs Singularity comme des applications classiques, ils peuvent donc être monitorés comme n’importe quel autre job.

Pour superviser l’utilisation des namespaces, vous pouvez utiliser lsns et nsenter du package util-linux. Normalement, les 2 utilitaires sont disponibles à partir de la version 2.28 du package.

C’est un peu plus complexe qu’avec un docker attach …​ :

lsns |grep bash
# recuperation du PID correspondant
sudo nsenter -a -t <PID>
# une fois dans le conteneur
chroot /usr/local/var/singularity/mnt/container
# /usr/local à remplacer par le prefix d'installation du ./configure ou localstatedir si utilisé
ls -l /

Cache et nettoyage

Il pourra s’avérer utile de vérifier le SINGULARITY_TMPDIR, voir éventuellement faire un epilog / prolog à votre Job Scheduler pour pouvoir fixer ce dernier à un sous-dossier de votre TMPDIR contenant le JOB ID (ex : SINGULARITY_TMPDIR="/tmp/singularity-slurm-${SLURM_JOB_ID}" ).

Scans d’image

Avec l’aide de l’outil clair de CoreOS, il est possible de scanner des images pour chercher des vulnérabilités dans celles-ci :

singularity pull shub://marcc-hpc/tensorflow:1.8.0-gpu
singularity check --tag security marcc-hpc-tensorflow-1.8.0-gpu-1.8.0-gpu.simg