Singularity Advanced Topics
Building containers
Building writable containers
By default, the containers you build in Singularity are read-only. Any changes you make are not saved. This usually is not a problem if the container you use has everything you need, since you can save files in your working directory or home directory and they will persist outside of the containers.
However, if your container is missing something that doesn't make sense to include in your home directory that you would like to persist between runs of the container (like another piece of software), you can build a container in a writable directory, called a sandbox.
Tip
An alternative way to have a writable (portion of a) filesystem in Singularity is an overlay. Overlays are files that act like a storage drive you can "plug in" to your container rather than encompassing the entire root filesystem. Since overlays are a viewed as a single file, they are great for "tricking" the HPCC into allowing you to use more files than your quota allows. For more information, including powertools to help you get started and examples installing conda, see the Lab Notebook on Singularity Overlays.
You can create a sandbox using the singularity build
command with the
--sandbox
option. As arguments, use a directory name for the location of the
sandbox and an image you want to start with (which can either be a URI or a
file):
1 |
|
If you look inside the directory, it looks like the full file system for the container
1 2 3 |
|
To run this image with any Singularity command, pass the directory as the image name:
1 |
|
However in order to make changes that will persist, you need to use the
--writable
option. Let's try to install some software:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
If we use the alpine/
sandbox again, we'll still have access to Python! The
sandbox can be packaged back up into an image file by again using the
singularity build
:
1 2 3 4 5 6 |
|
However, this method for building new containers does not leave a record of how you changed the base image. For better reproducibility, you should use a Singularity definition file as described in the next section.
Building containers from scratch with Singularity definition files
Warning
Building Singularity files from definition files requires super user permissions. You will need to install Singularity on your local computer to run these steps.
Alternatively, you might prefer building a Docker container and using it in Singularity as discussed below.
To build containers, Singularity uses a Singularity definition file which is similar to a Dockerfile in Docker. We will walk through building a Singularity definition file that creates a comparable image to the one in our Docker tutorial.
We will set up our working directory the same way:
1 2 3 |
|
and create the python script hello.py
:
hello.py | |
---|---|
1 2 |
|
Now, create the file Singularity
with the content below:
Singularity | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Now, let's learn the meaning of each section.
The first section means that we will use Alpine Linux as a base image. In fact,
the Bootstrap
line tells Singularity that we are using the Docker alpine
image hosted on Docker Hub. Other options for the Bootstrap
line include
library
for images in Sylab's container
library and shub
for images on the
(archived) Singularity hub.
1 2 |
|
The %files
section tells Singularity which files in our local directory we
want to copy to the container and where we should move them. In this case, we
are copying our Python script into /usr/src/my_app/
in the container.
1 2 |
|
The %post
section is used to install pip
using the Alpine Package Keeper (apk
).
1 2 |
|
Finally, the %runscript
section tells the container what command to run
when the container is invoked through singularity run
.
1 2 |
|
We can now build the image using the singularity build
command. Don't forget
that you'll need super user permission!
1 |
|
This will create the my_first_image.sif
file that you can now run.
1 2 3 |
|
You can now use this singularity image file anywhere you like, including the HPCC.
Migrating from Docker to Singularity
For more information regarding Docker support in Singularity, please see the official documentation.
Direct comparision
Topic | Docker | Singularity |
---|---|---|
Installation | Local computer only | HPCC and local computer |
Privileges | Requires super user privileges | Only requires super user privileges for building images |
Compatibility | Docker images | Docker and Singularity images |
Images | Cached and managed by Docker | Available as .sif files (can also be cached and managed by Singularity) |
File sharing | Manually specifying bind mounts (e.g., -v option) |
Automatically binds useful directories ($HOME , $PWD , etc.); others can be specified via --bind option and through overlay files |
Build file | Dockerfile | Singularity definition file |
Downloading images | docker pull <container> |
singularity pull <uri-prefix>://<container> |
Running | docker run <container> |
singularity run <container>.sif |
Running command | docker run <container> <command> |
singularity exec <container>.sif <command> |
Interactive shell | docker -it <container> sh |
singularity shell <container>.sif |
Converting from Docker images to Singularity images
There are a few ways to use Docker images with Singularity. If the image is
publicly available on Docker Hub, it is as easy as using the singularity pull
command with a Docker URI. See the example in the Singularity
introduction. If
you are installing from a private repository on Docker Hub, use the
--docker-login
flag with singularity pull
to authenticate with Docker.
If the Docker image is only available locally (e.g., you are testing local builds and don't want to push to a repository), you have two options. First, you can build a Singularity image directly from a cached Docker image:
1 |
|
Note that this requires Singularity and Docker to be installed on the same system, and requires super user permissions.
The second option is to first archive the Docker image into a tar
file, then
use this to build the Singularity image:
1 2 |
|
Here you could perform the docker save
on your local machine, move the
docker_image.tar
file to the HPCC, and then run the singularity build
step
on the HPCC since it does not require super user privileges.
A note on permissions
Singularity automatically mounts many system directories in your container,
including $HOME
and $PWD
. When you enter a shell in a Singularity
container, you will be in the same directory you started from. You are also
logged in as the same user inside the Singularity container as you are on the
host when you start the container.
In contrast, a Docker shell usually starts in /
as the root
user (or some
other user). Thus, you may have different permissions in a Docker container
that is run in Singularity. This can cause problems if a Docker container
expects you to be able to write to directories that your HPCC user will not
have access to (like /root
).
In these cases, you may have to modify the Dockerfile used to create the Docker image so that anything you need to access is stored in a location accessible to your user.
Using Singularity with MPI and GPUs
If you are running a container that uses MPI, you must use srun -n
$SLURM_NTASKS -c $SLURM_CPUS_PER_TASK
before the singularity
command to make
the command aware of all resources allotted. See a template script below.
singularity_mpi.sbatch | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
To run a container that takes advantage of GPU resources, you can use the
--nv
flag on any run
, exec
, or shell
singularity commands. Otherwise,
use the standard sbatch
setup for running any GPU job. An example script that
pulls a TensorFlow container and displays the available GPUs is shown below.
singularity_gpu.sbatch | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Cached images
When you use Docker image without pulling it first, it appears that no Singularity image file was created:
1 2 3 4 5 6 7 8 9 |
|
In fact, Singularity stores these files and the files used to create them in a cache:
1 2 3 |
|
As you can see, the files stored here can build up quickly. You can clean this cache using
1 |
|
Everything in the cache can be safely removed, and will just be redownloaded if needed again.
By default, Singularity uses ~/.singularity/cache
to store these files. If
you want to use another directory (e.g., your scratch space), you can use the
SINGULARITY_CACHEDIR
environment variable. Singularity also uses a temporary
directory (/tmp
by default) that you might also want to change using the
SINGULARITY_TEMPDIR
environment variable. For example:
1 2 3 |
|
Using the --debug
flag shows a lot of information, but at the end we see
these lines:
1 2 |
|
verifying that the scratch directories were used.