Skip to content

Containers

A container is a packaged unit of software that contains code and all its dependencies including, but not limited to: system tools, libraries, settings and data. This makes applications and pipelines portable and reproducible, allowing for a consistent environment that can run on multiple platforms.

Docker is widely used by researchers, however, Docker images require root privileges which means they cannot be run in an HPC environment. Apptainer (formerly Singularity) addresses this by completely containing the authority so that all privileges needed at runtime stay inside the container. This makes it ideal for the shared environment of a supercomputer.

Docker

Docker is a containerization platform that uses OS-level virtualization to package software and dependencies in deliverable units called containers. It is by far the most common containerization platform today, and most other container platforms are compatible with Docker (for example, Apptainer or Shifter).

Apptainer

Apptainer (aka Singularity) is a container solution designed to execute applications at bare-metal performance while being secure, portable and 100% reproducible. Apptainer’s permissions model makes it a popular choice for shared HPC environments where Docker cannot be supported. It has its own syntax for building containers but also support pulling and running Docker containers.

A common way to proceed is to: first, use Docker to develop new containers and run them on laptops/workstations and second, use Apptainer as a runtime on HPC systems. Existing containers that are compatible with both Docker and Apptainer platforms can be found at:

Warning

As a consequence of the above explantions, ONLY Apptainer is supported on Lucia!

Cache directory

To speed up image downloads for faster, less redundant builds and pulls, Apptainer sets a cache directory in the user home under ~/.apptainer. This directory stores images, metadata, and docker layers that can wind up being reasonably large. It is highly advised to set a new Apptainer directory using the APPTAINER_CACHEDIR environment variable pointing to a location that is:

  • unique to the user or his project coworkers. Permissions are set on the cache so that private images cached for one user are not exposed to another. This means that APPTAINER_CACHEDIR cannot be shared.

  • located on a filesystem with sufficient space for the number and size of container images anticipated

  • located on a filesystem that supports atomic rename, if possible.

On Lucia, user's project SCRATCH directory is the most suitable location.

Pulling containers

Pulling Docker containers

Apptainer has the ability to convert available docker images into sif format allowing them to be run on HPC. If a user finds an image on Docker Hub, it is possible to pull it using the command: apptainer pull <local_image_name>.sif docker://docker_image. The docker image will be downloaded from Docker Hub and converted in a sif image that will be usable on Lucia.

Example

On Docker Hub, let's pull a PyTorch docker container using Apptainer:

    user@frontal02:~ # ml containers/apptainer
    user@frontal02:~ # cd apptainer/
    user@frontal02:~/apptainer # apptainer pull pytorch_2.7.1-cuda11.8-cudnn9.sif docker://pytorch/pytorch:2.7.1-cuda11.8-cudnn9-runtime
    INFO:    Converting OCI blobs to SIF format
    INFO:    Starting build...
    Getting image source signatures
    Copying blob f557aa5ee224 done  
    Copying blob 8a0c3e162a80 done  
    Copying blob 01c183a1cbcd done  
    Copying blob ab224c3cf399 done  
    Copying blob 4f4fb700ef54 done  
    Copying config a39beb6962 done  
    Writing manifest to image destination
    Storing signatures
    2025/07/11 11:41:12  info unpack layer: sha256:f557aa5ee22480ee9e1af0a094ce5174a8c3d83e1aa20dc8482e4e387546e0c3
    2025/07/11 11:41:13  info unpack layer: sha256:8a0c3e162a807f339f885fe8cd62f60ea94d64745c74a483a8c1e419f360cb3e
    2025/07/11 11:41:13  info unpack layer: sha256:ab224c3cf399b42d4c9dfa9bdaa36275478cd38d2738fc03bdd45f8231e4dcf0
    2025/07/11 11:42:18  info unpack layer: sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1
    2025/07/11 11:42:18  info unpack layer: sha256:01c183a1cbcdd4616bbe68cf75ce03cfc6db58f8b1ca7174f6320834b971af68
    INFO:    Creating SIF file...
    user@frontal02:~/apptainer # ls
    pytorch_2.7.1-cuda11.8-cudnn9.sif
    user@frontal02:~/apptainer #

Pulling Nvidia Images

Building GPU-optimized containers for Artificial intelligence (AI) and Machine Learning (ML) workflows, tuned specifically for the most demanding deep learning applications, is not a trivial task. To solve this issue, NVIDIA has come up with a catalog of specialized containers called NGC Collections. The NGC catalog covers a wide variety of use cases and application scenarios: it features both popular deep learning frameworks and High-performance Computing libraries and toolkits that also leverage the accelerated computing of GPU clusters.

Once logged on the NVidia NGC catalog, it is possible to navigate through all available softwares or use the embedded search engine to find a specific package. All available versions of the selected software can be found in the Tags tab. For example, in order to pull the latest TensorFlow container available, copying the greyed zone nvcr.io/nvidia... to clipboard allows to get the pull statement for the latest tag of TensorFlow 2:

NGC

To pull and convert this NGC image to a local Apptainer image file:

    user@frontal02:~/apptainer # apptainer pull tensorflow-25.02-py3.sif docker://nvcr.io/nvidia/tensorflow:25.02-tf2-py3
    INFO:    Converting OCI blobs to SIF format
    INFO:    Starting build...
    Getting image source signatures
    Copying blob ec7790dc104b [============>-------------------------] 1.5GiB / 4.6GiB
    Copying blob ec7790dc104b [============>-------------------------] 1.6GiB / 4.6GiB
    ...
    [Skipped]
    ...
    INFO:    Creating SIF file...
    user@frontal02:~/apptainer #

The general format for any pull is:

apptainer pull <local_image_name> docker://nvcr.io/<registry>/<app:tag>

This Apptainer build command will download the app:tag NGC Docker image, convert it to Apptainer format and save it to the local filename <local_image_name>.

Using containers

Apptainer can be used to run analyses and applications in various ways: running a prepackaged workflow embedded in the image with apptainer run, executing commands within the container's environment using apptainer exec or starting an interactive instance to work directly within the container using apptainer shell.

Running prepackaged Apptainer workflows

apptainer run is used without any arguments and executes a predefined workflow embedded in the image. The general syntax is:

apptainer run image.sif

For example:

    user@frontal01:~/apptainer # apptainer run lolcow.sif 
    _______________________________
    < Tue Jul 15 11:56:06 CEST 2025 >
    -------------------------------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    user@frontal01:~/apptainer #

Executing commands within Apptainer images

apptainer exec allows to execute commands within an Apptainer image without entering it interactively. It simplifies running tasks by providing a command-line interface to interact with containerized applications, ensuring consistency and reproducibility in any workflow. The general syntax is:

apptainer exec image.sif <commands>

For example, using Tensorflow:

apptainer exec ~/apptainer/tensorflow-25.02-py3.sif python3 myscript.py

Using Apptainer applications interactively

Apptainer shell starts an interactive session within the container's environment. This is optimal for testing, debugging or using any sort of graphical interface installed in the image. The general syntax is:

apptainer shell image.sif

For example:

    user@frontal01:~ # apptainer shell ~/apptainer/tensorflow-25.02-py3.sif
    Apptainer> python3
    Python 3.12.3 (main, Jan 17 2025, 18:03:48) [GCC 13.3.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import tensorflow as tf
    >>> tf.__version__
    '2.17.0'
    >>>

Warning

When using Apptainer to execute workflows that require a GPU, the additional flag --nv must be added to the Apptainer command. The general syntax for GPU usage is:

apptainer {run/exec/shell} --nv image.sif <commands>

Creating Apptainer containers

In this section, an Apptainer container for the famous PAPI software will be created on the user's laptop/workstation and tested later on Lucia. PAPI provides the tool designer and application engineer with a consistent interface and methodology for use of the performance counter hardware found in most major microprocessors. PAPI enables software engineers to see, in near real time, the relation between software performance and processor events. In addition Component PAPI provides access to a collection of components that expose performance measurement opportunites across the hardware and software stack. PAPI is easily installed using a configure/make/make install procedure.

Sandbox mode

One way to create an Apptainer container is in the so-called sandbox mode. Instead of an image file, a directory structure representing the file system of the container is created.

  1. The first step is to create a basic container from a very bare-bones definition file. An arbitrary choice is made here: creation of an Ubuntu 20.04 container image for PAPI. The basic definition file - called papi-ubuntu.def - is as simple as:

         Bootstrap: docker
         From: ubuntu:20.04
    

    Hint

    For full description of a definition file, see Apptainer definition files

  2. Using this definition file, build the container

        apptainer build --fakeroot --sandbox papi papi-ubuntu.def
    

    Note that instead of an image file, a directory called papi has been created. If some reference files etc... have to be included, they can be copied to the correct subdirectory.

  3. A shell can be now opened in the container. The container file system needs to be writable, so the Apptainer option --writable is required. The --fakeroot option is also needed:

        apptainer shell --fakeroot --writable papi
    
  4. The command prompt should now be Apptainer>. This means that all coming work will be done inside the container itself.

    💡 The base container images are typically very bare-bones and do not contain any compilers, download tools etc..., so those need to be installed.

    💡 In the case of PAPI, GNU compilers as well as make and wget (to download the source file) have to be installed.

    So, within the container shell, the recipe for PAPI installation has to be reproduced.

        Apptainer> cd /path/to/papi
        Apptainer> apt update
        ...
        [Skipped]
        ...
        Apptainer> apt install wget -y
        ...
        [Skipped]
        ...
        Apptainer> apt install gcc -y
        ...
        [Skipped]
        ...
        Apptainer> apt install make -y
        ...
        [Skipped]
        ...
        Apptainer>
    
  5. Now that the necessary tools are available in the container shell, it is possible to proceed to the installation of PAPI.

        Apptainer> wget https://icl.utk.edu/projects/papi/downloads/papi-7.1.0.tar.gz
        ...
        [Skipped]
        ...
        Apptainer> tar xf papi-7.1.0.tar.gz 
        ...
        [Skipped]
        ...
        Apptainer> cd papi-7.1.0/src/
        Apptainer> ./configure --prefix=/path/to/papi/PAPI
        ...
        [Skipped]
        ...
        Apptainer> make
        ...
        [Skipped]
        ...
        Apptainer> make install
        ...
        [Skipped]
        ...
        Apptainer> /path/to/papi/PAPI/bin/papi_version 
        PAPI Version: 7.1.0.0
        Apptainer>
    
  6. Now that PAPI is installed within the container, it is possible to clean up the source file and the installation directory and exit the sandbox:

        Apptainer> cd ../..
        Apptainer> rm -rf papi-7.1.0 papi-7.1.0.tar.gz
        Apptainer> exit
    
  7. The production image can now be built from the sandbox:

        apptainer build --fakeroot papi.sif papi
        INFO:    Starting build...
        INFO:    Extracting local image...
        INFO:    Creating SIF file...
        [==============================================================================================================] 100 % 0s
        INFO:    Build complete: papi.sif
    
  8. Check the Apptainer image:

        apptainer exec papi.sif /path/to/papi/PAPI/bin/papi_version
        PAPI Version: 7.1.0.0
    

Definition file

The above method is fine if the container is intended to be only used by the user himself and/or his close collaborators. However, if the goal is to distribute it wider, it’s best to write a definition file for it so that way other users can see what is in the container, and they can easily rebuild the production image.

To write a definition file, it is advised to start from the original bare-bones file and add various sections as required:

  • the installation commands go in the %post section

  • if environment variables are required, they will be placed in the %environment section

  • if additional files are needed, they go into the %files section

  • if a runscript is necessary for the container to work properly, it goes in the %runscript.

Hint

There are also other sections available if needed. More information can be found in the Definition Files chapter of the Apptainer documentation.

For the basic PAPI case, the definition file papi.def writes as follows:

    Bootstrap: docker
    From: ubuntu:20.04

    %post
        apt update
        apt install wget -y
        apt install gcc -y
        apt install make -y
        wget https://icl.utk.edu/projects/papi/downloads/papi-7.1.0.tar.gz
        tar xf papi-7.1.0.tar.gz
        cd papi-7.1.0/src/
        ./configure --prefix=/path/to/papi/PAPI
        make
        make install
        cd ../..
        rm -rf papi-7.1.0 papi-7.1.0.tar.gz
The Apptainer image can be built using the following command:

apptainer build --fakeroot papi.sif papi.def

Documentation

All information about Apptainer can be found in the Apptainer User Guide.