knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" )
Project-specific cache of {renv}
dependencies in Docker workflows
Past me:
I wanted to use {renv}
in combination with Docker and didn't yet know how
to mount my local {renv}
cache, so the
build process took much longer than I was willing to wait ;-)
This also happened at a time before rocker switched to Ubuntu as the underlying Linux OS (Thanks to Eric Nantz for pointing that out in your podcast!).
Before that (AFAIU and AFAIR), it could happen that the compilation process
slightly differed between Ubuntu and Debian(?). So even though you might
have properly mounted your local {renv}
cache so it was
available at build time, the resulting builds might have been incompatible
with your local Linux OS.
To be honest, I'm not sure how much of this still holds/is necessary after
the switch to Ubuntu, but I nevertheless liked the idea of having an
{renv}
cache that is completely project-specific, so I continued building
this package out.
[TODO: Investigate the rocker history, etc. so I don't tell incorrect stuff here ;-)]
So I wanted to have a faster build experience and came up with this two-step approach:
STEP 1
Build an image that handles all of my package dependencies.
It only builds the dependencies once or when it has to (that is whenever my
renv.lock
is updated) and caches them back to a subdirectory within my local
package directory (./renv/cache_docker
[TODO: or was it ./renv/cache
-->
review this]) for future builds.
I called this image the Dependency Cache Manager (DCM).
STEP 2
Build the actual image
This image get access to the locally persisted {renv}
cache from the previous
step as well as ./renv/local
(the place where your package's .tar.gz
file is
built to when you use the build.R
; see below).
It calls renv::restore()
which uses the cache and restores your package by
installing it from source.
remotes::install_github("rappster/renv2docker")
library(renv2docker)
write_env_vars()
Technically, they are mostly used as ARG
s instead of ENV
s, but at least for
PACKAGE_PORT
it would make sense to pass it on as e ENV
. Still learning
about the nitty-gritty details ;-) See Docker ARG, ENV and .env - a Complete
Guide for more details on
this
./Dockerfile
and ./renv/Dockerfile
dockerfile <- use_template_dockerfile(open = FALSE) readLines(dockerfile) %>% cat(sep = "\n")
dockerfile <- use_template_dockerfile_dcm(open = FALSE) readLines(dockerfile) %>% cat(sep = "\n")
build.R
This template ensures that your package is built into ./renv/local
and that
all workflow requirements of renv2docker
are met regarding the caching of
package dependency builds.
build_r <- use_template_build(open = FALSE) readLines(build_r) %>% cat(sep = "\n")
docker_build.sh
and docker_run.sh
build_build_sh <- use_template_docker_build(open = FALSE) readLines(build_build_sh) %>% cat(sep = "\n")
docker_run_sh <- use_template_docker_run(open = FALSE) readLines(docker_run_sh) %>% cat(sep = "\n")
Find line
COPY inst/main.R main.R
and line
CMD Rscript 'main.R'
and adapt it to your setup.
The default setup
main.R
within your inst
directorymain.R
Runs main.R
via Rscript
Build your Docker container
Open a terminal/shell within your package/project root directory and type
./docker_build.sh
./docker_run.sh
This package was inspired and influenced by
My goal is to align this package as much as I can with existing workflows and best practices around R in combination with Docker.
This is another one of my "scratch your own itch" type of projects.
I use Linux (Pop!_OS) and hence aligned {renv}
and Docker workflows to that platform --> not sure how much of it is applicable
for MacOS or Windows
Still hope it works for other developers out there as well :-)
Please note that the renv2docker project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.