Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6b6a380
gnu: switch to ftpmirror and https
Oct 9, 2025
5b10357
change tag name (temporary)
Oct 15, 2025
7d6f819
r-base - introduce a multi stage build with a non-root user
Oct 15, 2025
6205327
r-batch - remove aws config
Oct 16, 2025
cdf071c
r-batch - introduce a multi stage build with a non-root user
Oct 16, 2025
ade12c2
r-shiny - add installAutomake.sh to r-shiny
Oct 16, 2025
f03fe06
r-shiny - introduce a multi stage build with a non-root user
Oct 16, 2025
954a141
r-base - remove automake
Oct 16, 2025
8b97fde
r-model - introduce a multi stage build with a non-root user
Oct 16, 2025
ab200ff
r-geos - introduce a multi stage build with a non-root user
Oct 16, 2025
98b18f4
add Makefile to change R-Version and Build Images
Oct 16, 2025
c736967
add global arguments
Oct 16, 2025
f2e07aa
adjust sed command
Oct 16, 2025
14276b6
add opencontainer Lables
Oct 16, 2025
ea76724
add revision and created lables to image builds
Oct 16, 2025
2db420e
adjust Lables
Oct 16, 2025
bdb05a2
Create LICENSE
jan-abel-inwt Oct 16, 2025
21c929c
adjust Readme
Oct 16, 2025
c8e8ea6
add dependabot
Oct 16, 2025
69cefca
Merge branch '4.5.1.non-root' of github.com:INWTlab/r-docker into 4.5…
Oct 16, 2025
0a669f3
Update Makefile
jan-abel-inwt Oct 16, 2025
c55d0b5
Update Makefile
jan-abel-inwt Oct 16, 2025
0d329ac
Update r-batch/Dockerfile
jan-abel-inwt Oct 16, 2025
12b9eb9
Update r-geos/Dockerfile
jan-abel-inwt Oct 16, 2025
281589b
Update r-model/Dockerfile
jan-abel-inwt Oct 16, 2025
097ac05
fix typos
Oct 16, 2025
b011a26
ShellCheck InstallAutomake Script
Oct 16, 2025
4da1ece
remove install automake script from r-base
Oct 16, 2025
a366303
use TZ envvar
Oct 16, 2025
54a4545
use TZ envvar II
Oct 16, 2025
5697902
test pak
jan-abel-inwt Dec 17, 2025
c28460f
adjust os codename for ppm url
jan-abel-inwt Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/r-base/"
schedule:
interval: "monthly"
assignees:
- "jan-abel-inwt"
25 changes: 20 additions & 5 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ pipeline {
steps {
withDockerRegistry([ credentialsId: "jenkins-docker-hub", url: "" ]) {
sh '''
docker build -t inwt/r-base:$LABEL r-base
docker build \
--label org.opencontainers.image.revision=$(git rev-parse HEAD) \
--label org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t inwt/r-base:$LABEL r-base
docker push inwt/r-base:$LABEL
'''
}
Expand All @@ -31,7 +34,10 @@ pipeline {
steps {
withDockerRegistry([ credentialsId: "jenkins-docker-hub", url: "" ]) {
sh '''
docker build -t inwt/r-batch:$LABEL r-batch
docker build \
--label org.opencontainers.image.revision=$(git rev-parse HEAD) \
--label org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t inwt/r-batch:$LABEL r-batch
docker push inwt/r-batch:$LABEL
'''
}
Expand All @@ -41,7 +47,10 @@ pipeline {
steps {
withDockerRegistry([ credentialsId: "jenkins-docker-hub", url: "" ]) {
sh '''
docker build -t inwt/r-shiny:$LABEL r-shiny
docker build \
--label org.opencontainers.image.revision=$(git rev-parse HEAD) \
--label org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t inwt/r-shiny:$LABEL r-shiny
docker push inwt/r-shiny:$LABEL
'''
}
Expand All @@ -51,7 +60,10 @@ pipeline {
steps {
withDockerRegistry([ credentialsId: "jenkins-docker-hub", url: "" ]) {
sh '''
docker build -t inwt/r-model:$LABEL r-model
docker build \
--label org.opencontainers.image.revision=$(git rev-parse HEAD) \
--label org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t inwt/r-model:$LABEL r-model
docker push inwt/r-model:$LABEL
'''
}
Expand All @@ -61,7 +73,10 @@ pipeline {
steps {
withDockerRegistry([ credentialsId: "jenkins-docker-hub", url: "" ]) {
sh '''
docker build -t inwt/r-geos:$LABEL r-geos
docker build \
--label org.opencontainers.image.revision=$(git rev-parse HEAD) \
--label org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t inwt/r-geos:$LABEL r-geos
docker push inwt/r-geos:$LABEL
'''
}
Expand Down
339 changes: 339 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
R_VERSION := 4.5.1
TAG := ${R_VERSION}
IMAGES := r-base r-batch r-model r-geos r-shiny

.PHONY: update-version
update-version:
@echo "--- Updating R version tags to ${R_VERSION} in Dockerfiles ---"
@for image in ${IMAGES}; do \
file="$$image/Dockerfile"; \
sed -i "s/\(ARG R_VERSION=\)[0-9]\+\.[0-9]\+\.[0-9]\+[^[:space:]]*/\1${R_VERSION}/g" "$$file" \
&& echo "Updated $$file"; \
done
@echo "--- All Dockerfiles updated successfully! ---"

.PHONY: all $(IMAGES) clean
all: $(IMAGES)
@echo "--- Successfully built all Docker images with tag: $(TAG) ---"

$(IMAGES):
@echo "Building Docker image: inwt/$@:$(TAG) from folder: $@"
docker build -t inwt/$@:$(TAG) $@

.PHONY: clean
clean:
@echo "Removing locally tagged images for version ${TAG}..."
@for img in ${IMAGES}; do \
docker rmi inwt/$$img:${TAG} || true; \
done
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Container for R Applications
# Multi-Stage Container for R Applications

In this project we keep our configuration for INWT projects. If you are not working with us you can
see what we think is a good way to bring R applications into production. If you need a clean docker
Expand All @@ -13,44 +13,45 @@ The container from this project can be found at:

## Featured images

All images now use a multi-stage build for minimal size and enforce execution as a non-root user

### r-base

- Starts from rocker/r-ver:4.1.2
- Includes basic build tools
- Starts from rocker/r-ver
- Includes basic build tools and core R packages (`devtools`, `drat`)
- Enforces non-root user execution as `user`

- Adds INWT network settings: certificate and r-repo

### r-batch

- Starts from r-base
- Adds database connectors (MySQL)
- Adds database connectors (MySQL, Postgres)
- Includes `AWS CLI v2`
- Basic packages for modelling (lme4, mgcv, gbm)
- Packages for data manipulation (data.table, dplyr, tidyr)
- Home-brewed and open source (dbtools, mctools)
- Packages for data manipulation (`data.table`, `dplyr`, `tidyr`)
- Home-brewed and open source (`dbtools`, `mctools`)

### r-geos

- Starts from r-batch
- Installs Linux libraries necessary for running geo/gis related operations.
- Adds geo/gis related r packages (sf, stars, terra, etc.)
- Installs Linux libraries for GIS/geo related operations.
- Adds geo/gis related r packages (`sf`, `stars`, `terra`, etc.)

### r-shiny

- Starts from r-batch
- Adds shiny related packages (shiny, shinyjs, etc.)

### r-ver-ubuntu (deprecated)

- Based on Ubuntu
- R in given version with fixed MRAN
- Based on the rocker r-ver project
- Installs `Automake`
- Adds shiny related packages (`shiny`, `shinyjs`, `leaflet` etc.)
- Exposes port `3838`

## Simplest use of an image

Example for `r-base` image:

```
docker pull inwt/r-base:3.4.4
docker run -it inwt/r-base:3.4.4
docker pull inwt/r-base:4.5.1
docker run -it inwt/r-base:4.5.1
```

## Why using docker
Expand Down Expand Up @@ -88,7 +89,7 @@ make use of the predefined images introduced above. Therefore, a possible Docker
the following code:

```
FROM inwt/r-batch:3.4.4
FROM inwt/r-batch:4.5.1

ADD . .
RUN rm -vf .Rprofile && \
Expand Down Expand Up @@ -195,7 +196,7 @@ directory of the container. Be aware that with `-v` we are granting write access

```
cd /path/to/your/package
docker run --rm -v $PWD:/app --user `id -u`:`id -g` inwt/r-batch:3.4.4 check
docker run --rm -v $PWD:/app --user `id -u`:`id -g` inwt/r-batch:3.5.1 check
docker run --rm -v $PWD:/app inwt/r-batch:4.4.3 check
docker run --rm -v $PWD:/app inwt/r-batch:4.5.1 check
```

109 changes: 98 additions & 11 deletions r-base/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
FROM rocker/r-ver:4.5.1
# -------------------
# Setup (Global Args)
# -------------------
ARG R_VERSION=4.5.1
ARG USER_NAME=user
ARG USER_UID=1000
ARG USER_GID=1000
ARG TZ="Europe/Berlin"
ARG LANG="en_US.UTF-8"

# ----------------
# Stage 1: builder
# ----------------
FROM rocker/r-ver:${R_VERSION} AS builder

# 1. User & Environment Setup
ARG USER_NAME
ARG USER_UID
ARG USER_GID
ARG TZ
ARG LANG

WORKDIR /app
ENV HOME=/app
ENV DEBIAN_FRONTEND=noninteractive
ENV OPENBLAS_NUM_THREADS=1
ENV _R_CHECK_TESTS_NLINES_=0
ENV TZ="Europe/Berlin"
ENV LANG=en_US.UTF-8
ENV TZ=${TZ}
ENV LANG=${LANG}

ADD . /includes/
# Create the non-root user (UID 1000:GID 1000)
RUN groupadd --gid ${USER_GID} ${USER_NAME} \
&& useradd --uid ${USER_UID} --gid ${USER_GID} -m -G staff ${USER_NAME}

WORKDIR /app
COPY . /includes/

# 2. System Dependencies, Timezone, and CA Certificates
# CA Certificates and Timezone Setup
RUN mv -v /includes/*.crt /usr/local/share/ca-certificates/ \
&& dpkg-reconfigure ca-certificates \
&& rm /etc/localtime \
&& ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
&& echo "Europe/Berlin" > /etc/timezone \
&& echo "${TZ}" > /etc/timezone \
# Install System Dependencies
&& apt-get -y update \
&& apt-get -y upgrade \
&& apt-get install -y --no-install-recommends \
Expand Down Expand Up @@ -42,7 +68,8 @@ RUN mv -v /includes/*.crt /usr/local/share/ca-certificates/ \
&& apt-get autoclean -y \
&& rm -rf /var/lib/apt/lists/*

# R things
# 3. R Environment Setup and Package Installation
# Link scripts
RUN chmod +x /includes/*.R \
&& ln -s /usr/local/lib/R/site-library/littler/examples/dratInsert.r /usr/local/bin/dratInsert.r \
&& ln -s /includes/check.R /usr/local/bin/check \
Expand All @@ -51,16 +78,76 @@ RUN chmod +x /includes/*.R \
&& ln -s /includes/main.R /usr/local/bin/main \
&& ln -s /includes/installGithub.R /usr/local/bin/installGithub \
&& ln -s /includes/installPackage.R /usr/local/bin/installPackage \
&& ln -s /includes/installAutomake.sh /usr/local/bin/installAutomake \
# Set Posit Package Manager as CRAN Mirror
&& echo "options(repos = c(CRAN = '$(Rscript /includes/get_mirror_date.R)'), download.file.method = 'libcurl')" >> /usr/local/lib/R/etc/Rprofile.site \
# temporary fix for stringr & libicu lib
# Install R Packages (stringi needs to be recompiled)
&& Rscript -e "options(warn = 2); install.packages('https://github.com/gagolews/stringi/releases/download/v1.8.7/stringi_1.8.7.tar.gz', repos = NULL, type = 'source')" \
&& Rscript -e "options(warn = 2); install.packages(c('devtools', 'docopt', 'drat', 'modules'), Ncpus = parallel::detectCores())" \
&& rm -rf /tmp/downloaded_packages/* \
# Setup local repository
&& mkdir -p /r-repo/src/contrib \
&& touch /r-repo/src/contrib/PACKAGES \
&& echo "options(repos = c(getOption('repos'), LOCAL = 'file:////r-repo/'))" >> /usr/local/lib/R/etc/Rprofile.site \
&& echo "options(repos = c(getOption('repos'), INWT = 'https://r-repo.core.cld.htz.int.inwt.de'))" >> /usr/local/lib/R/etc/Rprofile.site \
&& echo "options(repos = c(getOption('repos'), INWTLab = 'https://inwtlab.github.io/drat/'))" >> /usr/local/lib/R/etc/Rprofile.site \
&& echo "options(dratRepo = '/r-repo/')" >> /usr/local/lib/R/etc/Rprofile.site \
&& chmod --recursive o+w /usr/local/lib/R/site-library
# Set ownership for site-library, local r-repo & R scripts
&& chown -R ${USER_NAME}:${USER_NAME} /usr/local/lib/R/site-library/ \
&& chown -R ${USER_NAME}:${USER_NAME} /r-repo \
&& chown -R ${USER_NAME}:${USER_NAME} /includes

# --------------
# Stage 2: final
# --------------
FROM rocker/r-ver:${R_VERSION}

LABEL org.opencontainers.image.authors="Sebastian Warnholz, Jan Abel" \
org.opencontainers.image.created="BUILD_DATE_TIME_PLACEHOLDER" \
org.opencontainers.image.description="Multi-stage R environment based on Rocker" \
org.opencontainers.image.licenses="GPL-2.0-or-later" \
org.opencontainers.image.revision="GIT_SHA_PLACEHOLDER" \
org.opencontainers.image.source="https://github.com/INWTlab/r-docker" \
org.opencontainers.image.title="inwt/r-base" \
org.opencontainers.image.vendor="INWT Statistics" \
org.opencontainers.image.version="${R_VERSION}"

# 1. User Setup
ARG USER_NAME
ARG USER_UID
ARG USER_GID
ARG TZ
ARG LANG

# Re-create the non-root user in the final stage (since this is a new base layer)
RUN groupadd --gid ${USER_GID} ${USER_NAME} \
&& useradd --uid ${USER_UID} --gid ${USER_GID} -m -G staff ${USER_NAME}

# Set runtime environment variables
ENV HOME=/app
ENV TZ=${TZ}
ENV LANG=${LANG}

# 2. Copy Artifacts from the builder stage
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /usr/local/lib/R/site-library/ /usr/local/lib/R/site-library/
COPY --from=builder /usr/local/lib/R/etc/Rprofile.site /usr/local/lib/R/etc/Rprofile.site
COPY --from=builder /r-repo/ /r-repo/

# 3. Add utility scripts
RUN mkdir -p /includes/check-lib

COPY --from=builder /includes/build.R /includes/build.R
COPY --from=builder /includes/check.R /includes/check.R
COPY --from=builder /includes/installPackage.R /includes/installPackage.R
COPY --from=builder /includes/installGithub.R /includes/installGithub.R
COPY --from=builder /includes/register-dependencies.R /includes/register-dependencies.R
COPY --from=builder /includes/validate-settings.R /includes/validate-settings.R
COPY --from=builder /includes/check-lib/ /includes/check-lib/

RUN chown -R ${USER_NAME}:${USER_NAME} /includes

# 3. Set User and Workdir
USER ${USER_NAME}
WORKDIR ${HOME}

CMD ["R"]
6 changes: 5 additions & 1 deletion r-base/get_mirror_date.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
create_mirror_url <- function(date) {
sprintf("https://packagemanager.posit.co/cran/__linux__/jammy/%s", format(date, "%Y-%m-%d"))
os_info <- readLines("/etc/os-release")
os_codename_line <- grep("^VERSION_CODENAME=", os_info, value = TRUE)
os_codename <- gsub("VERSION_CODENAME=", "", os_codename_line)

sprintf("https://packagemanager.posit.co/cran/__linux__/%s/%s", os_codename, format(date, "%Y-%m-%d"))
}

check_if_mirror_is_available <- function(date) {
Expand Down
28 changes: 0 additions & 28 deletions r-base/installAutomake.sh

This file was deleted.

Loading