icaoberg / Short intro to Apptainer

Created Tue, 12 May 2026 00:00:00 +0000 Modified Sat, 16 May 2026 15:39:26 -0400
Short intro to Apptainer

Apptainer (formerly Singularity) is a container runtime designed for HPC clusters. Unlike Docker, it does not require a daemon or root privileges to run containers, making it the standard choice on shared systems where users lack admin access.

Key Concepts

  • Image — a single immutable .sif file (Singularity Image Format) that contains the entire container filesystem
  • Definition file — a plain-text recipe (.def) that describes how to build an image, similar to a Dockerfile
  • Bind mount — a way to expose host directories inside the container at runtime

Essential Commands

Command What it does
apptainer build image.sif image.def Build an image from a definition file (requires root or --fakeroot)
apptainer shell image.sif Open an interactive shell inside the container
apptainer exec image.sif <cmd> Run a single command inside the container
apptainer run image.sif Run the container’s default %runscript
apptainer pull docker://ubuntu:22.04 Pull a Docker image and convert it to .sif
apptainer inspect image.sif Show metadata and labels

Definition File Structure

Bootstrap: docker
From: ubuntu:22.04

%post
    apt-get update && apt-get install -y curl

%environment
    export PATH=/opt/myapp/bin:$PATH

%runscript
    exec myapp "$@"

%labels
    Author your.name@example.com
    Version 1.0

Example: Miniconda Container

Bootstrap: docker
From: ubuntu:22.04

%post
    apt-get update && apt-get install -y wget bzip2 ca-certificates && \
    wget -q https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \
         -O /tmp/miniconda.sh && \
    bash /tmp/miniconda.sh -b -p /opt/conda && \
    rm /tmp/miniconda.sh && \
    /opt/conda/bin/conda clean -afy

%environment
    export PATH=/opt/conda/bin:$PATH
    export CONDA_DEFAULT_ENV=base

%runscript
    exec /opt/conda/bin/conda "$@"

%labels
    Description Miniconda3 on Ubuntu 22.04

Build and test:

apptainer build --fakeroot miniconda.sif miniconda.def
apptainer exec miniconda.sif conda --version
apptainer exec miniconda.sif python --version

To create an environment inside the container at build time, add to %post:

/opt/conda/bin/conda create -n myenv python=3.11 numpy pandas -y

Example: PostgreSQL Container

Bootstrap: docker
From: postgres:16

%post
    mkdir -p /var/run/postgresql && \
    chown -R postgres:postgres /var/run/postgresql

%environment
    export PGDATA=/var/lib/postgresql/data
    export POSTGRES_USER=postgres

%startscript
    postgres -D $PGDATA

%labels
    Description PostgreSQL 16

Build and initialize a database:

apptainer build --fakeroot postgres.sif postgres.def

# Initialize a data directory on the host
mkdir -p $HOME/pgdata
apptainer exec \
    --env POSTGRES_PASSWORD=secret \
    --bind $HOME/pgdata:/var/lib/postgresql/data \
    postgres.sif initdb -D /var/lib/postgresql/data

# Start the server
apptainer instance start \
    --bind $HOME/pgdata:/var/lib/postgresql/data \
    postgres.sif pgserver

# Connect
apptainer exec instance://pgserver psql -U postgres

# Stop
apptainer instance stop pgserver

Example: Emacs Container

Bootstrap: docker
From: ubuntu:22.04

%post
    apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
        emacs-nox \
        git \
        ripgrep \
        fd-find && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

%environment
    export TERM=xterm-256color

%runscript
    exec emacs "$@"

%labels
    Description Emacs (no-X) on Ubuntu 22.04

Build and run:

apptainer build --fakeroot emacs.sif emacs.def

# Open a file
apptainer run --bind $HOME:/home/$USER emacs.sif myfile.txt

# Or via exec
apptainer exec --bind $HOME:/home/$USER emacs.sif emacs --batch --eval "(message \"hello\")"

Bind-mount your home directory so Emacs can read your ~/.emacs.d config.


Further Reading