R in an Apptainer Container
When to Use This Approach
Use Apptainer when your workflow depends on software that cannot be installed via spack or the module system — for example a Docker image that bundles a specific R version together with external tools or system libraries your code requires.
If you only need R and standard R packages, use the spack-based workflow in Section 3 instead. Apptainer adds complexity.
The rslurm workflow from Section 3 stays largely the same. The two things that change are: how R is started (via the container instead of directly), and the job template.
Building the Container Image
Apptainer runs containers from a single image file (.sif). The most common
starting point is a Docker image from Docker Hub or a similar registry.
Important for SCC users: building images is possible, but not advised on the login node as it is compute-intensive and slows down the login node for all users. Therefore, start an interactive compute job first:
srun -p scc-cpu -c 8 -N 1 -t 30 --pty bash # interactive session, 8 CPUs, 1 Node, timeout after 30 mins
module load apptainer
Store container images in a personal subdirectory of $PROJECT. Use your first
name or a project name (e.g. $PROJECT/sebastian) rather than $USER — the
HPC account names (u12345) are not recognisable without looking them up.
Create the folder if it doesn't exist yet:
mkdir -p $PROJECT/<name>
Then build the image:
apptainer build $PROJECT/<name>/mycontainer.sif docker://organisation/imagename:tag
The file can be several GB — $PROJECT has more quota than $HOME.
To inspect the container interactively:
apptainer shell --bind $HOME,$PROJECT $PROJECT/<name>/mycontainer.sif
The --bind flag makes HPC filesystems accessible inside the container. Without
it, the container only sees its own internal filesystem.
If your simulation writes temporary files intensively, you can also bind the job-specific temporary directories for better I/O performance:
apptainer shell --bind $HOME,$PROJECT,$LOCAL_TMPDIR $PROJECT/<name>/mycontainer.sif
$LOCAL_TMPDIR (local SSD, fastest) and $SHM_TMPDIR (RAM, fastest but tiny)
are only available inside a running SLURM job, not on the login node. See
Section 2 and the
GWDG temporary storage docs
for details.
Adding R Packages to the Container
If you need R packages beyond what the container already provides, add them to
the Docker image and rebuild the .sif file — do not install packages into your
personal library from inside the container. Ad-hoc installs into $HOME create
a dependency on the container version: if the image is updated, those installs
may break silently.
Update the Dockerfile (or equivalent) upstream, push a new image, then rebuild:
srun -p scc-cpu -c 8 -N 1 -t 30 --pty bash
module load apptainer
apptainer build mycontainer.sif docker://organisation/imagename:tag
Running Parallel Jobs with rslurm
1. Create a job template
The template for container-based jobs extends the one from Section 3 with a
module load apptainer line:
#!/bin/bash
#SBATCH --array=0-{{{max_node}}}{{{job_array_task_limit}}}
#SBATCH --cpus-per-task={{{cpus_per_node}}}
#SBATCH --job-name={{{jobname}}}
#SBATCH --output=slurm_%a.out
{{#flags}}
#SBATCH --{{{name}}}
{{/flags}}
{{#options}}
#SBATCH --{{{name}}}={{{value}}}
{{/options}}
module load apptainer
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
{{{rscript}}} --vanilla slurm_run.R
Save this as submit_template_apptainer.sh locally (e.g. on your laptop).
2. Write the rslurm script locally (e.g. on your laptop)
The key difference from Section 3 is rscript_path: instead of a plain path to
Rscript, it becomes an apptainer exec command that runs Rscript inside the
container. rslurm appends --vanilla slurm_run.R to whatever you put here.
library(rslurm)
sim_fun <- function(param_a, param_b) {
result <- param_a * param_b # replace with your simulation
return(result)
}
params <- data.frame(
param_a = 1:10,
param_b = seq(0.1, 1.0, by = 0.1)
)
sjob <- slurm_apply(
f = sim_fun,
params = params,
jobname = "my_container_sim",
nodes = nrow(params),
cpus_per_node = 1,
rscript_path = "apptainer exec --bind $HOME,$PROJECT $PROJECT/<name>/mycontainer.sif Rscript",
sh_template = "submit_template_apptainer.sh",
slurm_options = list(
"partition" = "scc-cpu",
"time" = "01:00:00",
"mem-per-cpu" = "2G",
"mail-type" = "END,FAIL",
"mail-user" = "your@email.de"
),
submit = FALSE
)
3–5. Transfer, submit, and retrieve results
These steps are identical to Section 3 — transfer the _rslurm_* folder to the
HPC, sbatch submit.sh from Emmy-p3, and rsync results back when done.