= Definition File = Ein Defnition-File ist wie eine Blaupause zu verstehen für den [[https://wiki.init.mpg.de/IT4Science/SingularityContainerBauen|Bau eines Containers]]. Immer absolute Pfade angeben bzw. Umgebungsvariablen benutzen! <> == Was ist ein Definition File? == '''Es legt fest:''' * auf welchem OS bzw. Container basierend * welche Pakete installiert werden sollen * Umgebungsvariablen zur Laufzeit * benötigte Files vom Host * Metadaten und Beschreibung des Containers == Definition File eines Containers anzeigen == * Es ist möglich sich das Definition File eines Containers anzeigen zu lassen: {{{ $ singularity inspect -d CONTAINER.sif }}} == Komponenten == * Header: * beschreibt KernOS bzw. Container mit Quelle * konfigurieren von KernOS-Features * Linuxdistribution, genaue Version, Pakete die Teil der Installation sein müssen * Sections: * optional * kann mehrere Instanzen vorhandener Sections enthalten * /bin/sh interpreter und akzeptieren /bin/sh optionen * ausgeführt zur "build time" oder runtime == Header == * Bootstrap: Gibt den bootstrap agent an der zum erstellen den Kernsystems genutzt wird * möglich: library, docker, shub, localimage, yum, debootstrap, arch, busybox, zypper (genaueres in Doku: https://www.sylabs.io/guides/3.2/user-guide.pdf) * Beispiel für einen Header: {{{ Bootstrap: library From: debian:7 }}} oder {{{ Bootstrap: library From: ubuntu:18.04 }}} == Sections == * wenn ein Befehl fehlschlägt, wird der build-Prozess gestoppt * Reihenfolge der Sections spielt keine Rolle * es gibt verschiedenste sections: %setup, %files, %post, %runscript, %startscript, %test, %labels, %help === %setup === * Befehle, die '''außerhalb den Containers auf dem Host-System''' ausgeführt werden * werden ausgeführt, nachdem das KernOS den Container installiert worden ist * ContainerFS kann durch Umgebungsvariable referenziert werden: {{{$SINGULARITY_ROOTFS}}} * Beispiel: {{{ %setup touch /file1 touch${SINGULARITY_ROOTFS}/file2 }}} * file1 wird auf dem Host erstellt (/) * file2 wird im Container erstellt (/) * für das Kopieren von Files wird %files empfohlen, da %setup mit '''erweiterten Privilegien (Root)''' ausgeführt wird === %files === * zum '''Kopieren von Dateien aus dem Host-System''' in den Container * jede Zeile besteht aus einem Paar von zwei Pfaden, welche den Quellpfad auf dem Host-System und den Zielpfad im Container angeben * der Zielpfad ist optional und ist gleich dem Quellpfad, falls dieser weggelassen werden sollte * Beispiel: {{{ %files /file1 /file1 /opt }}} === %environment === * hier werden Umgebungsvariablen definiert, welche '''zur Runtime''' zur Verfügung stehen * Variablen, die hier definiert werden stehen '''nicht''' zu Buildtime zur Verfügung (%post wäre hier die Wahl) * es gelten die selben Konventionen wie in den .baschrc oder .profile Files * Beispiel: {{{ %environment export LISTEN_PORT=12345 export LC_ALL=C }}} * weitere Umgebungsvariablen können während der Runtime in %post definiert werden * %environment schreibt die Umgebungsvariablen in {{{/.singularity.d/env/90-environment.sh}}} * in %post definierte Umgebungsvariablen landen in {{{/.singularity.d/env/91-environment.sh}}} * %post-Umgebungsvariablen haben Vorrang gegenüber %environment-Variablen während der Laufzeit === %post === * Befehle werden ausgeführt, '''nachdem das KernOS installiert''' wurde * hier werden Dateien heruntergeladen, neue Software und Libraries installiert, Config-Files erstellt, neue Verzeichnisse angelegt, usw. * Beispiel: {{{ %post apt-get update && apt-get install -y netcat NOW=`date` echo "export NOW=\"${NOW}\"" >> $SINGULARITY_ENVIRONMENT }}} * um neue Umgebungsvariablen zu definieren wird hier {{{$SINGULARITY_ENVIRONMENT}}} benutzt * %post-Umgebungsvariablen haben Vorrang gegenüber %environment-Variablen während der Laufzeit === %runscript === * Befehle werden '''zur Runtime''' ausgeführt (durch singularity run oder exec) * Argumente, welche beim Start mitgegeben werden, werden hier genutzt * Beispiel: {{{ %runscript echo "Container was created $NOW" echo "Arguments received: $*" exec echo "$@" }}} * Konsolenoutput: {{{ $ ./my_container.sif Container was created Thu Dec 6 20:01:56 UTC 2018 Arguments received: }}} oder {{{ $ ./my_container.sif this that and the other Container was created Thu Dec 6 20:01:56 UTC 2018 Arguments received: this that and the other this that and the other }}} === %startscript === * Befehle werden ausgeführt, wenn '''instance start''' Befehl genutzt wird * Beispiel: {{{ %startscript nc -lp $LISTEN_PORT }}} * Skript lässt sich starten und stoppen mit: {{{ $ singularity instance start my_container.sif instance1 $ lsof | grep LISTEN $ singularity instance stop instance1 }}} === %test === * Befehle werden '''am Ende des Build-Prozesses''' ausgeführt * alternativ auch über den test-Befehl ausführbar * hier sollten Dinge wie BaseOS-Version, heruntergeladene Dateien und Softwarefunktionalität validiert werden * Beispiel: {{{ %test grep -q NAME=\"U buntu\"/etc/os-release if[ $? -eq 0 ]; then echo "Container base is Ubuntu as expected." else echo "Container base is not Ubuntu." fi }}} * zum Überspringen des Testskripts beim bauen eines Container den Parameter --notest benutzen: {{{$ sudo singularity build --notest my_container.sif my_container.def}}} === %labels === * Enthält '''Metadaten''', welche in das File /.singularity.d/labels.json im Container abgespeichert werden * jede Zeile besteht auch einem Name-Value Paar * Beispiel: {{{ %labels Author d@sylabs.io Version v0.0.1 }}} * Metadaten eines Containers (%labels) abrufbar mit $ singularity inspect my_container.sif === %help === * enthält einen beliebigen Text, welcher mit dem run-help Befehl aufgerufen werden kann: {{{$ singularity run-help my_container.sif}}} * hier sollte eine Beschreibung des Containers, ähnlich einer Dokumentation, stehen * gerade im Sinne der Reproduzierbarkeit können hier die Versionen der Softwarekomponenten angegeben werden * Beispiel: {{{ %help This is a demo container used to illustrate a def file that uses allsupported sections. }}} == Zeitliche Einordnung der Komponenten == * außen vor sind die für Metadaten zuständige Sections %help und %labels, da deren zeitliche Abfolge irrelevant sind * Unterteilung in Build-Prozess und Runtime: * Build-Prozess: * zuerst findet das Bootstrapping statt, also das hinzufügen eines KernOS bzw. Containers in den leeren Container. * als nächstes wird das Skript der %setup-Section mit root-Rechten auf dem Host-System ausgeführt * anschließende Schritte beeinflussen nur noch den Container * Schließlich wird der Build-Prozess mit den Skripten der %files- und %post-Section beendet, ab jetzt ohne erweiterte Privilegien. * an den Build-Prozess schließt das Skript der %test-Section an * Runtime: * zuerst werden die Umgebungsvariablen durch die %environment-Section definiert * je nach Befehl wird das Skript der %runscript-Section (exec, run) oder das Skript der %startscript-Section (start) ausgeführt {{attachment:definitionFileTime.png}} == Beispiel für ein komplettes Definition-File == {{{ Bootstrap: library From: ubuntu:18.04 %setup touch /file1 touch${SINGULARITY_ROOTFS}/file2 %files /file1 /file1 /opt %environment export LISTEN_PORT=12345 export LC_ALL=C %post apt-get update && apt-get install -y netcat NOW=`date`echo " export NOW=\"${NOW}\"" >> $SINGULARITY_ENVIRONMENT %runscript echo "Container was created $NOW" echo "Arguments received: $*"exec echo "$@" %startscript nc -lp $LISTEN_PORT %test grep -q NAME=\"Ubuntu\"/etc/os-release if[ $? -eq 0 ];then echo "Container base is Ubuntu as expected." else echo "Container base is not Ubuntu." fi %labels Author d@sylabs.io Version v0.0.1 %help This is a demo container used to illustrate a def file that uses allsupported sections. }}}