Zentrum für Datenverarbeitung (ZDV)

Singularity

Was ist Singularity?

Singularity ist eine Software zur Containervirtualisierung. Ein Container bietet Programmen und ihren Abhängikeiten, oder sogar vollständigen Betriebssystemen, einen abgeschlossenen und reproduzierbaren Raum. Singularity-Container können im Gegensatz zu Modulen beliebig dupliziert werden und funktionieren überall dort, wo Singularity installiert ist, gleich.

So kann man beispielsweise ein Programm am eigenen Rechner entwickeln und später einfach den Container auf den Server kopieren, um rechenintensive Operationen dort durchzuführen. Insbesondere für wissenschaftliches Arbeiten kann man mit Containern Programme zuverlässig unter den selben Bedingungen ausführen.

Eigene Container erstellen

Wer bereits einen Container hat oder von SingularityHub oder DockerHub herunterladen möchte, kann diesen Abschnitt überspringen und bei Container auf dem BinAC ausführen weiter lesen.

Um eigene Container zu erstellen ist ein Linux System mit Rootrechten erforderlich. Versuche mit einem Linux Subsystem unter Windows waren erfolglos. Steht kein Linux Rechner zur Verfügung muss Linux in einer Virtuellen Maschine ausgeführt werden.

Installation

Zunächst muss Singularity 3 installiert werden. Eine entsprechende Anleitung findet sich hier:

https://www.sylabs.io/guides/3.1/user-guide/quick_start.html#quick-installation-steps

Auf dem BinAC ist Singularity bereits auf installiert und Container können dort einfach benutzt werden. Da Nutzer dort keine Root-Rechte besitzen, können Sie dort aber keine Container bauen.

Einen ersten Container bauen

Über den Befehl

$ sudo singularity build --sandbox <containername> library://centos

wird ein neuer manipulierbarer Container mit einer vollständigen CentOS Installation im aktuellen Arbeitsverzeichnis erstellt. Im Verzeichnis befindet sich jetzt ein Ordner <containername>.

Über die Befehle exec --writable und shell --writable lassen sich Kommandos innerhalb des Containers ausführen, als würde das entsprechende Betriebssystem auf dem Rechner laufen.

Beispielsweise können wir mit

$ sudo singularity exec --writable <containername> yum - y update

den Paketmanager aktualisieren und danach eine Shell im Container öffnen

$ sudo singularity shell --writable <containername>

in der wir mit

$ yum -y install epel-release wget tar && yum -y groupinstall 'Development Tools'
$ cd /
$ wget www.clustal.org/download/current/clustalw-2.1.tar.gz
$ tar xzf clustalw-2.1.tar.gz
$ cd  clustalw-2.1
$ ./configure && make && make install
$ cd .. && rm -rf /clustalw-2.1 && rm clustalw-2.1-tar.gz
$ mkdir /input
$ mkdir /output

ClustalW2 installieren, um Multiple Sequenzalignments von DNA oder Proteinen zu berechnen.

Zuletzt kann von diesem Container ein unveränderliches Abbild erstellt werden:

$ sudo singularity build <unveränderlicher_containername>.sif <veränderlicher_containername>

Mittels

$ singularity exec <unveränderlicher_containername>.sif clustalw2

könnte ClustalW2 jetzt ausgeführt werden.

Definition Files

Für die Praxis ist es empfehlenswert Container über sogenannte Definitionsdateien zu erstellen. So wird sichergestellt, dass alle Container die mit dieser Datei erstellt wurden identisch sind.

Eine Datei mit dem folgenden Inhalt

Bootstrap: library
From: centos

%post
    yum -y install epel-release wget tar
    yum -y groupinstall 'Development Tools'

    # Install ClustalW
    cd /
    wget www.clustal.org/download/current/clustalw-2.1.tar.gz
    tar xzf clustalw-2.1.tar.gz
    cd clustalw-2.1
    ./configure && make && make install
    cd .. && rm -rf /clustalw-2.1 && rm clustalw-2.1.tar.gz

    # Input and output directory
    mkdir /input
    mkdir /output

%runscript
    clustalw2 "$@"

führt in Kombination mit diesem Befehl

$ sudo singularity build <neuer_container>.sif <definitionsdatei>

zu demselben unveränderlichen Container, der oben manuell erstellt wurde.

Die Unterteilung in Abschnitte trennt die verschiedenen Schritte des Erstellungsprozesses. Unter %post% werden beispielsweise die Kommandos angegeben, die unmittelbar nach der Installation des Betriebssystems ausgeführt werden sollen.

Neu ist das Konzept von runscripts. Befehle, die in diesem Abschnitt eingetragen sind, werden ausgeführt, wenn singularity mit dem Argument run augerufen wird.

Jetzt genügt

$ singularity run <neuer_container>.sif

um ClustalW2 auszuführen.

Unter https://www.sylabs.io/guides/3.0/user-guide/definition_files.html#definition-files finden sich alle Parameter, die in dieser Datei gesetzt werden können.

Container auf dem BinAC ausführen

Auf dem BinAC ist ein aktuelles Singularity auf jedem Knoten installiert.

Vom eigenen Rechner kann der Container z.B. per scp kopiert werden:

$ scp <containername>.sif <LoginID>@<BinAC_Adresse>:<Workspaceverzeichnis>

Wichtig ist, dass der Container in einem Workspace gespeichert wird. Container in Homeverzeichnissen können nicht ausgeführt werden. Falls nicht bereits vorhanden, muss man zunächst einen Workspace anlegen.

Alternativ kann auch ein existierender Container von DockerHub oder SingularityHub heruntergeladen werden. Dazu muss ins Workspaceverzeichnis gewechselt werden:

$ cd <Workspaceverzeichnis>

Anschließend kann ein Container nach dem Schema docker://<user>/container_name>:<tag> von DockerHub, beziehungsweise shub://<user>/<container_name>:<tag> von SingularityHub heruntergeladen werden. Beispielsweise

$ singularity pull docker://docker/whalesay:latest
$ singularity pull shub://GodloveD/lolcow:latest

Manche Biocontainer sind nur über quay.io erhältlich. Die Struktur entspricht aber der von DockerHub: docker://quay.io/biocontainers/<container_name>:<tag>.

Ausführung

Für das Beispiel des oben erstellten ClustalW2-Container, der alternativ auch unter docker://fbartusch/clustalw2:latest zur Verfügung steht, können wir zunächst einen kleinen Datensatz herunterladen und entpacken

und Multiple Sequenzalignments mit den Proteinen durchführen:

$ singularity exec clustalw2_latest.sif clustalw2 \
  -align -type=protein \
  -infile=./example_input/protein/example.fasta \
  -outfile=./example_protein.fasta.aln \
  -newtree=./example_protein.fasta.dnd

Die resultierenden Alignments der vier Proteinsequenzen (in diesem Fall Homoglobin Alpha Sequenzen verschiedener Spezies) können mit cat betrachtet werden:

$ cat example_protein.fasta.aln

Wie man an diesem Beispiel sieht, hängt Singularity das aktuelle Arbeitsverzeichnis ein, sodass über ./<name> auf die Dateien zugegriffen werden kann. Zum Ausprobieren ist das kein Problem, aber für echte Anwendungen sollten absolute statt relative Pfade angegeben werden.

Batchjobs

Die Alignments des Beispieldatensatzes wurden schnell berechnet. Um die Login-Knoten vor Überlastung zu schützen werden aufwendige Berechnungen und lang laufende Prozesse aber nach einer bestimmten Zeit automatisch abgebrochen. Deshalb ist es notwendig, die Ausführung mittels eines Batchjobs einem Scheduler zu überlassen, der sich im Hintergrund um die Auslastung des Clusters kümmert. Eine Jobscript-Datei für das ClustalW2-Beispiel mit absoluten Pfaden könnte so aussehen

#!/bin/bash
#PBS -l nodes=1:ppn=1
#PBS -l walltime=0:01:0
workspace=<workspace_verzeichnis>
singularity exec $workspace/clustalw2_latest.sif clustalw2 \
    -align -type=protein  \
    -infile=$workspace/example_input/protein/example.fasta \
    -outfile=$workspace/example_protein.fasta.aln \
    -newtree=$workspace/example_protein.fasta.dnd

und mit

$ qsub -q tiny <jobscript>

an den Scheduler übergeben werden. Für Details zu Batchjobs sei auf den entsprechenden Artikel verwiesen.

Verwendung von GPUs

Singularity-Container können in der Regel wie alle normalen, für GPUs gebaute, Programme genutzt werden. Dazu starten wir zunächst einen interaktiven job in der 'tiny' queue und prüfen die Verfügbarkeit von GPUs außerhalb eines Containers:

$ qsub -I -q tiny -l nodes=1:ppn=1:gpus=1
$ nvidia-smi

Um die Verfügbarkeit innerhalb eines Containers zu prüfen öffnen wir eine Shell im Container und führen darin den Befehl aus. Dies sollte dieselbe Ausgabe ergeben, wie außerhalb des Containers:

$ [...]
$ singularity shell --nv clustalw2_latest.sif
$ nvidia-smi

Das --nv Argument macht den NVIDIA-Treiber im Container verfügbar. Versuchsweise kann --nv weggelassen werden. Der Befehl nvidia-smi wird dann nicht gefunden.

Obwohl der System-NVIDIA-Treiber innerhalb des Containers verfügbar ist, muss der Container seine eigenes CUDA und andere GPU-bezogene Software bereitstellen.

Zum Abschluss noch ein Beispiel zum Trainieren eines kleinen Machine-Learning Modells mit GPUs und Containern:

# Container herunterladen
$ singularity pull docker://tensorflow/tensorflow:1.12.0-gpu-py3
# Tensorflow Models Repository herunterladen
$ wget github.com/tensorflow/models/archive/v1.11.tar.gz
$ tar xzf v1.11.tar.gz
# Interaktiven Job in der tiny queue starten
$ qsub -I -q tiny -l nodes=1:ppn=1:gpus=1
# Das Tutorial CIFAR10-model trainieren
$ singularity exec --nv tensorflow_1.12.0-gpu-py3.sif \
$ python models-1.11/tutorials/image/cifar10/cifar10_multi_gpu_train.py
# Die GPU-Nutzung kann in einer zweiten shell mit nvidia-smi beobachtet werden