2.2 Align local development and deployment environments
When developing and testing an app locally, it is important to ensure the environment is aligned with the target deployment environment. This might imply using e.g. multiple R and package versions for the local development of different applications. This is not possible with the typical setup (especially on Linux systems), where only one R version (the latest release) exists.
The idea is then to rely on the same version-stable rocker containers used for
the deployments, using a containerized versioned RStudio instance for the local
development. This is available through Rocker’s versioned
stack, so we could
use e.g. rocker/rstudio:4.4.1
.
Note that the same version-stable instance of RStudio can be used across all
different projects for which such version is relevant. For this reason, a
sensible choice is to rely on rocker/verse
images, which add tidyverse and
devtools to the stack. They also include R Markdown system
dependencies TinyTeX and pandoc, sparing the effort of the tedious extra
install.
2.2.1 Running versioned RStudio instances
Assume we want to run a containerized versioned instance of RStudio for R 4.4.1, possibly alongside instances for other versions of R.
First of all, we need to get the image from docker-hub:
We then want to have a running instance on localhost
(127.0.0.1
), with the
following setup:
- No authentication required (local setup).
- Enable root by setting the environment variable
ROOT
toTRUE
, so that e.g.sudo apt-get
can be used in RStudio. - Use a version-specific port, e.g.
4000
for R 4.0.0,4410
for R 4.4.1 and so on, so that we can uselocalhost
for concurrent R version instances. We bind the port to localhost (127.0.0.1:4410
), so it is only accessible locally (see the Rocker reference). - The development code of all relevant projects should live outside the
container and be shared with it (and possibly multiple other containers), e.g. under
~/workspace
on the host machine and/home/rstudio/workspace
in the container.- For this to work w/o permission
issues,
the container user (
rstudio
) must match the UID of the host user ($UID
). This has the effect of setting the ownership of~/workspace
on the host machine to$UID
if it is not already owned by that user.
- For this to work w/o permission
issues,
the container user (
- In order for the RStudio settings to persist if the container is recreated
(e.g. after pulling a new
rocker
image), we also use a shared volume (like~/.rstudio-config/4.4.1
) for the/home/rstudio/.config/rstudio
directory, which is version-specific in case of multiple R versions. - If we want to use Meld via the compareWith addins, we need to
- map the
DISPLAY
environment variable and volume/tmp/.X11-unix
, - add
DISPLAY
toRenviron
, - install Meld,
- install
dbus-x11
.
- map the
- Use a version-specific name for the container running the RStudio instance,
e.g.
rstudio_4.4.1
.
R_VER=4.4.1
SHARED_DIR=workspace
mkdir -p $HOME/.rstudio-config/$R_VER
docker run -d --restart=always \
-p 127.0.0.1:$(echo $R_VER | sed 's/[.]//g')0:8787 \
-e DISABLE_AUTH=true \
-e ROOT=true \
-e USERID=$UID \
-e GROUPID=$GID \
-v $HOME/$SHARED_DIR:/home/rstudio/$SHARED_DIR \
-v $HOME/.rstudio-config/$R_VER:/home/rstudio/.config/rstudio \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
--name rstudio_$R_VER \
rocker/verse:$R_VER
# R and RStudio are not getting the DISPLAY environment variable
docker exec rstudio_$R_VER bash -c \
'echo "DISPLAY=${DISPLAY}" >> /usr/local/lib/R/etc/Renviron'
# Install Meld
docker exec rstudio_$R_VER bash -c \
'apt-get update && apt-get install -y --no-install-recommends meld dbus-x11'
If you are using R_VER=4.4.1
, the running RStudio can then be accessed by visiting http://localhost:4410/
.
You may find convenient to define a shell function for these steps:
run_rstudio_ver() {
local R_VER=${1:?"you must supply the R version as first argument"}
local SHARED_DIR=${2:?"you must supply the shared directory as second argument"}
local RVER_IMAGE=${3:-"verse"}
local BASE_IMAGE=rocker/$RVER_IMAGE:$R_VER
local PORT=$(echo $R_VER | sed 's/[.]//g')0
local CONTAINER_NAME=rstudio_$R_VER
echo "Containerized version-stable RStudio for R "$R_VER\
"based on image "$BASE_IMAGE\
"with shared volume "$SHARED_DIR
docker pull $BASE_IMAGE &&
mkdir -p $HOME/.rstudio-config/$R_VER &&
docker run -d --restart=always \
-p 127.0.0.1:$PORT:8787 \
-e DISABLE_AUTH=true \
-e ROOT=true \
-e USERID=$UID \
-e GROUPID=$GID \
-v $HOME/$SHARED_DIR:/home/rstudio/$SHARED_DIR \
-v $HOME/.rstudio-config/$R_VER:/home/rstudio/.config/rstudio \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
--name $CONTAINER_NAME \
$BASE_IMAGE &&
# R and RStudio are not getting the DISPLAY environment variable
docker exec $CONTAINER_NAME bash -c \
'echo "DISPLAY=${DISPLAY}" >> /usr/local/lib/R/etc/Renviron' &&
# Install Meld
docker exec $CONTAINER_NAME bash -c \
'apt-get update && apt-get install -y --no-install-recommends meld dbus-x11' &&
echo "RStudio running in container "$CONTAINER_NAME" on port "$PORT &&
echo "visit http://localhost:"$PORT
}
which you can re-use as compact command for any R version:
Note that --restart=always
specifies that the container should stay up and restart
itself after stopping, e.g. upon machine reboot or docker upgrade, so that it is
always available. Still, you can explicitly stop the running container with
Alternatively, you can omit --restart=always
and explicitly start the
container whenever needed with
Note that start
/stop
operations do not affect the persistence of any files
created in rstudio while the container is running.
However if the container is removed, files created outside of mounted volumes
do not persist (docker rm
, see below).
This is why we use a mounted volume for the ~/.config/rstudio
directory.
2.2.2 Using podman
instead of docker
podman
can be used instead of docker
to run the above commands. In that case, the active user in the container will be root,
which is then mapped to the user that invoked the podman command when writing files to the shared volume.
Because of this, RStudio does not set the desired home directory as the initial working directory. To correct this, add
echo '{ "initial_working_directory": "/home/rstudio" }' > $HOME/.rstudio-config/$R_VER/rstudio-prefs.json &&
After mkdir -p $HOME/.rstudio-config/$R_VER
in the run_rstudio_ver
function.
If you run into issues, the discussion in this rocker pull request
about rootless container support may help.
2.2.3 Best-supported R versions
This tutorial uses images based on the rocker-versioned2 repository. We recommend using the latest patch version for each minor version - e.g. 4.0.5 for 4.0.x, as these seem to be the most regularly updated images (see e.g. rocker/verse on docker hub).