Introduction to containers

Overview

Teaching: 10 min
Exercises: 0 min
Questions
  • What are containers for?

  • Who is using containers in HPC ecosystems?

Objectives
  • Define the term: “container” in contrast to “virtual machine”

  • Define other terms, such as image and registry

  • Discuss when you would benefit from using containers in your workflow

What is a container?

A container is a way of running one or more applications in an isolated software environment. The applications, tools, libraries and configuration they need are packaged together in a container image.

Containers are used to distribute software with its dependencies, avoid conflicts between software environments and make workflows easier to reproduce and move between compatible systems. They can be used across personal computers, cloud platforms and HPC systems.

Containers vs Virtual Machines

If you understand the general concept of a virtual machine (VM), either on your own computer (for example, using VirtualBox) or through a cloud provider such as Azure, you’re already familiar with some of the concepts needed to understand containers.

Architecture of virtual machines and containers

VMs and containers provide isolation in different ways. A VM behaves like a complete computer running inside another computer, with its own guest operating system and kernel. A container isolates processes but does not boot its own kernel. Instead, applications inside containers use the host system’s Linux kernel. (More generally, containers share the host system’s kernel rather than running their own.)

The container image supplies the user-space environment required by the application, including applications, tools, libraries and a filesystem.

By sharing the host kernel, containers are generally:

Container images are also typically built as specialised software environments for a particular application or workflow. This specialisation is a usage convention rather than an architectural difference: an image can contain several applications and tools, but they usually serve a common purpose.

Because containerised applications use the host kernel and CPU architecture, they must be compatible with the host system. For example, Linux containers require a compatible Linux kernel, and an image built for an x86_64 CPU does not normally run on an arm64 system, or vice versa. (Cross-architecture execution may be possible through emulation, but it is generally not appropriate for HPC workloads.)

Why use containers?

There are a number of reasons for using containers in your daily work:

A few examples of how containers are being used at Pawsey include:

Terminology

An image is a file (or set of files) that contains an application together with its software dependencies, libraries, tools, run-time environment and filesystem. Images can be copied, shared, uploaded and downloaded.

A container is a running instance of an image. In other words, it is a process that has been started from an image. Multiple containers can be launched from the same image, just as the same application can be run multiple times with different inputs or options.

In abstract, an image corresponds to a file, whereas a container corresponds to a process.

A registry is a service that stores and distributes container images. Registries can be public (for example, Docker Hub or Quay.io) or private. Users can download images from registries and, where permitted, upload their own images for others to use.

A container engine is the software used to create, download and run containers. Examples include Docker, Singularity and Apptainer.

To build an image, we normally use a recipe describing how the image should be assembled. Most recipes start from an existing image that provides a base software environment, and then specify the additional applications, libraries, tools and configuration to include. This recipe is called a Definition File (or def file) in the Singularity and Apptainer ecosystems, and a Dockerfile in the Docker ecosystem.

Container engines

A number of tools are available to create, distribute and run containerised applications. Some of these will be covered throughout this tutorial:

Other container engines (not covered here) include:

Image formats

Most images distributed through registries such as Docker Hub and Quay.io use the container image structure standardised by the Open Container Initiative (OCI). OCI is an industry project that defines open standards for container images, their distribution through registries and their execution by compatible container runtimes. Modern Docker images are generally OCI-compatible, which allows them to be used by container engines other than Docker.

SingularityCE normally stores containers using the Singularity Image Format (SIF), commonly as a single .sif file. SingularityCE can pull Docker/OCI images from compatible registries and convert their contents into SIF for use with its native runtime. Therefore, an image published for Docker can often be pulled and used with SingularityCE, even though the original registry image and the resulting SIF file use different image formats.

Container registries

Most users do not create container images from scratch. Instead, they search for images prepared by software developers, research groups, collaborators or hardware vendors.

Container images are commonly published through online registries and container libraries. Public services include:

Organisations may also operate private registries for images intended for internal or restricted use. For example, NVIDIA publishes GPU-optimised AI and HPC images through the NVIDIA NGC Catalog, while AMD publishes official ROCm images through its ROCm organisation on Docker Hub.

A common workflow is:

  1. Search a registry or container library for an existing image.
  2. Download (or pull) the image.
  3. Run the required software from the image.

If no existing image fully meets your requirements, you can use a suitable image as a base and build a customised image that includes the additional applications and configuration required for your workflow.

Container Workflow

Get ready for the hands-on

Before we start, let us ensure we have the required files to run the tutorials.

If you haven’t done so already, move to a suitable working directory and download the following GitHub repository. On Pawsey systems, use your scratch directory; on other HPC or cloud systems, use the equivalent working directory recommended by the system administrators.

$ cd "$MYSCRATCH"    # On Pawsey systems
$ git clone https://github.com/PawseySC/singularity-containers
$ export TUTO="$PWD/singularity-containers"
$ cd "$TUTO"
Content update required — start
Update the following hands-on instructions

Want to save time later in the tutorial?

Read this

Open a second terminal in the machine where you’re running the tutorial, then run the script pull_big_images.sh to start downloading a few images that you’ll require later:

$ cd $TUTO/demos
$ nohup bash ./pull_big_images.sh &

Alternatively, if you are running at Pawsey, e.g. on Zeus, submit this other script with Slurm instead:

$ cd $TUTO/demos
$ sbatch ./sbatch_pull_big_images.sh

This pull process will take at least one hour. Meanwhile, you’ll be able to keep on going with this episode in your main terminal window.

Are you running on a shared HPC system?

If you’re running this tutorial on a shared system (e.g. on Zeus or Magnus at Pawsey), you should use one of the compute nodes rather than the login node. You can set this up by using an interactive scheduler allocation, for instance on Zeus with Slurm:

$ salloc -n 1 -t 4:00:00
salloc: Granted job allocation 3453895
salloc: Waiting for resource configuration
salloc: Nodes z052 are ready for job

Key Points

  • Containers allow users to run software directly from pre-built images provided by developers, vendors and collaborators.

  • Containers package applications together with their software environment.

  • Containers share the host system’s kernel instead of running their own.

  • Containers simplify software installation, portability and reproducibility.