Skip to content

Building containers

Containers are built from a definition file which allows the container to be built identically by anyone possessing the file.

Root privileges required to build a container

Note that the process of building a container requires elevated privileges

It is not possible to run the container build step on Apocrita.

Alternatively you can:

  • create the container on your own machine and copy to Apocrita.
  • create the container inside a virtual machine e.g. provisioning a Singularity Virtualbox VM using vagrant.
  • submit a container definition file for provisioning by the research support team.
  • pull pre-built images from a build service such as Singularity Hub.

One primary task per container

HPC Containers are designed to perform one primary task, and should consist of a main application and its dependencies, in a similar way to how module files are provided. Since containers are lightweight, you can use separate containers instead of general purpose containers containing a collection of applications. This improves supportability, performance and reproducibility.

Building a singularity container from scratch

The following example prepares a container from scratch giving complete control over the contents of your image. It utilises the package repository of the chosen Linux distribution to bootstrap the base OS layer, and adds the python34 package from the community EPEL repository.

Choosing a CentOS mirror

Although mirror.centos.org is used for these examples, you may optionally use other CentOS mirrors. www.mirrorservice.org/sites/mirror.centos.org is hosted at the University of Kent and may provide good performance from UK academic sites.

Using the following basic python3 definition file, called centos7-python-3.def:

BootStrap: yum
OSVersion: 7
MirrorURL: https://mirror.centos.org/centos/%{OSVERSION}/os/$basearch/
UpdateURL: https://mirror.centos.org/centos/%{OSVERSION}/updates/$basearch/
Include: yum

%post
    yum -y install epel-release
    yum -y install python34

%runscript
    python3 "${@}"

The build process is unattended, and will not succeed if any operations require interactive input. The yum -y command is used to avoid this.

Create the image (this step requires root privileges):

sudo singularity build centos7-python-3.img centos7-python-3.def

This will result in a usable image in the current working directory. Bear in mind that if you want a very specific version of package from a repository, that package may not be available in future, so where possible, try to future-proof your containers.

Building containers for other Linux distributions

You may build Ubuntu images using CentOS and vice versa. However to bootstrap, you will need extra packages on the host OS to build the container. CentOS hosts require the debootstrap package to create Ubuntu containers, and Ubuntu hosts require the yum package to build CentOS containers. Alternatively you may create containers from an existing Singularity or Docker image, as explained in the following section. Since this method builds upon pre-built images, the debootstrap or yum packages are not required.

Building containers from an existing base image

This enables you to use an existing Singularity or Docker image as a base.

Singularity images

The following example demonstrates the creation of a base image, and using it to prepare another container:

Using a simple definition file, centos7.def:

BootStrap: yum
OSVersion: 7
MirrorURL: https://mirror.centos.org/centos/%{OSVERSION}/os/$basearch/
UpdateURL: https://mirror.centos.org/centos/%{OSVERSION}/updates/$basearch/
Include: yum

Create the image which will serve as your CentOS7 base

sudo singularity build centos7.img centos7.def

To prepare a python34 container using the base image, make a new definition file, python34-centos7.def:

Bootstrap: localimage
From: /data/containers/base_images/centos7.img

%post
    yum -y install epel-release
    yum -y install python34

%runscript
    python3 "${@}"

The result will be a container almost identical to the one created from scratch.

sudo singularity build python34-centos7.img python34-centos7.def

Docker images

You can also bootstrap from Docker containers, although if supplied by a third party, you have less visibility or control over these images, so use with caution, as this may impact the future reproducibility of results:

Bootstrap: docker
From: centos:latest

%post
    yum -y install epel-release
    yum -y install python34

%runscript
    python3 "${@}"

Build the container. This will produce a container similar to the previous examples, but may vary slightly in overall size depending on packages installed in the base docker image:

sudo singularity build python34-centos7.img python34-centos7-docker.def

Future-proofing your containers

When building your own containers, be sure to make them portable and future-proof.

  • Consider whether the container will still build and produce the same results if the OS release or application version changes.
  • If copying files from a working directory as part of setup is unavoidable, ensure that any files copied from the working directory are included in the git repository
  • Perform all setup as part of the bootstrap process. If any manual steps are performed after the container is built, they should be integrated within the definition file, and the container rebuilt.
  • Consider if the ability to rebuild your container will be impacted by package updates, or deprecation of old releases.

Legacy versions of CentOS applications

Outdated minor CentOS releases are moved from the main CentOS servers to vault.centos.org. If you need to use a specific Operating System or application version other than the latest, you need to future-proof your container by using the CentOS vault.

Example definition file using CentOS vault for CentOS 7.2.1511 and ImageMagic-6.7.8.9-15

BootStrap: yum
OSVersion: 7.2.1511
MirrorURL: http://vault.centos.org/%{OSVERSION}/os/$basearch
UpdateURL: http://vault.centos.org/%{OSVERSION}/updates/$basearch/
Include: yum

%post
    yum -y install ImageMagick-6.7.8.9-15.el7_2.x86_64

Definition file sections

The following example definition file demonstrates commonly used definition file sections:

BootStrap: yum
OSVersion: 7
MirrorURL: http://mirror.centos.org/centos/%{OSVERSION}/os/$basearch/
UpdateURL: http://mirror.centos.org/centos/%{OSVERSION}/updates/$basearch/
Include: yum

%help
    Centos7 container providing latest python3 version from EPEL repository

%environment
    PYTHONPATH=/usr/lib/python3.4/

%post
    yum -y install epel-release
    yum -y install python34

%runscript
    python3 "${@}"

%test
    python3 -c 'import sys; print(sys.version)'

Help section

The %help section is designed to provide information about the container when singularity help <image.img> is run.

Environment settings

Environment settings supplied at build-time in the %post section do not get retained in the final image. Settings added to %environment are not read at build-time but appear in the final image.

Runscripts

Singularity containers can be configured to run a command or script with the %runscript directive, allowing you to execute the container and pass your own parameters. This is configured during the build process.

Remember to include "${@}" on the runscript command in your definition file to pass the parameters to the application inside your container, as shown in the earlier python3 example.

$  ./python34-centos7.img ./hello_world.py
Hello, World!

You can also use the singularity run <container> command.

$  singularity run ./python34-centos7.img ./hello_world.py
Hello, World!

Test scripts

The %test section at the end of your def file is automatically run during your build process. If you are testing on different hardware where the tests may fail, you can disable a %test section by providing the --notest option to the build command.

It is good practice to use these options in your container builds. Additional options are documented on the Singularity website.

Inspecting a container

You can find out how a container was created with the inspect command. The -d option shows the definition file used to create the container.

$ singularity inspect -d /data/containers/pandoc.img
BootStrap: debootstrap
OSVersion: xenial
MirrorURL: http://archive.ubuntu.com/ubuntu/

%post
    echo "Hello from inside the container"
    sed -i 's/$/ universe/' /etc/apt/sources.list
    apt-get update
    apt-get install --yes wget pandoc texlive \
    texlive-latex-recommended texlive-xetex texlive-luatex pandoc-citeproc
    apt-get clean

%runscript
    pandoc "${@}"

$test
    pandoc --version

The singularity inspect help command provides additional options for inspecting the container.

Known Issues

Bootstrapping CentOS using yum on an Ubuntu machine

Trying to bootstrap a CentOS container on an Ubuntu machine fails with an error RPM database is using a weird path

To fix this: Create a file /root/.rpmmacros containing the following and try again:

%_var /var
%_dbpath %{_var}/lib/rpm

Containers built for different CPU architectures

A container built on Intel CPU will not work on IBM Power nodes, and vice versa. This is expected behaviour, although the resulting error message Exec format error should be more informative. A feature request has been raised to improve this.