Example 2: Python/Conda Job

This example shows how to build a small Apptainer image for a CPU-only Python calculation. The image starts from a public Docker Python image, installs Miniforge, creates a Conda environment inside the image, and runs a simple prime-number calculation through Slurm.

Use this pattern when your workflow needs Python packages but does not need a GPU.

1. Connect to the CoSTAR cluster

Open a terminal and connect to the CoSTAR login node:

ssh ab1234@costar-login01

Replace ab1234 with your University username.

2. Create the Apptainer definition file

Download the definition file, or create a file called example-02-python.def in your working directory and copy in the recipe below.

The Bootstrap: docker and From: python:3.12-slim lines tell Apptainer to build the image from the public Docker Hub Python image. The %post section installs Miniforge and creates a Conda environment called costar-example inside the image.

example-02-python.def (click to collapse / view)
 1Bootstrap: docker
 2From: python:3.12-slim
 3
 4%post
 5    apt-get update
 6    apt-get install -y --no-install-recommends bzip2 ca-certificates curl
 7    rm -rf /var/lib/apt/lists/*
 8
 9    curl -L -o /tmp/miniforge.sh \
10        https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh
11    bash /tmp/miniforge.sh -b -p /opt/conda
12    rm /tmp/miniforge.sh
13
14    /opt/conda/bin/conda create -y -n costar-example python=3.12 numpy
15    /opt/conda/bin/conda clean -afy
16
17%environment
18    export PATH=/opt/conda/envs/costar-example/bin:/opt/conda/bin:$PATH
19    export PYTHONUNBUFFERED=1
20
21%runscript
22    exec /opt/conda/envs/costar-example/bin/python "$@"
23
24%labels
25    Author CoSTAR
26    Description "CPU-only Python/Conda example for CoSTAR tutorials"

3. Create the Python script

Download the Python script, or create a file called example-02-python.py in your working directory and copy in the script below.

example-02-python.py (click to collapse / view)
 1import sys
 2
 3import numpy as np
 4
 5
 6def is_prime(number):
 7    if number < 2:
 8        return False
 9    if number == 2:
10        return True
11    if number % 2 == 0:
12        return False
13
14    limit = int(np.sqrt(number)) + 1
15    for factor in range(3, limit, 2):
16        if number % factor == 0:
17            return False
18    return True
19
20
21def main():
22    upper_limit = 100_000
23    primes = [number for number in range(2, upper_limit + 1) if is_prime(number)]
24
25    print("Hello from a Python/Conda environment inside Apptainer")
26    print(f"Python executable: {sys.executable}")
27    print(f"NumPy version: {np.__version__}")
28    print(f"Prime search limit: {upper_limit}")
29    print(f"Number of primes found: {len(primes)}")
30    print(f"Largest prime found: {primes[-1]}")
31
32
33if __name__ == "__main__":
34    main()

4. Build the Apptainer image

Note

On CoSTAR, Apptainer is available on compute nodes, not on the login node. If you want to build the image on the cluster, start an interactive Slurm session on a compute node first.

Start an interactive Slurm session for one hour. This does not request a GPU and only needs minimal resources for the build, so Slurm can choose any available node on any partition:

srun -N 1 --time=00-01:00:00 --pty bash

The image is lightweight and based on python:3.12-slim, so the build may only take around 10 minutes. The one-hour allocation gives some buffer for queueing, pulling the base image, and installing the Conda packages.

To build the image use:

apptainer build example-02-python.sif example-02-python.def

When the build finishes, exit the interactive session:

exit

5. Create the submission script

Download the example submission script, or create a file called example-02-python.sh in your working directory and copy in the script below.

The job script runs example-02-python.py inside the Apptainer image built in step 4.

example-02-python.sh (click to collapse / view)
 1#!/bin/bash
 2
 3#SBATCH --job-name=python-conda
 4#SBATCH --partition=main
 5#SBATCH --time=00:10:00
 6#SBATCH --nodes=1
 7#SBATCH --ntasks=1
 8#SBATCH --cpus-per-task=1
 9#SBATCH --mem=2G
10#SBATCH --output=slurm.%N.%j.out
11#SBATCH --error=slurm.%N.%j.err
12
13apptainer run example-02-python.sif example-02-python.py

This example uses apptainer run because the definition file contains a %runscript section:

%runscript
    exec /opt/conda/envs/costar-example/bin/python "$@"

When you run:

apptainer run example-02-python.sif example-02-python.py

Apptainer executes the image’s runscript and passes example-02-python.py to it.

You can also use apptainer exec to specify the command directly:

apptainer exec example-02-python.sif python example-02-python.py

Use apptainer run when the image defines a useful default command in %runscript. Use apptainer exec when you want to explicitly choose the command to run inside the image.

6. Submit your job

Submit the script to the Slurm scheduler:

sbatch example-02-python.sh

You can check the status of your job by running:

squeue --me

7. Check the output

When the job finishes, Slurm writes the standard output and error streams to files in the submission directory:

  • slurm.<node>.<job_id>.out contains normal output from the calculation.

  • slurm.<node>.<job_id>.err contains error messages, if any were produced.

The output file should show the Python executable inside the container, the NumPy version, the prime search limit, the number of primes found, and the largest prime found.

For example, the .out file should contain output similar to:

Hello from a Python/Conda environment inside Apptainer
Python executable: /opt/conda/envs/costar-example/bin/python
NumPy version: 2.4.5
Prime search limit: 100000
Number of primes found: 9592
Largest prime found: 99991