Containers
Singularity Extreme Mobility of Computing
Singularity is a technology to run software containers (think Docker containers) in an High-Performance Computing environment. The most striking difference in comparison to Docker is that running these singularity containers do not need root rights.
Possible uses for Singularity on Ibex:
- Run an application that was built for a different distribution of Linux than the host OS.
- Reproduce an environment to run a workflow created by someone else.
- Run a series of applications (a 'pipeline') that includes applications built on different platforms.
- Run an application from Singularity Hub or Docker Hub on Ibex without actually installing anything.
- Singularity home
- Singularity Documentation
- Singularity on GitHub
- Singularity on Google groups
- Singularity Hub
- Docker Hub
Please Note:
Singularity gives you the ability to install and run applications on your own Linux environment with your own customized software stack. With this ability comes the added responsibility of managing your own Linux environment. While the KSL-CS staff can provide guidance on how to create and use singularity containers, we do not have the resources to manage containers for individual users. If you decide to use Singularity, it is your responsibility to build and manage your own containers.
Creating Singularity containers
To use Singularity on Ibex, you either need to build your own Singularity container or use one created by someone else.
The build command accepts a target as input and produces a container as output.
The target defines the method that build uses to create the container. It can be one of the following:
- URI beginning with library:// to build from the Container Library.
- URI beginning with docker:// to build from Docker Hub.
- URI beginning with shub:// to build from Singularity Hub.
- PATH to a existing container on your local machine.
- PATH to a directory to build from a sandbox.
- PATH to a Singularity definition file.
build can produce containers in two different formats that can be specified as follows.
- Compressed read-only Singularity Image File (SIF) format suitable for production (default).
- Writable (ch)root directory called a sandbox for interactive development ( --sandbox option).
Because build can accept an existing container as a target and create a container in either supported format you can convert existing containers from one format to another.
If you choose to build the image from a Singularity definition file, you should have root access and these are your possible options:
- Use fakeroot option available on Ibex compute nodes.
- Use remote option to build on Singularity Container Services.
- If you have a Linux system to which you have root (admin) access, you can install Singularity and build your Singularity container there.
- If you don't have a Linux system you could easily install one in a virtual machine using software like VirtualBox, Vagrant, VMware, or Parallels.
- You can allocate a cloud instance, to which you will have root access. Install Singularity and build your Singularity container there.
Example to build an image from DockerHub:
[user@dbn303-16-l]$ module load singularity Loading module for Singularity Singularity 3.5 modules now loaded [user@dbn503-33-r$ singularity build lolcow.sif docker://godlovedc/lolcow INFO: Starting build... Getting image source signatures Copying blob 9fb6c798fa41 done Copying blob 3b61febd4aef done Copying blob 9d99b9777eb0 done Copying blob d010c8cf75d7 done Copying blob 7fac07fb303e done Copying blob 8e860504ff1e done Copying config 73d5b1025f done Writing manifest to image destination Storing signatures INFO: Creating SIF file... INFO: Build complete: lolcow.sif
Example to build an image from recipe file using fakeroot:
Notice you can't use this feature on login nodes.
[user@dbn503-33-r:]$ srun -N1 t 01:00:00 --pty /bin/bash [user@cn605-16-l$ module load singularity Loading module for Singularity Singularity 3.5 modules now loaded [user@cn605-16-l:containers]$ cat lolcow.def BootStrap: docker From: godlovedc/lolco %post chown root.root /tmp/ apt update -y && apt upgrade -y && apt install vim -y [user@cn605-16-l]$ singularity build --fakeroot lolcow.sif-2 lolcow.def INFO: Starting build... Getting image source signatures Writing manifest to image destination Storing signatures INFO: Running post scriptlet INFO: Creating SIF file... INFO: Build complete: lolcow.sif-2
Simplify the preparation of singularity containers
A Singularity Definition File is like a set of blueprints explaining how to build a custom container. It is the same like Dockerfile but in different syntax. It includes specifics about the base OS to build or the base container to start from, software to install, environment variables to set at runtime, files to add from the host system, and container metadata. Unfortunately writing Singularity recipe or Dockerfile is not the straight forward task, sometimes it require advanced linux knowledge to write them. Hence we are using HPCCM an open source tool to make it easier to generate container specification files.
Example to use HPCCM on ibex:
First load hpccm module (available on ilogin)
[user@cn509-02-r:~]$ module load hpccm Loading module for hpccm hpccm 20.2.0 module now loaded [user@cn509-02-r:~]$
Then write HPCCM high level Python recipe, that will be translated to Dockerfile or Singularity recipe; for example this is an recipe for openmpi image:
[user@cn509-02-r:~]$cat mpi_3.0.0_ubuntu18.py """ MPI Bandwidth Contents: Ubuntu 18.04 GNU compilers (upstream) Mellanox OFED OpenMPI version 3.0.0 """ Stage0 += comment(__doc__, reformat=False) # CentOS base image Stage0 += baseimage(image='ubuntu:18.04') # GNU compilers Stage0 += gnu() # Mellanox OFED Stage0 += mlnx_ofed() # OpenMPI Stage0 += openmpi(configure_opts=['--with-slurm'], infiniband=False, cuda=False, version='3.0.0') # MPI Hello World Stage0 += copy(src='hello_world.c', dest='/var/tmp/hello_world.c') Stage0 += shell(commands=['mpicc -o /usr/local/bin/hello_world /var/tmp/hello_world.c'])
Then you are ready to convert this python recipe to Singularity recipe or Dockerfile:
[user@cn509-02-r:~]$ hpccm --format singularity --recipe ./mpi_3.0.0_ubuntu18.py --singularity-version=3.4 > mpi_3.0.0_ubuntu18.def
Now you are ready to build customized singularity image
[user@cn509-02-r:]$ srun -N1 t 01:00:00 --pty /bin/bash [user@cn605-16-l$ module load singularity Loading module for Singularity Singularity 3.4 modules now loaded [user@cn605-16-l:]$ singularity build --fakeroot mpi_3.0.0_ubuntu18.sif mpi_3.0.0_ubuntu18.def INFO: Starting build... Getting image source signatures Copying blob ab5ef0e58194 skipped: already exists Copying config 0a7908e1b9 done Writing manifest to image destination NFO: Running post scriptlet INFO: Creating SIF file... INFO: Build complete: mpi_3.0.0_ubuntu18.sif
Binding external directories
Binding a directory to your Singularity container allows you to access files in a host system directory from within your container. By default, Singularity will bind your $HOME directory (along with a few other directories such as /tmp and /dev). You can also bind other directories into your Singularity container yourself.
The Singularity action commands (run, exec and shell will accept the --bind/-B command-line option to specify bind paths, and will also honor the $SINGULARITY_BIND or $SINGULARITY_BINDPATH environment variable. The argument for this option is a comma-delimited string of bind path specifications in the format src[:dest[:opts]], where src and dest are paths outside and inside of the container respectively. If dest is not given, it is set equal tosrc. Mount options (opts) may be specified as ro (read-only) or rw (read/write, which is the default). The --bind/-B option can be specified multiple times, or a comma-delimited string of bind path specifications can be used.
$ singularity shell --bind /home/$USER,/ibex/scratch/$USER my-container.sif
Or using the environment variable:
$ export SINGULARITY_BINDPATH="/home/$USER,/ibex/scratch/$USER" $ singularity shell my-container.sif
Interactive Singularity containers
To run a Singularity container image on Ibex interactively,you need to allocate an interactive session and load the Singularity module. In this sample session (user input in bold), an Ubuntu 18.04.2 Singularity container is downloaded and run from Docker Hub. If you want to run a local Singularity container instead of downloading one, just replace the DockerHub URL with the path to your container image file.
[user@dbn503-35-r:~]$ srun -N1 -t 1:0:0 --pty bash srun: job 5696878 queued and waiting for resources srun: job 5696878 has been allocated resources [user@cn603-12-r:~]$ [user@cn603-12-r:/ibex/scratch/user/]$ module load singularity Loading module for Singularity Singularity 3.1.1 modules now loaded [user@cn603-12-r:/ibex/scratch/user/]$ singularity shell docker://ubuntu INFO: Converting OCI blobs to SIF format INFO: Starting build... Getting image source signatures Writing manifest to image destination Storing signatures INFO: Creating SIF file... Singularity ubuntu_latest.sif:/ibex/scratch/user/> Singularity ubuntu_latest.sif:/ibex/scratch/user/> cat /etc/os-release cat /etc/os-release NAME="Ubuntu" VERSION="18.04.2 LTS (Bionic Beaver)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 18.04.2 LTS" VERSION_ID="18.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=bionic UBUNTU_CODENAME=bionic Singularity ubuntu_latest.sif:/ibex/scratch/user/> exit [user@cn603-12-r:~]$ exit
Note that you need to exit your Singularity container as well as your allocated interactive Slurm session when you are done.
Singularity containers in serial batch jobs
Create the singularity image (e.g. serial.sif) from dockerhub , using the command:
singularity build serial.sif docker://chuanwen/cowsay
In the same directory as the singularity image, create a Slurm submission file (e.g. submit_serial.sh) with the contents:
#!/bin/sh #SBATCH --time=01:00:00 #SBATCH --nodes=1 #SBATCH --partition=batch #SBATCH --job-name=serial #SBATCH --output=log_slurm.txt module load singularity/3.5.0 singularity exec serial.sif cowsay 'Hello!'
Submit a job, using the command
sbatch submit_serial.sh
the job finishes, the output (in the log_slurm.txt) will look like
________ < Hello! > -------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
MPI code within a single node (using container MPI)
On your scratch create a C file (e.g. hello_world.c) with the contents:
#include #include #include int main(int argc, char** argv) { // Initialize the MPI environment MPI_Init(NULL, NULL); // Get the number of processes int world_size; MPI_Comm_size(MPI_COMM_WORLD, &world_size); //Get the rank of the process int world_rank; MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); // Get the name of the processor char processor_name[MPI_MAX_PROCESSOR_NAME]; int name_len; MPI_Get_processor_name(processor_name, &name_len); // Get the id of the core int core_id; core_id = sched_getcpu(); // Print off a hello world message printf("host=%s, size=%d, rank=%d, core=%d\n", processor_name, world_size, world_rank, core_id); // Finalize the MPI environment. MPI_Finalize(); }
Create a singularity definition file (e.g. mpi_container.def) with the contents
BootStrap: docker From: centos:7 %post yum -y update yum -y install openmpi3-devel ln -s /usr/lib64/openmpi3/bin/mpicc /usr/bin/mpicc ln -s /usr/lib64/openmpi3/bin/mpirun /usr/bin/mpirun %files hello_world.c /var/tmp/hello_world.c %post mpicc -o /usr/local/bin/hello_world /var/tmp/hello_world.c
Create the singularity image (e.g. mpi_container.sif) from the singularity definition file (mpi_container.def), using the fakeroot feature:
[user@dbn503-33-r:]$ srun -N1 t 01:00:00 --pty /bin/bash [user@cn605-16-l$ module load singularity/3.5 Loading module for Singularity Singularity 3.5 modules now loaded [user@cn605-16-l]$ singularity build --fakeroot mpi_container.sif mpi_container.def
In the same directory as the singularity image, create a Slurm submission file (e.g. submit_mpi_container.sh) with the contents:
#!/bin/bash #SBATCH --time=01:00:00 #SBATCH --nodes=1 #SBATCH --ntasks=20 #SBATCH --partition=batch #SBATCH --job-name=mpi_container #SBATCH --output=log_slurm.txt module load singularity/3.5 singularity exec mpi_container.sif /usr/bin/mpirun -np 20 /usr/local/bin/hello_world
Submit a job, using the command.
sbatch submit_mpi_container.sh
Once the job finishes, the output (in the log_slurm.txt) will look like:
host=cn605-16-r, size=20, rank=1, core=1 host=cn605-16-r, size=20, rank=2, core=2 host=cn605-16-r, size=20, rank=3, core=3 host=cn605-16-r, size=20, rank=4, core=4 host=cn605-16-r, size=20, rank=5, core=5 host=cn605-16-r, size=20, rank=6, core=6 host=cn605-16-r, size=20, rank=7, core=7 host=cn605-16-r, size=20, rank=8, core=8 host=cn605-16-r, size=20, rank=9, core=9 host=cn605-16-r, size=20, rank=10, core=10 host=cn605-16-r, size=20, rank=11, core=11 host=cn605-16-r, size=20, rank=12, core=12 host=cn605-16-r, size=20, rank=13, core=13 host=cn605-16-r, size=20, rank=14, core=14 host=cn605-16-r, size=20, rank=15, core=15 host=cn605-16-r, size=20, rank=16, core=16 host=cn605-16-r, size=20, rank=17, core=17 host=cn605-16-r, size=20, rank=18, core=18 host=cn605-16-r, size=20, rank=19, core=19 host=cn605-16-r, size=20, rank=20, core=20
MPI code over multiple nodes (using host and container MPI)
To run singularity containers with MPI over multiple nodes, the host MPI and the container MPI should be compatible, hence we will create customized container image using hpccm
We will use the same C file (hello_world.c) above and the following hpccm recipe:
[user@cn509-02-r:~]$cat mpi_host_container.py """ MPI Bandwidth Contents: CentOS 7 GNU compilers (upstream) Mellanox OFED OpenMPI version 3.1.2 """ Stage0 += comment(__doc__, reformat=False) # CentOS base image Stage0 += baseimage(image='centos:7') # GNU compilers Stage0 += gnu() # Mellanox OFED Stage0 += mlnx_ofed() # OpenMPI Stage0 += openmpi(configure_opts=['--with-slurm'], infiniband=False, cuda=False, version='3.1.2') # MPI Hello World Stage0 += copy(src='hello_world.c', dest='/var/tmp/hello_world.c') Stage0 += shell(commands=['mpicc -o /usr/local/bin/hello_world /var/tmp/hello_world.c'])
Create the singularity definition file (mpi_host_container.def) from the HPCCM recipe file (mpi_host_container.py)
[user@cn509-02-r:~]$ module load hpccm Loading module for hpccm hpccm 20.2.0 module now loaded [user@cn509-02-r:~]$ hpccm --format singularity --recipe ./mpi_host_container.py --singularity-version=3.5 > mpi_host_container.def
Then you can use the above examples to create the singularity image (mpi_host_container.sif) from the singularity definition file (mpi_host_container.def).
Afterthat, in the same directory as the singularity image (e.g. /ibex/scratch), create a Slurm submission file (e.g. submit_mpi_host_container.sh) with the contents
#!/bin/bash #SBATCH --time=01:00:00 #SBATCH --nodes=2 #SBATCH --ntasks=40 #SBATCH --ntasks-per-node=20 #SBATCH --partition=batch #SBATCH --job-name=mpi_host_container #SBATCH --output=log_slurm.txt module load singularity/3.5 module load openmpi/3.1.2/gnu-8.2.0 mpirun -np 40 singularity exec mpi_host_container.sif /usr/local/bin/hello_world
Submit a job, using the command.
sbatch submit_mpi_host_container.sh
Once the job finishes, the output (in the log_slurm.txt) will look like:
host=cn509-26-r, size=40, rank=11, core=16 host=cn509-26-r, size=40, rank=8, core=12 host=cn509-26-r, size=40, rank=19, core=6 host=cn509-26-r, size=40, rank=0, core=16 host=cn509-26-r, size=40, rank=1, core=4 host=cn509-26-r, size=40, rank=2, core=13 host=cn509-26-r, size=40, rank=3, core=2 host=cn509-26-r, size=40, rank=4, core=17 host=cn509-26-r, size=40, rank=5, core=10 host=cn509-26-r, size=40, rank=6, core=1 host=cn509-26-r, size=40, rank=7, core=5 host=cn509-26-r, size=40, rank=9, core=8 host=cn509-26-r, size=40, rank=10, core=7 host=cn509-26-r, size=40, rank=12, core=9 host=cn509-26-r, size=40, rank=13, core=14 host=cn509-26-r, size=40, rank=14, core=1 host=cn509-26-r, size=40, rank=15, core=0 host=cn509-26-r, size=40, rank=16, core=18 host=cn509-26-r, size=40, rank=17, core=15 host=cn509-26-r, size=40, rank=18, core=17 host=cn512-07-r, size=40, rank=27, core=4 host=cn512-07-r, size=40, rank=26, core=16 host=cn512-07-r, size=40, rank=28, core=18 host=cn512-07-r, size=40, rank=35, core=3 host=cn512-07-r, size=40, rank=38, core=6 host=cn512-07-r, size=40, rank=22, core=10 host=cn512-07-r, size=40, rank=23, core=15 host=cn512-07-r, size=40, rank=25, core=0 host=cn512-07-r, size=40, rank=34, core=7 host=cn512-07-r, size=40, rank=24, core=19 host=cn512-07-r, size=40, rank=31, core=1 host=cn512-07-r, size=40, rank=32, core=17 host=cn512-07-r, size=40, rank=33, core=14 host=cn512-07-r, size=40, rank=20, core=5 host=cn512-07-r, size=40, rank=21, core=4 host=cn512-07-r, size=40, rank=36, core=11 host=cn512-07-r, size=40, rank=37, core=12 host=cn512-07-r, size=40, rank=39, core=9 host=cn512-07-r, size=40, rank=29, core=13 host=cn512-07-r, size=40, rank=30, core=9
Singularity containers on GPU nodes
Singularity natively supports running application containers that use NVIDIA’s CUDA GPU compute framework, or AMD’s ROCm solution. This allows easy access to users of GPU-enabled machine learning frameworks such as tensorflow, regardless of the host operating system. As long as the host has a driver and library installation for CUDA/ROCm then it’s possible to e.g. run tensorflow in an up-to-date Ubuntu 18.04 container, from an older RHEL 6 host. For more info you can visit offical docs
srun -n1 singularity run --nv $IMAGE nvidia-smi WARNING: underlay of /etc/localtime required more than 50 (95) bind mounts WARNING: underlay of /usr/bin/nvidia-smi required more than 50 (443) bind mounts MOFED version '5.1-2.5.8' not available in this container. No matching alternate version found. ============= == PyTorch == ============= NVIDIA Release 20.08 (build 15516749) PyTorch Version 1.7.0a0+8deb4fe Container image Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. Copyright (c) 2014-2020 Facebook Inc. Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) Copyright (c) 2011-2013 NYU (Clement Farabet) Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) Copyright (c) 2006 Idiap Research Institute (Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) Copyright (c) 2015 Google Inc. Copyright (c) 2015 Yangqing Jia Copyright (c) 2013-2016 The Caffe contributors All rights reserved. Various files include modifications (c) NVIDIA CORPORATION. All rights reserved. NVIDIA modifications are covered by the license terms that apply to the underlying project or file. Detected MOFED 5.1-2.5.8. Sun Sep 19 09:27:05 2021 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 465.19.01 Driver Version: 465.19.01 CUDA Version: 11.3 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 NVIDIA GeForce ... On | 00000000:B2:00.0 Off | N/A | | 30% 31C P8 1W / 250W | 1MiB / 11019MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+