Apptainer: Getting started
Overview
Teaching: 30 min
Exercises: 20 minQuestions
What is apptainer and why might I want to use it?
Objectives
Understand what apptainer is and when you might want to use it.
Undertake your first run of a simple apptainer container.
The episodes in this lesson will introduce you to the apptainer container platform and demonstrate how to set up and use apptainer.
Work in progress…
This lesson is new material that is under ongoing development. We will introduce apptainer and demonstrate how to work with it. As the tools and best practices continue to develop, elements of this material are likely to evolve. We welcome any comments or suggestions on how the material can be improved or extended.
Apptainer - Part I
What is Apptainer?
Apptainer is a container platform that allows software engineers and researchers to easily share their work with others by packaging and deploying their software applications in a portable and reproducible manner. When you download a apptainer container image, you essentially receive a virtual computer disk that contains all of the necessary software, libraries and configuration to run one or more applications or undertake a particular task, e.g. to support a specific research project. This saves you the time and effort of installing and configuring software on your own system or setting up a new computer from scratch, as you can simply run a apptainer container from the image and have a virtual environment that is identical to the one used by the person who created the image. Container platforms like apptainer provide a convenient and consistent way to access and run software and tools. apptainer is increasingly widely used in the research community for supporting research projects as it allows users to isolate their software environments from the host operating system and can simplify tasks such as running multiple experiments simultaneously.
You may be familiar with Docker, another container platform that is now used widely. If you are, you will see that in some ways, apptainer is similar to Docker. However, in others, particularly in the system’s architecture, it is fundamentally different. These differences mean that apptainer is particularly well-suited to running on distributed, High Performance Computing (HPC) infrastructure, as well as a Linux laptop or desktop!
System administrators will not, generally, install Docker on shared computing platforms such as lab desktops, research clusters or HPC platforms because the design of Docker presents potential security issues for shared platforms with multiple users. Apptainer, on the other hand, can be run by end-users entirely within “user space”, that is, no special administrative privileges need to be assigned to a user in order for them to run and interact with containers on a platform where apptainer has been installed.
Getting started with Apptainer
Initially developed within the research community, apptainer is open source and the repository is currently available via GitHub. Part I of this apptainer material is intended to be undertaken on a remote platform where apptainer has been pre-installed.
Sign in to the remote platform, with apptainer installed, that you’ve been provided with access to. Check that the apptainer command is available in your terminal:
Loading a module
HPC systems often use modules to provide access to software on the system so you may need to use the command:
$ module load apptainerbefore you can use the
apptainercommand on the system.
$ apptainer --version
apptainer version 1.3.3-1.el8
Depending on the version of apptainer installed on your system, you may see a different version. At the time of writing, v1.3.5 is the latest release of apptainer.
Images and containers
We’ll start with a brief note on the terminology used in this section of the course. We refer to both images and containers. What is the distinction between these two terms?
Images are bundles of files including an operating system, software and potentially data and other application-related files. They may sometimes be referred to as a disk image or container image and they may be stored in different ways, perhaps as a single file, or as a group of files. Either way, we refer to this file, or collection of files, as an image.
A container is a virtual environment that is based on an image. That is, the files, applications, tools, etc that are available within a running container are determined by the image that the container is started from. It may be possible to start multiple container instances from an image. You could, perhaps, consider an image to be a form of template from which running container instances can be started.
Getting an image and running an apptainer container
If you recall from learning about Docker, Docker images are formed of a set of layers that make up the complete image. When you pull a Docker image from Docker Hub, you see the different layers being downloaded to your system. They are stored in your local Docker repository on your system and you can see details of the available images using the docker command.
Apptainer images are a little different. Apptainer uses the Singularity Image Format (SIF) and images are provided as single SIF files (with a .sif filename extension). Apptainer images can be pulled from Singularity Hub, a registry for container images. Apptainer is also capable of running containers based on images pulled from Docker Hub and some other sources. We’ll look at accessing containers from Docker Hub later in the Apptainer material.
Singularity Hub
Note that in addition to providing a repository that you can pull images from, Singularity Hub can also build apptainer images for you from a recipe - a configuration file defining the steps to build an image. We’ll look at recipes and building images later.
Let’s begin by creating a test directory, changing into it and pulling a test Hello World image from Singularity Hub:
$ mkdir test
$ cd test
$ apptainer pull hello-world.sif shub://vsoch/hello-world
INFO: Downloading shub image
59.75 MiB / 59.75 MiB [===============================================================================================================] 100.00% 52.03 MiB/s 1s
What just happened?! We pulled a SIF image from Singularity Hub using the apptainer pull command and directed it to store the image file using the name hello-world.sif in the current directory. If you run the ls command, you should see that the hello-world.sif file is now present in the current directory. This is our image and we can now run a container based on this image:
$ apptainer run hello-world.sif
RaawwWWWWWRRRR!! Avocado!
The above command ran the hello-world container from the image we downloaded from Singularity Hub and the resulting output was shown.
How did the container determine what to do when we ran it?! What did running the container actually do to result in the displayed output?
When you run a container from an apptainer image without using any additional command line arguments, the container runs the default run script that is embedded within the image. This is a shell script that can be used to run commands, tools or applications stored within the image on container startup. We can inspect the image’s run script using the apptainer inspect command:
$ apptainer inspect -r hello-world.sif
#!/bin/sh
exec /bin/bash /rawr.sh
This shows us the script within the hello-world.sif image configured to run by default when we use the apptainer run command.
Running specific commands within a container
We saw earlier that we can use the apptainer inspect command to see the run script that a container is configured to run by default. What if we want to run a different command within a container?
If we know the path of an executable that we want to run within a container, we can use the apptainer exec command. For example, using the hello-world.sif container that we’ve already pulled from Singularity Hub, we can run the following within the test directory where the hello-world.sif file is located:
$ apptainer exec hello-world.sif /bin/echo Hello World!
Hello World!
Here we see that a container has been started from the hello-world.sif image and the /bin/echo command has been run within the container, passing the input Hello World!. The command has echoed the provided input to the console and the container has terminated.
Note that the use of apptainer exec has overriden any run script set within the image metadata and the command that we specified as an argument to apptainer exec has been run instead.
Basic exercise: Running a different command within the “hello-world” container
Can you run a container based on the
hello-world.sifimage that prints the current date and time?Solution
$ apptainer exec hello-world.sif /bin/dateFri Jun 26 15:17:44 BST 2020
The difference between apptainer run and apptainer exec
Above we used the apptainer exec command. Earlier in this
course we used apptainer run. To clarify, the difference between these
two commands is:
-
apptainer run: This will run the default command set for containers based on the specfied image. This default command is set within the image metadata when the image is built (we’ll see more about this in later episodes). You do not specify a command to run when usingapptainer run, you simply specify the image file name. As we saw earlier, you can use theapptainer inspectcommand to see what command is run by default when starting a new container based on an image. -
apptainer exec: This will start a container based on the specified image and run the command provided on the command line followingapptainer exec <image file name>. This will override any default command specified within the image metadata that would otherwise be run if you usedapptainer run.
Opening an interactive shell within a container
If you want to open an interactive shell within a container, apptainer provides the apptainer shell command. Again, using the hello-world.sif image, and within our test directory, we can run a shell within a container from the hello-world image:
$ apptainer shell hello-world.sif
Singularity> whoami
[<your username>]
Singularity> ls
hello-world.sif
Singularity>
As shown above, we have opened a shell in a new container started from the hello-world.sif image. Note that the shell prompt has changed to show we are now within the apptainer container.
Use the exit command to exit from the container shell.
Making a module out of a container
We can also integrate apptainers into the environment module framework we’ve been learning about. The procedure is similar to what we’ve seen for other installation methods, but we will need to modify it slightly to expose commands in the container to the shell.
First, the familiar part - let’s put our example container in an install directory.
$ mkdir -p ~/software.install/singularity-hello/1.0/image
$ cd ~/software.install/singularity-hello/1.0/image
$ apptainer pull hello-world.sif shub://vsoch/hello-world
The directory structure is slightly different, as we are going to store some additional content in the install directory in a moment. That additional content will be how we expose the commands in the container to the shell. Let’s also make the directory where that content will be stored:
$ mkdir -p ~/software.install/singularity-hello/1.0/bin
The contents of this directory will be shell scripts that contain apptainer commands that refer to the image we downloaded.
We will make the scripts executable and add this new directory to PATH when we make our modulefile so the commands can be called directly from the shell.
Let’s create a couple of these scripts now to see what I’m talking about.
First, let’s make a script hello_avocado that just execs the container to print the avocado message:
#!/usr/bin/bash
IMG=/users/3/dunn0404/software.install/apptainer-hello/1.0/image/hello-world.sif
apptainer run $IMG
Let’s also make a script hello_to that takes arguments, using the special $@ bash variable:
#!/usr/bin/bash
IMG=/users/3/dunn0404/software.install/apptainer-hello/1.0/image/hello-world.sif
apptainer exec $IMG echo Hello "$@"
I’ll need to make these scripts executable for our workflow:
$ chmod +x ~/software.install/apptainer-hello/1.0/bin/hello_avocado
$ chmod +x ~/software.install/apptainer-hello/1.0/bin/hello_to
Now, we can create a modulefile that lets us load and unload this module and these commands:
$ mkdir -p ~/modulefiles.local/apptainer-hello/
And then create a modulefile ~/modulefiles.local/apptainer-hello/1.0 with contents:
#%Module
prepend-path PATH /users/3/dunn0404/software.install/apptainer-hello/1.0/bin
Now we can load our module and use the commands we just defined:
$ module load apptainer-hello/1.0
$ hello_avocado
RaawwWWWWWRRRR!! Avocado!
$ hello_to everyone at home
Hello everyone at home
This is one basic approach to incorporating apptainers into a module environment.
The wrapper scripts like hello_avocado can be further customized to your needs, making this potentially a very flexible way to install and run software.
In the next section we will look at some other details regarding running apptainer, including some customizations you will likely want to make for scripts like this in your own modules.
References
- [1] Gregory M. Kurzer, Containers for Science, Reproducibility and Mobility: Singularity P2. Intel HPC Developer Conference, 2017. Available at: https://www.intel.com/content/dam/www/public/us/en/documents/presentation/hpc-containers-singularity-advanced.pdf
- [2] J. Cohen and A. Turner. Reproducible computational environments using containers: Introduction to Singularity. Version 2020.08a, August 2020. Carpentries Incubator. Available at: https://github.com/carpentries-incubator/singularity-introduction
Key Points
apptainer is another container platform and it is often used in cluster/HPC/research environments.
apptainer has a different security model to other container platforms, one of the key reasons that it is well suited to HPC and cluster environments.
apptainer has its own container image format (SIF).
The
apptainercommand can be used to pull images from apptainer Hub and run a container from an image file.