Skip to content

Commit

Permalink
Add rstudio-server to r image as rstudio image
Browse files Browse the repository at this point in the history
  • Loading branch information
remlapmot committed Oct 8, 2024
1 parent bb8e032 commit 5083d15
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 1 deletion.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
renv.lock.bak
renv/
.tests.R

# rstudio-server directories
*.config
*.local

# R files
.Rhistory

# metadata directory, ignored in research-template, ignore for rstudio test
metadata/
42 changes: 42 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,45 @@ WORKDIR /workspace
COPY --from=builder /renv /renv
# this will ensure the renv is activated by default
RUN echo 'source("/renv/renv/activate.R")' >> /etc/R/Rprofile.site

#################################################
#
# Add rstudio-server to r image - creating rstudio image
ARG RSTUDIO_BASE_URL="default-arg-to-silence-docker"
ARG RSTUDIO_DEB="default-arg-to-silence-docker"
FROM r as rstudio

# Install rstudio-server (and a few dependencies)
COPY rstudio-dependencies.txt /root/rstudio-dependencies.txt
RUN --mount=type=cache,target=/var/cache/apt /root/docker-apt-install.sh /root/rstudio-dependencies.txt &&\
test -f /var/cache/apt/"${RSTUDIO_DEB}" ||\
/usr/lib/apt/apt-helper download-file "${RSTUDIO_BASE_URL}${RSTUDIO_DEB}" /var/cache/apt/"${RSTUDIO_DEB}" &&\
apt-get install --no-install-recommends -y /var/cache/apt/"${RSTUDIO_DEB}"

# Configuration
## Start by setting up rstudio user using approach in opensafely-core/research-template-docker
RUN useradd rstudio &&\
# Disable rstudio-server authentication
echo "auth-none=1" >> /etc/rstudio/rserver.conf &&\
# Run the server under the single user account
echo "server-user=rstudio" >> /etc/rstudio/rserver.conf &&\
echo "USER=rstudio" >> /etc/environment &&\
# Give the rstudio user sudo (aka root) permissions
usermod -aG sudo rstudio &&\
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers &&\
# Add a home directory for the rstudio user
mkdir /home/rstudio &&\
chown -R rstudio:rstudio /home/rstudio/ &&\
# Use renv R packages
# Remember that the second renv library directory /renv/sandbox/R-4.0/x86_64-pc-linux-gnu/9a444a72
# contains 14 symlinks to 14 of the 15 packages in ${R_HOME}/library which is /usr/lib/R/library/
# so that is already setup
echo "R_LIBS_SITE=/renv/lib/R-4.0/x86_64-pc-linux-gnu" >> /usr/lib/R/etc/Renviron.site &&\
# open RStudio in /workspace
echo "session-default-working-dir=/workspace" >> /etc/rstudio/rsession.conf

COPY rstudio-entrypoint.sh /usr/local/bin/rstudio-entrypoint.sh
COPY rstudio-rprofile.R /home/rstudio/rstudio-rprofile.R

ENV USER rstudio
ENTRYPOINT ["/usr/local/bin/rstudio-entrypoint.sh"]
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,23 @@ Find a previous version at `https://cran.r-project.org/src/contrib/Archive/{PACK
```sh
just add-package PACKAGE@VERSION
```

## Building, testing, and publishing the rstudio image

The rstudio image is based on the r image including rstudio-server. To build run

```sh
just build-rstudio
```

To test that rstudio-server appears at `http://localhost:8787` run

```sh
just test-rstudio
```

And then push the new rstudio image to the GitHub container registry with

```sh
just publish-rstudio
```
10 changes: 9 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ services:
target: add-package
args:
- PACKAGE

rstudio:
extends: r
image: rstudio
build:
target: rstudio
args:
# supplied by just
- RSTUDIO_BASE_URL
- RSTUDIO_DEB
16 changes: 16 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,23 @@ build:
add-package package:
bash ./add-package.sh {{ package }}

# r image containing rstudio-server
build-rstudio:
#!/usr/bin/env bash
set -euo pipefail
# Set RStudio Server .deb filename
export RSTUDIO_BASE_URL=https://download2.rstudio.org/server/focal/amd64/
export RSTUDIO_DEB=rstudio-server-2024.09.0-375-amd64.deb
docker-compose build --pull rstudio

# test the locally built image
test image="r": build
bash ./test.sh "{{ image }}"

# test rstudio-server launches
test-rstudio:
bash ./test-rstudio.sh

# lint source code
lint:
Expand All @@ -36,3 +48,7 @@ lint:
publish:
docker tag r ghcr.io/opensafely-core/r:latest
docker push ghcr.io/opensafely-core/r:latest

publish-rstudio:
docker tag rstudio ghcr.io/opensafely-core/rstudio:latest
docker push ghcr.io/opensafely-core/rstudio:latest
5 changes: 5 additions & 0 deletions rstudio-dependencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
git
libclang-dev
lsb-release
psmisc
sudo
33 changes: 33 additions & 0 deletions rstudio-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

# On Linux set rstudio user id to same as id of host if rstudio user id not already the same
if [ "$HOSTPLATFORM" = "linux" -a "$(id -u rstudio)" != "$HOSTUID" ]; then
usermod -u $HOSTUID rstudio
fi

# Check for 1 .Rproj file
if [ $(find /workspace -type f -name "*.Rproj" | wc -w) -eq 1 ]; then

# Copy in Git user.name and user.email from copied local-gitconfig from additionally mounted volume
if test -f /home/rstudio/local-gitconfig; then
grep -e "\[user\]" -e "name = *" -e "email = *" /home/rstudio/local-gitconfig >> /home/rstudio/.gitconfig
fi

# Avoid Git error: fatal detected dubious ownership of repository if using Git in container
# Without this the Git pane fails to open when RStudio project opened
echo -e "[safe]\n\tdirectory = \"*\"" >> /home/rstudio/.gitconfig

# Open RStudio project on opening RStudio Server session using an rstudio hook in .Rprofile
cat /home/rstudio/rstudio-rprofile.R >> /home/rstudio/.Rprofile
fi

# Set file line endings as crlf if docker run from Windows
if [ "$HOSTPLATFORM" = "win32" ]; then
echo -e "{\n\t\"line_ending_conversion\": \"windows\"\n}" >> /etc/rstudio/rstudio-prefs.json
fi

# Start RStudio Server session in foreground
# Hence don't use `rstudio-server start` which runs in background
# and attempt to capture std out and err to a metadata log file
mkdir -p /workspace/metadata
exec /usr/lib/rstudio-server/bin/rserver --server-daemonize 0 >/workspace/metadata/rstudio.log 2>&1
5 changes: 5 additions & 0 deletions rstudio-rprofile.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
setHook("rstudio.sessionInit", function(newSession) {
if (newSession && is.null(rstudioapi::getActiveProject())) {
rstudioapi::openProject(paste0("/workspace/", list.files(pattern = "Rproj")))
}
}, action = "append")
39 changes: 39 additions & 0 deletions test-rstudio.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash
set -eu

# Detect operating system for `docker run` call
OSTYPEFIRSTFIVE=$(echo "$OSTYPE" | cut -c1-5)
if [[ "$OSTYPEFIRSTFIVE" == "linux" ]]; then
PLATFORM="linux"
else
PLATFORM="somethingelse"
fi

trap "docker stop test_rstudio > /dev/null 2>&1 || true" EXIT

docker run \
--rm \
--init \
--label=opensafely \
--interactive \
--user=0:0 --volume="/${PWD}://workspace" \
--platform=linux/amd64 \
-p=8787:8787 \
--name=test_rstudio \
--hostname=test_rstudio \
--volume="/${HOME}/.gitconfig:/home/rstudio/local-gitconfig" \
--env=HOSTPLATFORM=${PLATFORM} \
--env=HOSTUID=$(id -u) \
--detach \
rstudio > /dev/null 2>&1

sleep 5

status_code=$(curl --write-out %{http_code} --silent --output /dev/null -L --retry 3 --max-time 10 http://localhost:8787)
if [[ "$status_code" -ne 200 ]] ; then
echo "200 response not received from http://localhost:8787"
exit 1
else
echo "200 response successfully received from http://localhost:8787"
exit 0
fi

0 comments on commit 5083d15

Please sign in to comment.