Carry your own environments on our servers

A new tool is available on eslsrv8: singularity

This tool is a container runtime which allows you to run your programs in the environment of your choice. It is based on Linux containers and can be run as a normal user.

Singularity has a some interesting features:

  • The image in run with user permissions, not root permissions
  • There is no daemon needed, just an executable
  • The image is contained in only one file
  • The image can be easily built from scratch using the default reposiroties
  • The image is portable and can be copied from your laptop to another server
  • All the mount points present on the host can still be accessed from the image
  • Works with X11 programs too

Usage example

Let’s say you want to run a python script with needs a python version newer than the one installed on the server. The workflow is as follow:

1) Choose your type of image

You can either build your image from scratch and add your own version of python in it (can be fastidious) or you can build your image by picking a version of an OS that you know comes with the python version you need (more common case).

2) Write your def file

Here is an example of a definition file which will let you compile some python and gcc stuff. There are more examples on the official site. This one is based on Ubuntu Trusty:

BootStrap: debootstrap
OSVersion: trusty
MirrorURL: http://mirror.switch.ch/ftp/mirror/ubuntu/
#MirrorURL: http://us.archive.ubuntu.com/ubuntu/
#use the mirror closer to you, Switch is free for EPFL %runscript
# this phase is executed when you run the container, before your command
# echo "This is what happens when you run the container %post
# this is run during the build phase of your image
# add the packages you want here # echo "Hello from inside the container
# sed -i 's/$/ universe/' /etc/apt/sources.list
apt-get update
apt-get -y install vim gcc python g++

This def file is enough to build a container able to run python, gcc and g++ in the versions provided in the trusty ubuntu environment. The dependencies wll automatically be resolved by the package manager. Feel free to add the packages you need.

To build the image you have to run the two commands below, as sudo:

First to create the core file of the image (-s is used to set the size of the image, in this case 2GB)

$ sudo singularity create -s 2048 /tmp/singularity_images/my_image.img

then apply your definition to it

$ sudo singularity bootstrap /tmp/singularity_images/my_image.img my_image.def

The result will be an executable file of 2GB in the /tmp/singularity_images folder called my_image.img and owned by root

If you want to add more packages then modify the def file and run the same bootstrap command.

For now make sure that you build your image in the /tmp/singularity_images folder.

3) Move the image to the server

This image is owned by root, this is a necessity imposed by the container system, but you can now copy the image into your homedir and use it as a normal user. If you created the image directly on eslsrv8 in /tmp/singularity_images then you can simply move the file to your homedir with mv. The images are portable, if you created the file on another desktop or laptop, you can scp the image to your homedir on the server. The root privileges are only needed during the creation and edition steps of the image, not when running it.

4) run your command  in the image

On the server, type:

$ singularity exec my_image.img ls -la

This will return the content of your homedir, seen by your user. The result is mostly independant of the environment. It’s just to show that your homedir is seen the same with or without a singularity environment.

In my case, my image is called trusty.img, which gives:

-bash-4.2$ singularity exec trusty.img ls -la
total 2105460
drwxr-xr-x 2 buret lsi1       4096 Apr 26 09:36 .
drwxr-xr-x 3 buret lsi1      24576 Apr 26 09:35 ..
-rwxr-xr-x 1 buret lsi1        997 Apr 26 09:36 test.py
-rwxr-xr-x 1 buret lsi1 2147483679 Apr 26 09:36 trusty.img

now if I run the test.py script, which is a python script reporting the versions of gcc, g++ and python and which writes it down to the versions.txt file I will get:

-bash-4.2$ python test.py
-bash-4.2$ cat versions.txt
Python 2.7.5
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)

These are the versions of the tools seen by my shell, a typical centos7 setup.

Now if I run the same script but in the trusty image

bash-4.2$ singularity exec trusty.img python test.py
-bash-4.2$ cat versions.txt
Python 2.7.6
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

The versions seen by the script are different.

Now if I want to run the script under fedora 24 all I have to do is bring an image built from fedora 24 (see below for the def file) and run the same script in the fedora 24 image:

-bash-4.2$ cp /tmp/singularity_image/fedora24.img .
-bash-4.2$ singularity exec fedora24.img python test.py
-bash-4.2$ cat versions.txt
Python 2.7.11
gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)
g++ (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)

Again, different versions of the tools, but still the same homedir:

-bash-4.2$ singularity exec fedora24.img ls -la
total 4210888
drwxr-xr-x 2 buret lsi1       4096 Apr 26 09:42 .
drwxr-xr-x 3 buret lsi1      24576 Apr 26 09:35 ..
-rwxr-xr-x 1 buret lsi1 2147483679 Apr 26 09:42 fedora24.img
-rwxr-xr-x 1 buret lsi1        997 Apr 26 09:36 test.py
-rwxr-xr-x 1 buret lsi1 2147483679 Apr 26 09:36 trusty.img
-rw-r–r– 1 buret lsi1        100 Apr 26 09:42 versions.txt

 

Misc

The idea is to keep the execution step as simple as possible so you can add singularity transparently to your workflow, even if you run your jobs in a scheduling system (ex: condor). It is also to make your development as portable and independant from the host OS as possible. The images can be used on any system which has singularity installed. As long as you make your development in the image you will be in control of the version of your tools no matter what. Just make sure that the version of singularity is recent enough.

You can run a shell in an image, for example just after you built an image, to check that every tool is in place:

-bash-4.2$ singularity shell trusty.img
Singularity: Invoking an interactive shell within container… Singularity.trusty.img> gcc –version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 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.

If you notice that a package is missing then you can add the package to your def file and rerun the bootstrap step. This will take care of only the diference in the content and won’t rebuild from scratch.

Singularity is very easy to install. See this page for the details.

Singularity can even be used to run X11 programs, like the EDA tools. It also follows NFS links. Just make sure to insert the EDA main folders in your image with.

%post
mkdir /softs
mkdir /edadk
mkdir /dkits

The configuration file of singularity also needs to allow overlay, which is disabled by default because centos versions older than 7.3 do not support it. If you run singularity on a centos 7.3 then you can safely allow overlay in the config file (not the def file).

Singularity is able to import docker images, but a big advantage of singularity is being able to create an environment from scratch, using the mirrors of your OS directly, including updates, making your image very secure by default.

The documentation of singularity is available here.

FAQ

You may ask: “Why use /tmp/singularity_images”?

The images are created with sudo, which create images owned by root, and which can only be removed by root. But singularity cannot remove images, even with sudo. Which means that if you create an image in the wrong folder you may be unable to remove it. The folder /tmp/singularity_images is regularly cleaned from all .img files which are older than 1 hour. So make sure that you create ALL your images in /tmp/singularity_images and that their suffix is .img. This way the OS will take care of purging the old, unused images. Just copy them to your homedir once you are ok with the image. Whithout this system the filesystem would become full very quickly, with files owned by root. Also, keep your def files in your homedir.

More definition files

In the case of a fedora, the def file would look like this:

 # Bootstrap definition example for Centos-7 with the latest Open MPI from GitHub master

BootStrap: yum
OSVersion: 24
MirrorURL: http://mirror.switch.ch/ftp/mirror/fedora/linux/releases/%{OSVERSION}/Everything/$basearch/os/
#MirrorURL: http://mirror.centos.org/centos-%{OSVERSION}/%{OSVERSION}/os/$basearch/
Include: yum

%setup
    echo "Looking in directory '$SINGULARITY_ROOTFS' for /bin/sh"
    if [ ! -x "$SINGULARITY_ROOTFS/bin/sh" ]; then
        echo "Hrmm, this container does not have /bin/sh installed..."
        exit 1
    fi
    exit 0

%post
        echo "Installing Development Tools YUM group"
        yum -y groupinstall "C Development Tools and Libraries"


#%runscript
#       echo "Arguments received: $*"
#       exec /usr/bin/python "$@"

#%test
#       /usr/local/bin/mpirun --allow-run-as-root /usr/bin/mpi_ring 

 

Here is a def file for running the EDA tools. MUST be built from a centos 6 host. This image (read-only) is available on eslsrv8 in the folder /files/singularity. Let me know if you need changes applied to it since this OS requires the image to be built on centos 6 specifically.

 # Bootstrap definition example for Centos-6 with the latest Open MPI from GitHub master

BootStrap: yum
OSVersion: 6
MirrorURL: http://mirror.switch.ch/ftp/mirror/centos/%{OSVERSION}/os/$basearch/
#MirrorURL: http://mirror.centos.org/centos-%{OSVERSION}/%{OSVERSION}/os/$basearch/
Include: yum

%setup
    echo "Looking in directory '$SINGULARITY_ROOTFS' for /bin/sh"
    if [ ! -x "$SINGULARITY_ROOTFS/bin/sh" ]; then
        echo "Hrmm, this container does not have /bin/sh installed..."
        exit 1
    fi
    exit 0

%post
#        echo "Installing nothing"
#        yum -y groupinstall "nothing"
         yum  -y install tcsh vi vim nfs-utils util-linux-ng

         yum -y install xterm glibc-devel.i686 glibc-devel.x86_64 ksh xorg-x11-font* libXext.i686 libXext.x86_64 libXft.i686 libXft.x86_64 libX11.i686 libX11.x86_64 fontconfig.i686 fontconfig.x86_64 libXt.i686 libXt.x86_64 mesa-libGLU.i686 mesa-libGLU.x86_64 mesa-libGL.i686 mesa-libGL.x86_64 libXp.i686 libXp.x86_64

         mkdir -p /softs
         mkdir -p /edadk
         mkdir -p /dkits

%runscript
#       echo "Arguments received: $*"
#       exec /usr/bin/python "$@"


#%test
#       /usr/local/bin/mpirun --allow-run-as-root /usr/bin/mpi_ring