R in Windows Containers
There are numerous Dockerfiles/Docker images available with R running on a Linux distribution.
Here I look into running R in a Windows container.
I see two advantages:
- “Environments” should be similar. Developing on Windows and running the code on Linux (or vice versa) may not be a smooth process.
- It is much faster to install R packages with compiled code on Windows.
The final Dockerfiles are in my GitHub repository with R Dockerfiles.
R in Server Core
CRAN has an archive with installers for the last 16 years of R for Windows: https://cran.r-project.org/bin/windows/base/old.
Just as in a Linux container we only have a command line/PowerShell available in a Windows container, so we have to install R from the command line.
For many practical purposes, Rtools are also necessary on Windows.
The Rtools installer also has some special flags which I found in the CI script used in the daily build of R for Windows
Armed with these commands R and Rtools can be installed as in this Dockerfile:
FROM mcr.microsoft.com/windows/servercore:ltsc2019
ARG R_VERSION
ENV R_VERSION=${R_VERSION}
RUN curl.exe -o R-%R_VERSION%-win.exe https://cran.r-project.org/bin/windows/base/old/%R_VERSION%/R-%R_VERSION%-win.exe
RUN R-%R_VERSION%-win.exe /VERYSILENT /DIR="C:\R\"
RUN curl.exe -o Rtools.exe https://cran.r-project.org/bin/windows/Rtools/Rtools35.exe
RUN Rtools.exe /TYPE=full /VERYSILENT -NoNewWindow -Wait
CMD [ "C:\R\bin\R.exe", "--no-save" ]
The R version is passed as a build argument:
docker build --build-arg R_VERSION=3.6.0 --tag r-base:3.6.0 .
To make the image smaller the downloaded installers should be deleted.
But the usual sign for multi-line commands (the caret ^
) doesn’t seem to work in the Windows containers.
Instead I rely on a multi-stage build.
I also specify a CRAN that is compatible with this version of R – just as I do with every R installation.
Image sizes
A key difference between Windows Docker images and Linux Docker images is their size:
PS > docker image ls
REPOSITORY TAG SIZE
r-base 3.6.0 5.8GB
mcr.microsoft.com/windows/servercore ltsc2019 4.71GB
mcr.microsoft.com/windows/nanoserver 1809 250MB
The servercore
image is huge compared to any Linux distribution’s plain vanilla image.
R and Rtools also take up more than a Gigabyte, which is also quite a lot more than on Linux.
However, the nanoserver
image is quite small, so it’s tempting to use this instead of servercore
.
R in Nano Server
TL; DR: I cannot make R run in the nanoserver
image.
This section is to document my attemps.
Simply replacing servercore
with nanoserver
in the above Dockerfile does not work – the installer cannot run.
Instead we can try out a multi-stage build where R is installed in a servercore
image and then copied to a nanoserver
image.
Running a container based on such an image will exit immediately with error code 3221225781.
To see the error code, we can run the container without the --rm
flag and list the containers:
PS > docker run r-base-nano:3.6.0
PS > docker container ls -a
IMAGE COMMAND STATUS
r-base-nano:3.6.0 "R.exe --va…" Exited (3221226625)
Runtime dependencies
It turns out that R has a number of runtime dependencies on Windows.
These can be revealed with the program Process Explorer in a normal Windows.
Process Explorer lists all dll
's that a program depends on.
On my computer I see the following for R when it is started from the command line.
(As noted in a previous post starting an R instance on Windows actually starts two R.exe
and one Rterm.exe
.)
All non-R related dll
's for Rterm.exe
and the two R.exe
are in C:\Windows\System32
.
My final attempt is to copy the dll
's from servercore
that are missing in nanoserver
:
FROM mcr.microsoft.com/windows/servercore:ltsc2019 as builder
ARG R_VERSION
ENV R_VERSION=${R_VERSION}
RUN curl.exe -o R-%R_VERSION%-win.exe https://cran.r-project.org/bin/windows/base/old/%R_VERSION%/R-%R_VERSION%-win.exe
RUN R-%R_VERSION%-win.exe /VERYSILENT /DIR="C:\R\"
RUN curl.exe -o Rtools.exe https://cran.r-project.org/bin/windows/Rtools/Rtools35.exe
RUN Rtools.exe /TYPE=full /VERYSILENT -NoNewWindow -Wait
# --------------------------------------------------------------------
FROM mcr.microsoft.com/windows/nanoserver:1809
COPY --from=builder C:\\R C:\\R
COPY --from=builder C:\\Rtools C:\\Rtools
RUN setx path "%path%;C:\R\bin;C:\Rtools\bin"
RUN echo options(repos = "https://mran.microsoft.com/snapshot/2019-07-04") >> C:\R\library\base\R\Rprofile
# System runtime dependencies
COPY --from=builder \
C:\\Windows\\System32\\advapi32.dll \
C:\\Windows\\System32\\clbcatq.dll \
C:\\Windows\\System32\\comdlg32.dll \
C:\\Windows\\System32\\CoreMessaging.dll \
C:\\Windows\\System32\\gdi32.dll \
C:\\Windows\\System32\\gdi32full.dll \
C:\\Windows\\System32\\imm32.dll \
C:\\Windows\\System32\\kernel.appcore.dll \
C:\\Windows\\System32\\msimg32.dll \
C:\\Windows\\System32\\ole32.dll \
C:\\Windows\\System32\\shell32.dll \
C:\\Windows\\System32\\shlwapi.dll \
C:\\Windows\\System32\\user32.dll \
C:\\Windows\\System32\\uxtheme.dll \
C:\\Windows\\System32\\version.dll \
C:\\Windows\\System32\\win32u.dll \
C:\\Windows\\System32\\windows.storage.dll \
C:\\Windows\\System32\\winmm.dll \
C:\\Windows\\System32\\winmmbase.dll \
C:\\Windows\\System32\\kernel32.dll \
C:\\Windows\\System32/
CMD [ "R.exe", "--no-save" ]
The R in the resulting image also crashes immediately, but with a diffrent error code (3221226625).