This guide explains how to build and run a Docker container on the Alps system using Podman, Enroot, and SLURM. Follow the steps carefully to set up your environment and run workloads inside a container.
Navigate to your project location and create a folder to store your Dockerfile and the .sqsh file (SquashFS image) generated from the Docker image.
cd /capstor/store/cscs/sdsc/<project-name>
mkdir MyDocker && cd MyDockerFROM nvcr.io/nvidia/pytorch:24.01-py3
ENV DEBIAN_FRONTEND=noninteractive
# Install python venv and OpenCV dependencies, then clean up
RUN apt-get update && apt-get install -y \
python3.10-venv \
libgl1 \
libglib2.0-0 \
libsm6 \
libxrender1 \
libxext6Now that we’ve set up the Dockerfile, we can pass it to Podman to build a container. Podman requires some storage configuration. Create the following file:
vim $HOME/.config/containers/storage.confInsert this content:
[storage]
driver = "overlay"
runroot = "/dev/shm/$USER/runroot"
graphroot = "/dev/shm/$USER/root"
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs-1.13"To build a container with Podman, request a compute node shell from SLURM, pass the Dockerfile to Podman, and finally import the built container using Enroot.
srun --partition debug --pty bashpodman build -t ExampleDocker .Use Enroot to convert the Podman image into an Enroot-compatible SquashFS image:
enroot import -x mount -o ExampleDocker.sqsh podman://ExampleDockerExit the SLURM allocation:
exitAt this point, you should see both the Dockerfile and the new .sqsh file, an example below:
ls -l /capstor/store/cscs/sdsc/<project-name>/MyDocker
...
-rw-r-----+ 1 ssaha sd24 16440033280 Aug 5 18:28 ExampleDocker.sqsh
-rw-rw----+ 1 ssaha sd24 1446 Aug 5 18:25 Dockerfile
...We need to set up an EDF (Environment Definition File) to tell SLURM which container to use. Create the file:
vim ~/.edf/ExampleDocker.tomlInsert the following:
image = "/capstor/store/cscs/sdsc/<project-name>/MyDocker/ExampleDocker.sqsh"
mounts = ["/capstor", "/users"]
writable = true
[annotations]
com.hooks.aws_ofi_nccl.enabled = "true"
com.hooks.aws_ofi_nccl.variant = "cuda12"
[env]
FI_CXI_DISABLE_HOST_REGISTER = "1"
FI_MR_CACHE_MONITOR = "userfaultfd"
NCCL_DEBUG = "INFO"
srun --environment=ExampleDocker --container-workdir=$PWD --pty bashpython -m venv --system-site-packages ./<ExampleEnv>source /capstor/store/cscs/sdsc/<project-name>/ExampleDocker/ExampleEnv/bin/activateInstall required packages:
python -m pip install \
omegaconf==2.3.0 \
opencv-python==4.9.0.80 \
tensorboardX==2.6 \
tensorboard==2.15.1 \
h5py==3.14.0 \
scikit-image==0.25.2
#!/bin/bash
#SBATCH --job-name=cad
#SBATCH --partition debug
#SBATCH --nodes=1
#SBATCH --gpus-per-node=4
#SBATCH --exclusive
#SBATCH --time=00:15:00
##SBATCH --environment=taming-transformer-pytorch-250325
#SBATCH --account=sd24
#SBATCH --output=/capstor/scratch/cscs/ssaha/Experiments/CAD-August-8-2025/daint_exp_07-08-2025-001_debug/bs_0_ngpu_4_250808_1141_70540/slurm_out_%j.out # Output log file
CONFIG=no-defined
CODE_PATH=/capstor/scratch/cscs/ssaha/Jobs/cad
CODE_TARGZ_FILE_NAME=250808_114151_cd6941f6.tar.gz
echo "*** CONFIG ***"
echo $CONFIG
echo "*** CODE_PATH ***"
echo $CODE_PATH
echo "*** CODE_FOLDER_NAME ***"
echo 250808_114151_cd6941f6
echo "*** CODE_TARGZ_FILE_NAME ***"
echo $CODE_TARGZ_FILE_NAME
# Path to your Docker environment config
TOML_PATH="/users/ssaha/.edf/ExampleDocker.toml"
# Distributed training setup
# export MASTER_ADDR=$(hostname) # Activate if you use DistributedDataParallel instead of DataParallel in PyTorch
# export MASTER_PORT=29501 # Activate if you use DistributedDataParallel instead of DataParallel in PyTorch
export OMP_NUM_THREADS=4
# Setting the codebase path to PYTHONPATH
export PYTHONPATH=/capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad/:$PYTHONPATH
echo "*** PYTHONPATH ***"
echo $PYTHONPATH
srun --export=ALL,CONFIG="$CONFIG",CODE_PATH="$CODE_PATH",CODE_TARGZ_FILE_NAME="$CODE_TARGZ_FILE_NAME" \
--environment=$TOML_PATH \
-u -l \
bash -c '
# Extract codebase
echo "mkdir -p /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad"
mkdir -p /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad
echo "tar -xzf $CODE_PATH/$CODE_TARGZ_FILE_NAME -C /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad/ --strip-components=1"
tar -xzf $CODE_PATH/$CODE_TARGZ_FILE_NAME -C /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad/ --strip-components=1
# Change directory to code folder
echo "cd /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad/"
cd /capstor/scratch/cscs/ssaha/Code/250808_114151_cd6941f6/cad/
echo "[Node $SLURM_PROCID] In container: $(hostname)"
echo "[Node $SLURM_PROCID] PWD: $(pwd)"
# ✅ Activate your virtual environment inside the container
echo "source /capstor/store/cscs/sdsc/sd24/docker4cad/python_venv/cad/bin/activate"
source /capstor/store/cscs/sdsc/sd24/docker4cad/python_venv/cad/bin/activate
set -x
echo ""
echo "*** which python"
which python
# echo "*** which torchrun"
# which torchrun
# ✅ Optional sanity checks
python -c "import torch; print(\"Torch version:\", torch.__version__)"
python -c "import omegaconf; print(\"OmegaConf OK\")"
python -c "import cv2; print(\"cv2 OK\")"
# Numeric safety settings
export NVIDIA_TF32_OVERRIDE=0 # Disable TF32 in all CUDA libraries
export TORCH_FLOAT32_MATMUL_PRECISION=highest # Use highest precision for PyTorch GEMMs
echo "*** Numeric Safety Settings ***"
echo "NVIDIA_TF32_OVERRIDE=$NVIDIA_TF32_OVERRIDE"
echo "TORCH_FLOAT32_MATMUL_PRECISION=$TORCH_FLOAT32_MATMUL_PRECISION"
# Use this for Distributed Data Parallel
# python -m torch.distributed.run --standalone --nproc-per-node=4 main.py $CONFIG
# Use this for Data Parallel
export CUDA_VISIBLE_DEVICES=0,1,2,3
python -m scripts_2_5d_3d/main_CAD.py
'
echo "✅ Finished at: $(date)"
Running multiple job steps in parallel on the same allocated set of nodes can improve resource utilization by taking advantage of all the available CPUs, GPUs, or memory within a single job allocation. Please visit the CSCS documentation for more details. Below is an example SLURM job script that submits four training jobs to the four GPUs on a single compute node.
#!/bin/bash
## SBATCH --partition=debug # TODO
#SBATCH --job-name=cad
#SBATCH --exclusive
#SBATCH --mem=450G
#SBATCH -N1
#SBATCH --time=24:00:00
#SBATCH --account=sd24
#SBATCH --output=/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/SLURM_OUTPUT_FILES/251014_2117_93f05/slurm_master_%j.out
TOML_PATH="/users/ssaha/.edf/docker4cad.toml"
echo "*** code_path ***"; echo "/capstor/scratch/cscs/ssaha/Jobs/cad"
echo "*** CODE_FOLDER_NAME ***"; echo "251014_211708_6cc5eae4"
echo "*** code_targz_file_name ***"; echo "251014_211708_6cc5eae4.tar.gz"
# ---------- 1) Prep (no GPU) ----------
echo ">>> [prep] Extracting code and verifying environment..."
mkdir -p /capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad
tar -xzf "/capstor/scratch/cscs/ssaha/Jobs/cad/251014_211708_6cc5eae4.tar.gz" -C /capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad --strip-components=1
# ---------- 2) Parallel training helper (1 GPU per step) ----------
launch_step () {
local SET="$1"; shift
local LOG="/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/SLURM_OUTPUT_FILES/251014_2117_93f05/slurm_${SET}_%j.out"
local ARGS=("$@")
mkdir -p -- "$(dirname "$LOG")"
srun --export=NONE \
--environment="$TOML_PATH" \
-N1 \
--ntasks-per-node=1 \
--exclusive \
--gpus-per-task=1 \
--cpus-per-gpu=16 \
--mem=50G \
-u -l \
--output="$LOG" \
bash -c '
set -euo pipefail
echo "[Node $SLURM_PROCID] In container: $(hostname)"
echo "[Node $SLURM_PROCID] PWD: $(pwd)"
source /capstor/store/cscs/sdsc/sd24/docker4cad/python_venv/cad/bin/activate
set -x
echo \" \"
echo \"*** which python\"
which python
echo \"*** which torchrun\"
which torchrun
# ✅ Optionally sanity check
python -c "import torch; print(\"*** Torch version: ***\", torch.__version__)"
python -c "import omegaconf; print(\"*** OmegaConf OK ***\")"
python -c "import cv2; print(\"*** cv2 OK ***\")"
# step-local thread
export OMP_NUM_THREADS=1
export MKL_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
cd "/capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad"
echo "PWD: $(pwd)"
export PYTHONPATH="/capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad:/capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad/scripts_2_5d_3d:${PYTHONPATH:-}"
mkdir -p -- "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/caches" "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/models"
PYMAIN="/capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad/scripts_2_5d_3d/main_CAD_modified_October_10_2025.py"
[ -f "$PYMAIN" ] || { echo "FATAL: $PYMAIN not found" >&2; ls -la "/capstor/scratch/cscs/ssaha/Code/251014_211708_6cc5eae4/cad"; exit 2; }
python "$PYMAIN" \
"$@"
' _ "${ARGS[@]}" &
}
# ---------- 3) Four parallel steps ----------
launch_step "SET-1" \
--cfg "2d_cremiA_bs16_ps256_loss0.0_slice1.0_cross1.0_interaction1.0" \
--cfg_3d "3d_cremiA_h160_noft_lr_ratio1_ft10000" \
--cache_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/caches" \
--save_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/models" \
--resume "false" \
--model_id -1 \
--model_name "" \
--display_freq 100 \
--valid_freq 10000 \
--save_freq 10000 \
--batch_size 16 \
--num_workers 4 \
--batch_size_3d 2 \
--num_workers_3d 2 \
--data_folder "/capstor/scratch/cscs/ssaha/Datasets/PSI/ALBUM" \
--dataset_name "cremiA" \
--valid_dataset "cremiA" \
--dataset_name_3d "cremiA"
launch_step "SET-2" \
--cfg "2d_cremiA_bs16_ps256_loss0.0_slice1.0_cross1.0_interaction1.0" \
--cfg_3d "3d_cremiA_h160_noft_lr_ratio1_ft10000" \
--cache_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/caches" \
--save_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/models" \
--resume "false" \
--model_id -1 \
--model_name "" \
--display_freq 100 \
--valid_freq 10000 \
--save_freq 10000 \
--batch_size 16 \
--num_workers 4 \
--batch_size_3d 2 \
--num_workers_3d 2 \
--data_folder "/capstor/scratch/cscs/ssaha/Datasets/PSI/ALBUM" \
--dataset_name "cremiB" \
--valid_dataset "cremiB" \
--dataset_name_3d "cremiB"
launch_step "SET-3" \
--cfg "2d_cremiA_bs16_ps256_loss0.0_slice1.0_cross1.0_interaction1.0" \
--cfg_3d "3d_cremiA_h160_noft_lr_ratio1_ft10000" \
--cache_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/caches" \
--save_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/models" \
--resume "false" \
--model_id -1 \
--model_name "" \
--display_freq 100 \
--valid_freq 10000 \
--save_freq 10000 \
--batch_size 16 \
--num_workers 4 \
--batch_size_3d 2 \
--num_workers_3d 2 \
--data_folder "/capstor/scratch/cscs/ssaha/Datasets/PSI/ALBUM" \
--dataset_name "cremiC" \
--valid_dataset "cremiC" \
--dataset_name_3d "cremiC"
launch_step "SET-4" \
--cfg "2d_wafer4_bs16_ps256_loss0.0_slice1.0_cross1.0_interaction1.0_original" \
--cfg_3d "3d_wafer4_h160_noft_lr_ratio1_ft10000_original" \
--cache_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/caches" \
--save_path "/capstor/scratch/cscs/ssaha/Experiments/ALBUM-CAD-October-14-2025-001/models" \
--resume "false" \
--model_id -1 \
--model_name "" \
--display_freq 100 \
--valid_freq 10000 \
--save_freq 10000 \
--batch_size 16 \
--num_workers 4 \
--batch_size_3d 2 \
--num_workers_3d 2 \
--data_folder "/capstor/scratch/cscs/ssaha/Datasets/PSI/ALBUM" \
--dataset_name "wafer4" \
--valid_dataset "wafer4" \
--dataset_name_3d "wafer4"
wait
echo "✅ All jobs finished at: $(date)"
### 📚 BibTeX Citation
```bibtex
@misc{cscs_llm_inference_tutorial,
title = {LLM Inference Tutorial: Build a Modified NGC PyTorch Container},
author = {{Swiss National Supercomputing Centre (CSCS)}},
year = {2025},
howpublished = {\url{https://docs.cscs.ch/tutorials/ml/llm-inference/#build-a-modified-ngc-pytorch-container}},
note = {Accessed: 2025-08-27}
}