Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/47 update docker based version stable r #48

Merged
merged 15 commits into from
Aug 14, 2024
2 changes: 1 addition & 1 deletion renv.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ would restore the versions as listed in `renv.lock`, and is the go-to command to
By default, development dependencies (like those specified under `Suggests:` in the `DESCRIPTION` file), are not included in `renv.lock`. They can be however included via

```{r, echo = TRUE, eval = FALSE}
renv::snaphot(dev = TRUE)
renv::snapshot(dev = TRUE)
```

Note that, given the default behavior with respect to development dependencies, `renv` might report out-of-sync dependencies upon session startup. Make sure to use
Expand Down
71 changes: 37 additions & 34 deletions version-stable-r-development.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,30 @@ environments or projects.
## Version-stable deployments

When deploying R applications (e.g. a Shiny app) using Docker containers, it is
important to control versioning of R and packages for the sake of reproducibilty
important to control versioning of R and packages for the sake of reproducibility
and stability of the deployments. For this reason,
[version-stable](https://github.com/rocker-org/rocker-versioned) images are
[version-stable](https://github.com/rocker-org/rocker-versioned2) images are
provided as part of the [Rocker project](https://www.rocker-project.org/) and
used as a basis for deploying productive applications.

Each version-stable Rocker image has an associated _tag_ for all non-latest R
versions (e.g. `rocker/r-ver:3.6.1`). Besides being specific to the
versions (e.g. `rocker/r-ver:4.4.1`). Besides being specific to the
corresponding version of R, each tag fixes the version of contributed packages
(by using as package repository the MRAN snapshot of the last day CRAN
(by using as package repository the CRAN snapshot of the last day CRAN
distributed that R version as latest release). See
[VERSIONS.md](https://github.com/rocker-org/rocker-versioned/blob/master/VERSIONS.md)
[wiki/Versions](https://github.com/rocker-org/rocker-versioned2/wiki/Versions).
If that R version is the latest, the CRAN date will not be set and the latest packages will always be installed.


The `Dockerfile` of a deployed application then defines a given version-stable
image tag to start `FROM`, e.g.
```dockerfile
FROM rocker/r-ver:3.6.1
FROM rocker/r-ver:4.4.1
```
See
[SmaRP/Dockerfile](https://github.com/miraisolutions/SmaRP/blob/master/Dockerfile)
[SmaRP/Dockerfile](https://github.com/miraisolutions/SmaRP/blob/feature/upgrade-latest-r/Dockerfile)
for an example.
<!-- NOTE: Not yet merged into master, to be replaced with https://github.com/miraisolutions/SmaRP/blob/master/Dockerfile -->


## Align local development and deployment environments
Expand All @@ -57,7 +60,7 @@ 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](https://www.rocker-project.org/images/#the-versioned-stack), so we could
use e.g. `rocker/rstudio:3.6.1`.
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
Expand All @@ -69,12 +72,12 @@ install. See the specific section below about 'TinyTeX considerations'.

### Running versioned RStudio instances
riccardoporreca marked this conversation as resolved.
Show resolved Hide resolved

Assume we want to run a containerized versioned instance of RStudio for R 3.6.1,
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
```{bash pull}
docker pull rocker/verse:3.6.1
docker pull rocker/verse:4.4.1
```

We then want to have a running instance on `localhost` (`127.0.0.1`), with the
Expand All @@ -83,7 +86,7 @@ following setup:
- No authentication required (local setup).
- Enable root by setting the environment variable `ROOT` to `TRUE`, so that e.g.
`sudo apt-get` can be used in RStudio.
- Use a version-specific port, e.g. `3500` for R 3.5.0, `3610` for R 3.6.1 and
- 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 use `localhost` for concurrent R version instances.
- The development code of all relevant projects should live outside the
container and be shared with it (and possibly many of them), e.g. under
Expand All @@ -94,19 +97,19 @@ the container.
the container user (`rstudio`) must match the UID of the host user (`$UID`).
- In order for the RStudio setting to persist if the container is recreated
(e.g. after pulling a new `rocker` image), we also use a shared volume (like
`~/.rstudio-docker/3.6.1`) for the `home/rstudio/.rstudio` directory, which is
`~/.rstudio-docker/4.4.1`) for the `home/rstudio/.rstudio` directory, which is
version-specific in case of multiple R versions
- If we want to use Meld via the [compareWith](https://github.com/miraisolutions/compareWith/) addins, we need to
- map the `DISPLAY` environment variable and volume `/tmp/.X11-unix`
- add `DISPLAY` to `Renviron`
- install Meld
- install `dbus-x11`
- Use a version-specific name for the container running the RStudio instance,
e.g. `rstudio_3.6.1`.
e.g. `rstudio_4.4.1`.


```{bash run}
R_VER=3.6.1
R_VER=4.4.1
SHARED_DIR=RStudioProjects
docker run -d --restart=always \
-p 127.0.0.1:$(echo $R_VER | sed 's/[.]//g')0:8787 \
Expand All @@ -126,7 +129,7 @@ docker exec rstudio_$R_VER bash -c \
docker exec rstudio_$R_VER bash -c \
'apt-get update && apt-get install -y --no-install-recommends meld dbus-x11'
```
The running RStudio can then be accessed by visiting `http://localhost:3610/`.
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 as follows

Expand All @@ -137,7 +140,7 @@ run_rstudio_ver() {
local RVER_IMAGE=${3:-"verse"}
local BASE_IMAGE=rocker/$RVER_IMAGE:$R_VER
local PORT=$(echo $R_VER | sed 's/[.]//g')0
local CONTANER_NAME=rstudio_$R_VER
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
Expand All @@ -151,41 +154,41 @@ run_rstudio_ver() {
-v $HOME/.rstudio-docker/$R_VER:/home/rstudio/.rstudio \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
--name $CONTANER_NAME \
--name $CONTAINER_NAME \
$BASE_IMAGE &&
# R and RStudio are not getting the DISPLAY environment variable
docker exec $CONTANER_NAME bash -c \
docker exec $CONTAINER_NAME bash -c \
'echo "DISPLAY=${DISPLAY}" >> /usr/local/lib/R/etc/Renviron' &&
# Install Meld
docker exec $CONTANER_NAME bash -c \
docker exec $CONTAINER_NAME bash -c \
'apt-get update && apt-get install -y --no-install-recommends meld dbus-x11' &&
echo "RStudio running in container "$CONTANER_NAME" on port "$PORT &&
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 as follows
```{bash run_rstudio_ver-use}
run_rstudio_ver 3.6.1 RStudioProjects
run_rstudio_ver 4.4.1 RStudioProjects
```

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
```{bash stop}
docker stop rstudio_3.6.1
docker stop rstudio_4.4.1
```
Alternatively, you can omit `--restart=always` and explicitly start the
container whenever needed with
```{bash start}
docker start rstudio_3.6.1
docker start rstudio_4.4.1
```

Note that `start`/`stop` operations do not affect the persistence of files
created outside the shared location, including global RStudio options such as
dark theme, diagnostic, etc. (set via _Tools > Global Options..._). On the other
hand, these files and settings do ~~not~~ (see above) persist removing the
container (`docker rm`, see below) .
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 `~/.rstudio` directory.


### TinyTeX considerations
riccardoporreca marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -212,22 +215,22 @@ If you are using LaTeX and start seeing errors like
```
Remote repository is newer than local (2018 < 2019)
riccardoporreca marked this conversation as resolved.
Show resolved Hide resolved
```
it means that you have to re-install TinyTeX. This happens e.g. with
`rocker/verse:3.6.1`, since it was build at the end of 2018 but the current
you have to re-install TinyTeX. This happens e.g. with
`rocker/verse:4.3.2`, since it was built at the end of 2018 but the current
Tex Live repo is 2019. You can fix this via a **user-specific** re-installation of
TinyTeX for R. **NOTE** however that this will uninstall the system-level
TinyTeX pre-installed in `rocker/verse`.

First, make sure `/home/rstudio/bin` is part of the `PATH` environment variable.
Check this by running
```{bash check-path}
docker exec --user rstudio rstudio_3.6.1 R --slave -e 'Sys.getenv("PATH")'
docker exec --user rstudio rstudio_4.4.1 R --slave -e 'Sys.getenv("PATH")'
riccardoporreca marked this conversation as resolved.
Show resolved Hide resolved
```
If you don't see `/home/rstudio/bin`, you can make sure it is part of the `PATH` for R via
```{bash set-path}
docker exec --user rstudio rstudio_3.6.1 sh -c 'echo "PATH=$HOME/bin:\${PATH}" >> $HOME/.Renviron'
docker exec --user rstudio rstudio_4.4.1 sh -c 'echo "PATH=$HOME/bin:\${PATH}" >> $HOME/.Renviron'
# check again
docker exec --user rstudio rstudio_3.6.1 R --slave -e 'Sys.getenv("PATH")'
docker exec --user rstudio rstudio_4.4.1 R --slave -e 'Sys.getenv("PATH")'
```

Then, from the running RStudio, run
Expand All @@ -239,7 +242,7 @@ tinytex::reinstall_tinytex()
### Cleanup

```{bash cleanup}
docker rm $(docker stop rstudio_3.6.1)
docker rm $(docker stop rstudio_4.4.1)
```


Expand Down