Container with build environment
Note
To follow this tutorial you need to have root access to a Linux computer with Singularity installed, e.g. your personal laptop/workstation. Please follow the installation instructions from the Singularity documentation.
Sometimes we encounter applications that have system dependencies which are incompatible with the global environment on the cluster. This can happen for instance if you download a precompiled binary from an online archive which has been built for a specific OS version or depends on a system library which is not available, or if you want to compile your own application with some non-standard dependencies. One way to resolve such issues is to containerize the appropriate environment and run/compile your application through this container on the cluster. In the following examples we will demonstrate such a work flow.
Hello world example
This example demonstrates:
how to write a simple Singularity definition file
how to install system packages on top of a standard OS base image
how to build the container on your laptop
how to run commands through the container environment on the cluster
In this example we will create a very simple container environment with a Ubuntu-16.04 operating system and a GNU compiler. We will then use this environment to compile a simple program on the cluster.
Writing the definition file
We start with the following definition file (we call it example.def
)
Bootstrap: docker
From: ubuntu16.04
%post
apt-get update && apt-get install -y g++
This recipe will pull the ubuntu16.04
image from the docker
registry and install the GNU C++ compiler using the Ubuntu package manager. Any system
package that is available for the base OS can be installed in this way. Other common
Bootstrap
options include
library
for the Singularity Container Library,
shub
for Singularity-Hub or
localimage
if you want to build on top of another image located on your computer.
Tip
You can find much more on Singularity definition files here.
Building the container
We can now build the container with the following command (you need sudo rights for this step):
[me@laptop]$ sudo singularity build example.sif example.def
[... lots of output ...]
INFO: Adding environment to container
INFO: Creating SIF file...
INFO: Build complete: example.sif
Running the container
Once example.sif
is generated, we can scp
the container file to the cluster:
[me@laptop]$ scp example.sif me@saga.sigma2.no
First we check the default g++
compiler on the cluster:
[me@login-1.SAGA ~]$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Then we check the g++
version in the container by running the command through
singularity exec
:
[me@login-1.SAGA ~]$ singularity exec example.sif g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
We write a simple hello-world.cpp
program:
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}
and compile it through the container environment:
[me@login-1.SAGA ~]$ singularity exec example.sif g++ hello-world.cpp
[me@login-1.SAGA ~]$ singularity exec example.sif ./a.out
Hello World!
Remember that you also need to run the program through the container if it is dynamically linked to some of the containerized libraries.
Real world example: pdflatex
This example demonstrates:
how to build a container from a definition file
how to set environment variables inside the container
how to document your container
how to make your container look like an executable application
how to run your container application on the cluster
Latex is a software package with a plethora of different
package options which can easily mess up your global environment. It is something that is
typically not installed on compute clusters, but could still be useful e.g. for building
code documentation. In this example we will create a fully functional container for the
pdflatex
command for building PDFs from tex
files.
Writing the definition file
Bootstrap: library
From: ubuntu:20.04
%post
apt-get install -y software-properties-common
add-apt-repository universe
apt-get update -y
apt-get install -y texlive texlive-fonts-extra
%environment
export LC_ALL=C
%runscript
pdflatex $@
%labels
Author Me <me@mymail.com>
Description PDF latex on a Ubuntu-20.04 base image
Version v1.0.0
%help
How to run the container on a tex file:
$ ./<image-name>.sif <file-name>.tex
Here we use the Ubuntu package manager to install a few texlive
packages on top of a
Ubuntu-20.04 base image, and we set the LC_ALL
environment variable inside the container
at run time. The %runscript
section specifies the commands to be run inside the container
when you launch the image file as an executable, where the $@
will capture an argument string.
In this particular example it means that we can run the image as
$ ./<image-name>.sif <file-name>.tex
which will be equivalent of running the given %runscript
command (pdflatex
in this case)
through the container with singularity exec
:
$ singularity exec <image-name>.sif pdflatex <file-name>.tex
Finally, we add a few labels (accessible through singularity inspect <image-name>.sif
) and a help
string (accessible through singularity run-help <image-name>.sif
) for documentation.
Building the container
We build the container on a local computer (requires sudo rights), where we have called the
definition and image files pdflatex.def
and pdflatex.sif
, respectively:
[me@laptop]$ sudo singularity build pdflatex.sif pdflatex.def
[... lots of output ...]
This may take some time... done.
INFO: Adding help info
INFO: Adding labels
INFO: Adding environment to container
INFO: Adding runscript
INFO: Creating SIF file...
INFO: Build complete: pdflatex.sif
Inpecting the container
When the image is ready we can inspect the metadata that we put into it
[me@laptop]$ singularity inspect pdflatex.sif
Author: Me <me@mymail.com>
Description: PDF latex on a Ubuntu-20.04 base image
Version: v1.0.0
org.label-schema.build-arch: amd64
org.label-schema.build-date: Thursday_10_June_2021_13:12:27_CEST
org.label-schema.schema-version: 1.0
org.label-schema.usage: /.singularity.d/runscript.help
org.label-schema.usage.singularity.deffile.bootstrap: library
org.label-schema.usage.singularity.deffile.from: ubuntu:20.04
org.label-schema.usage.singularity.deffile.mirrorurl: http://us.archive.ubuntu.com/ubuntu/
org.label-schema.usage.singularity.deffile.osversion: focal
org.label-schema.usage.singularity.runscript.help: /.singularity.d/runscript.help
org.label-schema.usage.singularity.version: 3.7.0
[me@laptop]$ singularity run-help pdflatex.sif
How to run the container on a tex file:
$ ./<image-name>.sif <file-name>.tex
Running the container
When we are happy with the container we can move it to any machine where we would like
to run pdflatex
. Here we scp
to Saga and log in with -X
in order to browse the
produced PDF:
[me@laptop]$ scp pdflatex.sif me@saga.sigma2.no
[me@laptop]$ ssh -X me@saga.sigma2.no
We write a simple hello-world.tex
file
\documentclass[12pt]{article}
\begin{document}
Hello World!
\end{document}
and run our container on it:
[me@login-1.SAGA ~]$ ./pdflatex.sif hello-world.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) (preloaded format=pdflatex) restricted \write18 enabled.
entering extended mode
(./hello-world.tex
LaTeX2e <2020-02-02> patch level 2
L3 programming layer <2020-02-14>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2019/12/20 v1.4l Standard LaTeX document class
(/usr/share/texlive/texmf-dist/tex/latex/base/size12.clo))
(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdfmode.def)
No file hello-world.aux.
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./hello-world.aux) )</u
sr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr12.pfb>
Output written on hello-world.pdf (1 page, 9893 bytes).
Transcript written on hello-world.log.
Finally, you can inspect the produced file e.g. in a browser:
[me@login-1.SAGA ~]$ firefox hello-world.pdf
where you will hopefully see an almost blank page with the words “Hello World!” written.