Container (Apptainer)#
Containerization allows you to stick your application and all of its dependencies into a single package. This makes the application portable, shareable and reproducible across different computing platforms and environments. It also allows for a faster loading of your setup, when used as a replacement for conda or python environments.
At NHR@FAU, Apptainer (formerly known as Singularity) is the standard container solution. It is specifically designed for HPC systems and causes no performance penalties.
Info
Docker containers cannot be run natively on the HPC system. However, they can be easily converted to the Apptainer format.
Properties of Apptainer:
- available on all NHR@FAU systems
- all filesystems available by default inside the container
- supports GPU-dependent applications
- not suitable for MPI applications across multiple nodes
Basic usage#
Command | Explanation |
---|---|
apptainer build <container_name> <def-file> |
Build an Apptainer image |
apptainer pull <URI> |
Pull an image from a URI |
apptainer push <URI> |
Upload image to the provided URI |
apptainer run <container_name> |
Run the user-defined default command within a container |
apptainer exec <container_name> <command> |
Run a command within a container |
apptainer inspect <container_name> |
Check container metadata |
More information including examples of all basic commands and workflows is available in the Apptainer Quick Start Guide.
Using existing containers#
- Download / pull a container from a container repository (DockerHub) and it will be automatically converted into the Apptainer (
.sif
) format:apptainer pull docker://<repository>
- Enter container with a shell:
apptainer shell <container_name>
- Execute commands inside a container:
apptainer exec <container_name> <command>
- Run pre-defined
runscript
of container:apptainer run <container_name>
or./<container name>
Building your own container#
Containers have to be built on a system where you have enough permissions and the security model allows it. Containers can be build on the AlmaLinux based cluster frontend nodes (Fritz, Alex, Helma, Woody, Meggie). It is not possible to build them on our Ubuntu based systems (TinyX, Testcluster), but we offer a work around by building the container inside a container. If you get the following error
ERROR : Could not write info to setgroups: Permission denied
ERROR : Error while waiting event for user namespace mappings: Success
FATAL: While performing build: while running engine: exit status 1
apptainer build <options>
with /apps/singularity/apptainer-wrapper.sh build <options>
Info
They can also be built on your local machine making permissions and security model less of an issue.
Interactive build - example#
- Create sandbox based on a pre-existing container:
apptainer build --sandbox <sandbox_name> docker://<repository>
- Enter (writable) container with shell:
apptainer shell --writable <sandbox_name>
- Install/setup software inside container
- Convert sandbox to image and back again:
apptainer build <container_name>.sif <sandbox_name>
,apptainer build --sandbox <sandbox_name> <container_name>.sif
Info
On Helma, sandbox containers should be prepared in $TMPDIR. In workspaces, the inodes are not sufficient and in $HOME it crowds the space.
Build from definition file#
Definition specify how a container is build and configured and therefore help to make the build reproducible. Apptainer definition files and Dockerfiles are very similar in how they work, but they use different syntax.
To build a container from a definition file, use the following command:
A simple example for a definition file is given below:
Python example#
Bootstrap: docker
From: ubuntu:latest
%post
apt-get dist-upgrade
apt-get update
apt-get install -y python
mkdir /test
mv /python_sum.py /test
%files
python_sum.py
%runscript
exec "python" "/test/python_sum.py" "$@"
In the %post
section, you can specify what happens during build time in the container, e.g. downloading and installing software and libraries, creating directories, etc.
The %files
section can be used to copy files into the container. This is executed before the %post
section.
The %runscript
is the command that is executed when the container image is run via apptainer run
.
The %environment
section can be used to set environment variables inside the container. This is executed before the %runscript
section.
More information on definition files and the different sections is available in the Apptainer documentation.
python container with conda example#
In this example, a definition file is shown to setup a python environment from a requirements.txt
file using conda. If you need packages, that are not installed in the original docker image, you can install them with apt-get during the build.
Bootstrap: docker
From: dockerhub-mirror3.rrze.uni-erlangen.de/condaforge/miniforge3:latest
%files
requirements.txt /
%environment
export PATH=/opt/conda/envs/myenv/bin:$PATH
export CONDA_DEFAULT_ENV=myenv
%post
apt-get update -y
apt-get install -y <packages>
apt-get clean
# Create a new conda environment named 'myenv' with Python installed
conda create -y -n myenv python=3.11
# Activate the conda environment
. /opt/conda/etc/profile.d/conda.sh
conda activate myenv
# Install pip dependencies inside the conda environment
pip install --upgrade pip
pip install -r /requirements.txt
# Optional: clean up
conda clean --all -y
%runscript
exec "$@"
Depending on your task, you may change the following settings:
-
Base container: Best choose the container that is fundamental to your environment. Use
condaforge/miniforge3
if you already have a conda environment definition file and install it directly withconda env create -f /environment.yaml
. Use thenvidia/cuda
container if you need some special cuda libraries. When needing pure pytorch, you may use the 'pytorch/pytorch' docker container and use pip to install all your python packages. -
Packages: If you want to use specific packages that are not present in the base container. You cannot use
module load
inside of the container and you are responsible for installing all required programs withapt-get
.
Using GPUs inside containers#
Apptainer natively supports running GPU-enabled applications inside a container.
On the GPU clusters (Alex, Helma, TinyGPU), GPU device libraries are automatically bind-mounted into the container. No additional options should be necessary.
Requirements:
- Host has working installation of GPU driver and CUDA libraries (Alex, Helma, TinyGPU)
- CUDA version of application inside container must be compatible with host installation
If you encounter problems with missing GPU-support, try the Apptainer commands run
/shell
/execute
with the --nv
option, e.g. apptainer run --nv <container_name>
.
Additional hints#
-
Per default, all file systems (/home, ...) are mounted inside a container.
- To prevent mounting any file systems:
apptainer run --contain <container_name>
- Specify different home directory:
apptainer run -H $HOME/my-container-home <container_name>
- To prevent mounting any file systems:
-
Pulled container images (e.g. from DockerHub) are by default saved to
$HOME/.apptainer/cache
. Set the environment variable$APPTAINER_CACHEDIR
to different location, e.g.$WORK
to save space in$HOME
. -
Using MPI inside containers is not recommended, as it requires the exact version of the host MPI implementation including all dependencies (e.g. Slurm, Infiniband libraries, ...) to work properly.
-
To efficiently use RDMA/Infiniband communication, make sure to include
rdma-cora
,libibverbs1
, etc. in your image. Check (debug) the output (see Debugging NCCL). For NCCL as used by Pytorch, etc. check for an error such asNCCL INFO Failed to open libibverbs.so[.1]
.