Skip to content

Commit

Permalink
Update Singularity guide (#120)
Browse files Browse the repository at this point in the history
Updates the Singularity guide:

* Set `rserver --server-user` in job script
(rocker-org/rocker-versioned2#837)
* Show where R_PROFILE_USER and R_LIBS_USER can be set
  (rocker-org/rocker-versioned2#855)
*  Use rocker/rstudio:4.4.2
* Specify `python3` instead of `python` (the latter may be python 2 or
absent on some hosts)
* Mention Apptainer
* mktemp is simpler and portable-enough (GNU coreutils) for creating
temp dirs
* Simplify creation of various writable directories in container with
`--scratch` and `--workdir`
* Ensure R_LIBS_USER directory exists
* no longer need to create readable database.conf (sqlite seems to be
the default)
* SLURM_CPUS_ON_NODE technically more correct than
SLURM_JOB_CPUS_PER_NODE
  (though shouldn't make a difference with a single-node allocation)

---------

Co-authored-by: eitsupi <[email protected]>
  • Loading branch information
nathanweeks and eitsupi authored Dec 14, 2024
1 parent 700b5d2 commit 25b0f2c
Showing 1 changed file with 35 additions and 36 deletions.
71 changes: 35 additions & 36 deletions use/singularity.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,35 @@ aliases:
- /use/singularity/
---

[Singularity](https://www.sylabs.io/guides/latest/user-guide/) is useful for running containers as an unprivileged user, especially in multi-user environments like High-Performance Computing clusters.
[Singularity](https://docs.sylabs.io/guides/latest/user-guide/) is useful for running containers as an unprivileged user, especially in multi-user environments like High-Performance Computing clusters.
Rocker images can be imported and run using Singularity, with optional custom password support.

:::{.callout-note}

In this guide, *Singularity* can refer to either [SingularityCE](https://sylabs.io/singularity/) or [Apptainer](https://apptainer.org/).
While Apptainer is generally [compatible with Singularity commands and environment variables](https://apptainer.org/docs/user/latest/singularity_compatibility.html), Apptainer users may wish to replace the `singularity` command with `apptainer`, and `SINGULARITY` with `APPTAINER` in environment variables.

:::

## Importing a Rocker Image

Use the `singularity pull` command to import the desired Rocker image from Docker Hub into a (compressed, read-only) Singularity Image File:

```bash
singularity pull docker://rocker/rstudio:4.2
singularity pull docker://rocker/rstudio:4.4.2
```

If additional Debian (or other) software packages are needed, a Rocker base image can be extended in a [Singularity definition file](https://sylabs.io/guides/3.7/user-guide/definition_files.html).
Note that sudo privileges are required to use the `singularity build` command, unless using a remote builder such as the [Sylabs Cloud Remote Builder](https://cloud.sylabs.io/builder).
Alternatively, a Rocker base image can be extended in a Dockerfile and a Singularity image built using the [docker2singularity](https://github.com/singularityhub/docker2singularity) Docker image.
If additional Linux software packages are needed, a new container image must be built using the Rocker image as the base image; see the [SingularityCE](https://docs.sylabs.io/guides/latest/user-guide/build_a_container.html) and [Apptainer](https://apptainer.org/docs/user/latest/build_a_container.html) guides for building container images.
Modifications to the base Rocker image are not needed for installing R packages into a personal library in the user's home directory.

## Running a Rocker Singularity container (localhost, no password)

```bash
mkdir -p run var-lib-rstudio-server

printf 'provider=sqlite\ndirectory=/var/lib/rstudio-server\n' > database.conf

singularity exec \
--bind run:/run,var-lib-rstudio-server:/var/lib/rstudio-server,database.conf:/etc/rstudio/database.conf \
rstudio_4.2.sif \
/usr/lib/rstudio-server/bin/rserver --www-address=127.0.0.1
--scratch /run,/var/lib/rstudio-server \
--workdir $(mktemp -d) \
rstudio_4.4.2.sif \
rserver --www-address=127.0.0.1 --server-user=$(whoami)
```

This will run rserver in a Singularity container.
Expand All @@ -44,12 +46,12 @@ To enable password authentication, set the PASSWORD environment variable and add

```bash
PASSWORD='...' singularity exec \
--bind run:/run,var-lib-rstudio-server:/var/lib/rstudio-server,database.conf:/etc/rstudio/database.conf \
rstudio_4.2.sif \
/usr/lib/rstudio-server/bin/rserver --auth-none=0 --auth-pam-helper-path=pam-helper --server-user=$(whoami)
--scratch /run,/var/lib/rstudio-server \
rstudio_4.4.2.sif \
rserver --auth-none=0 --auth-pam-helper-path=pam-helper --server-user=$(whoami)
```

After pointing your browser to http://_hostname_:8787, enter your local user ID on the system as the username, and the custom password specified in the PASSWORD environment variable.
After pointing your browser to http://*hostname*:8787, enter your local user ID on the system as the username, and the custom password specified in the PASSWORD environment variable.

## Additional Options for RStudio >= 1.3.x

Expand Down Expand Up @@ -78,31 +80,24 @@ The following example illustrates how this may be done with a SLURM job script.

# Create temporary directory to be populated with directories to bind-mount in the container
# where writable file systems are necessary. Adjust path as appropriate for your computing environment.
workdir=$(python -c 'import tempfile; print(tempfile.mkdtemp())')

mkdir -p -m 700 ${workdir}/run ${workdir}/tmp ${workdir}/var/lib/rstudio-server
cat > ${workdir}/database.conf <<END
provider=sqlite
directory=/var/lib/rstudio-server
END
workdir=$(mktemp -d)

# Set OMP_NUM_THREADS to prevent OpenBLAS (and any other OpenMP-enhanced
# libraries used by R) from spawning more threads than the number of processors
# allocated to the job.
#
# Set R_LIBS_USER to a path specific to rocker/rstudio to avoid conflicts with
# Set R_LIBS_USER to an existing path specific to rocker/rstudio to avoid conflicts with
# personal libraries from any R installation in the host environment

cat > ${workdir}/rsession.sh <<END
cat > ${workdir}/rsession.sh <<"END"
#!/bin/sh
export OMP_NUM_THREADS=${SLURM_JOB_CPUS_PER_NODE}
export R_LIBS_USER=${HOME}/R/rocker-rstudio/4.2
exec /usr/lib/rstudio-server/bin/rsession "\${@}"
export R_LIBS_USER=${HOME}/R/rocker-rstudio/4.4.2
mkdir -p "${R_LIBS_USER}"
## custom Rprofile & Renviron (default is $HOME/.Rprofile and $HOME/.Renviron)
# export R_PROFILE_USER=/path/to/Rprofile
# export R_ENVIRON_USER=/path/to/Renviron
exec /usr/lib/rstudio-server/bin/rsession "${@}"
END

chmod +x ${workdir}/rsession.sh

export SINGULARITY_BIND="${workdir}/run:/run,${workdir}/tmp:/tmp,${workdir}/database.conf:/etc/rstudio/database.conf,${workdir}/rsession.sh:/etc/rstudio/rsession.sh,${workdir}/var/lib/rstudio-server:/var/lib/rstudio-server"
export SINGULARITY_BIND="${workdir}/rsession.sh:/etc/rstudio/rsession.sh"

# Do not suspend idle sessions.
# Alternative to setting session-timeout-minutes=0 in /etc/rstudio/rsession.conf
Expand All @@ -113,7 +108,7 @@ export SINGULARITYENV_USER=$(id -un)
export SINGULARITYENV_PASSWORD=$(openssl rand -base64 15)
# get unused socket per https://unix.stackexchange.com/a/132524
# tiny race condition between the python & singularity commands
readonly PORT=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()')
readonly PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()')
cat 1>&2 <<END
1. SSH tunnel from your workstation using the following command:
Expand All @@ -134,12 +129,16 @@ When done using RStudio Server, terminate the job by:
scancel -f ${SLURM_JOB_ID}
END

singularity exec --cleanenv rstudio_4.2.sif \
/usr/lib/rstudio-server/bin/rserver --www-port ${PORT} \
singularity exec --cleanenv \
--scratch /run,/tmp,/var/lib/rstudio-server \
--workdir ${workdir} \
rstudio_4.4.2.sif \
rserver --www-port ${PORT} \
--auth-none=0 \
--auth-pam-helper-path=pam-helper \
--auth-stay-signed-in-days=30 \
--auth-timeout-minutes=0 \
--server-user=$(whoami) \
--rsession-path=/etc/rstudio/rsession.sh
printf 'rserver exited' 1>&2
```
Expand Down

0 comments on commit 25b0f2c

Please sign in to comment.