This lesson is being piloted (Beta version)

Containers from definition files

Overview

Teaching: 20 min
Exercises: 20 min
Questions
  • How to easily build and deploy containers from a single definition file?

Objectives
  • Create a container from a definition file.

As shown in the previous chapter, building containers with an interactive session may take several steps, and it can become as complicated as the required setup. An Apptainer definition file provides an easy way to build and deploy containers.

Hello World Apptainer

The following recipe shows how to build a hello-world container, and run the container on your local computer.

Deleting Apptainer image

To delete the hello-world Apptainer image, simply delete the hello-world.sif file.

apptainer delete

Note that there is also a apptainer delete command, but it is to delete an image from a remote library. To learn more about using remote endpoints and pulling and pushing images from or to libraries, read Remote Endpoints and Library API Registries.

Example of a more elaborated definition file

Let’s look at the structure of the definition file with another example. Let’s prepare a container from an official Ubuntu image, but this time we will install ROOT with RooFit and Python integration.

Following the ROOT instructions to download a pre-compiled binary distribution, the definition file will look like

BootStrap: docker
From: ubuntu:20.04

%post
    apt-get update -y
    apt-get install wget -y
    export DEBIAN_FRONTEND=noninteractive
    apt-get install dpkg-dev cmake g++ gcc binutils libx11-dev libxpm-dev \
        libxft-dev libxext-dev python libssl-dev libgsl0-dev libtiff-dev -y
    cd /opt
    wget https://root.cern/download/root_v6.22.06.Linux-ubuntu20-x86_64-gcc9.3.tar.gz
    tar -xzvf root_v6.22.06.Linux-ubuntu20-x86_64-gcc9.3.tar.gz

%environment
    export PATH=/opt/root/bin:$PATH
    export LD_LIBRARY_PATH=/opt/root/lib:$LD_LIBRARY_PATH
    export PYTHONPATH=/opt/root/lib

%runscript
    python /opt/root/tutorials/roofit/rf101_basics.py

%labels
    Author HEPTraining
    Version v0.0.1

%help
    Example container running the RooFit tutorial and producing the rf101_basics.png image.
    The container provides ROOT with RooFit and Python integration running on Ubuntu.

Let’s take a look at the definition file:

Save this definition file as rootInUbuntu.def. To build the container, just provide the definition file as argument (executing as superuser):

apptainer build rootInUbuntu.sif rootInUbuntu.def

Then, an interactive shell inside the container can be initialized with apptainer shell, or a command executed with apptainer exec. A third option is execute the actions defined inside %runscript simply by calling the container as an executable

./rootInUbuntu.sif
RooFit v3.60 -- Developed by Wouter Verkerke and David Kirkby
                Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
                All rights reserved, please read http://roofit.sourceforge.net/license.txt
...
 PARAMETER  CORRELATION COEFFICIENTS
       NO.  GLOBAL      1      2
        1  0.02723   1.000  0.027
        2  0.02723   0.027  1.000
[#1] INFO:Minization -- RooMinimizer::optimizeConst: deactivating const optimization
RooRealVar::mean = 1.01746 +/- 0.0300144  L(-10 - 10)
RooRealVar::sigma = 2.9787 +/- 0.0219217  L(0.1 - 10)
Info in <TCanvas::Print>: png file rf101_basics.png has been created

You will find the output file rf101_basics.png in the location where the container was executed. If you don’t have a DISPLAY setup, Root may complain. Ignore the error messages, the image will be created anyway,

Here we have covered the basics with a few examples focused to HEP software. Check the Apptainer docs to see all the available options and more details related to the container creation.

A few best practices for your containers to make them more usable, portable, and secure:

  1. Always install packages, programs, data, and files into operating system locations (e.g. not /home, /tmp , or any other directories that might get commonly binded on).
  2. Document your container. If your runscript doesn’t supply help, write a %help or %apphelp section. A good container tells the user how to interact with it.
  3. If you require any special environment variables to be defined, add them to the %environment and %appenv sections of the build recipe.
  4. Files should always be owned by a system account (UID less than 500).
  5. Ensure that sensitive files like /etc/passwd, /etc/group, and /etc/shadow do not contain secrets.
  6. Build production containers from a definition file instead of a sandbox that has been manually changed. This ensures the greatest possibility of reproducibility and mitigates the “black box” effect.

Deploying your containers

Keep in mind that, while building a container may be time consuming, the execution can be immediate and anywhere your image is available. Once your container is built with the requirements of your analysis, you can deploy it in a large cluster and execute it as far as Apptainer is available on the site.

Libraries like Sylabs Cloud Library ease the distribution of images. Your institution (e.g. Fermilab or CERN) may provide an Harbor registry. GitHub has a Container Registry that Apptainer can access via the ORAS API. Organizations like OSG provide instructions to use available images and distribute custom images via CVMFS.

Be smart, and this will open endless possibilities in your workflow.

Write a definition file to build a container with Pythia8 available in Python

Following the example of the first section in which a container is built with an interactive session (see the previous episode), write a definition file to deploy a container with Pythia8 available.

Take a look at /opt/pythia/pythia8310/examples/main01.py and define the %runscript to execute it using python3.

(Tip: notice that main01.py requires Makefile.inc).

Solution

BootStrap: docker
From: almalinux:9

%post
    yum -y groupinstall 'Development Tools'
    yum -y install python3-devel
    mkdir /opt/pythia && cd /opt/pythia
    curl -o pythia8310.tgz https://pythia.org/download/pythia83/pythia8310.tgz
    tar xvfz pythia8310.tgz
    cd pythia8310
    ./configure --with-python-include=/usr/include/python3.9
    make

%environment
    export PYTHONPATH=/opt/pythia/pythia8310/lib:$PYTHONPATH
    export LD_LIBRARY_PATH=/opt/pythia/pythia8310/lib:$LD_LIBRARY_PATH

%runscript
    cp /opt/pythia/pythia8310/Makefile.inc .
    python3 /opt/pythia/pythia8310/examples/main01.py

%labels
    Author HEPTraining
    Version v0.0.2

%help
    Container providing Pythia 8.310. Execute the container to run an example.
    Open it in a shell to use the Pythia installation with Python 3.9

Build your container executing

apptainer build pythiaInAlma9.sif myPythia8.def

And finally, execute the container to run main01.py

./pythiaInAlma9.sif

This solution is building Pythia from scratch and may take several minutes to build the container. In the previous episode we saw that binary packages of Pythia are available in EPEL. Use them to build a similar container mych faster.

Key Points

  • An Apptainer definition file provides an easy way to build and deploy containers.