futile.logger::flog.threshold(futile.logger::INFO)
This R extension package provides features to bundle an R analysis together with the required runtime environment in so called software containers, more specifically Docker. The intention of this package is to provide a building block to support reproducible and archivable research. Development is supported by the DFG-funded project Opening Reproducible Research (http://o2r.info).
The core functionality is to create a Dockerfile
from a given R session, script, or workspace directory. This Dockerfile contains all the R packages and their system dependencies required by the R workflow to be packaged.
The Dockerfiles are based on rocker (on Docker Hub). Eventually it should/could be possible to create images from scratch?
Dockerfile generation relies on the sysreqs package.
To build images and run containers, this package integrates with the harbor package.
For nitty gritty things like reading/loading/installing the exact versions, including system dependencies, internal and external libraries etc., this project is focused on the geospatial domain.
Load the package, do your analysis, and create a Dockerfile.
suppressPackageStartupMessages(library("containerit")) # do stuff, based on demo("krige") suppressPackageStartupMessages(library("gstat")) suppressPackageStartupMessages(library("sp")) data(meuse) coordinates(meuse) = ~x+y data(meuse.grid) gridded(meuse.grid) = ~x+y v <- variogram(log(zinc)~1, meuse) m <- fit.variogram(v, vgm(1, "Sph", 300, 1)) plot(v, model = m) my_environment <- dockerfile(from = sessionInfo())
The Dockerfile object can be saved to a file or printed out.
cat(as.character(format(my_environment)), sep = "\n")
write(my_environment, file = tempfile())
# https://stackoverflow.com/questions/7505547/detach-all-packages-while-working-in-r clear_all <- function() { # objects rm(list = ls(all.names = TRUE)) # packages .kept.packages <- c("stats", "graphics", "grDevices", "utils", "datasets", "methods", "base", "tools", "stringr", "stringi", "containerit", "futile.logger", "futile.namespaces", "futile.options", "lambda.r") .package.list <- search()[ifelse(unlist(gregexpr("package:",search())) == 1,TRUE,FALSE)] .package.list <- setdiff(.package.list, paste("package:", .kept.packages, sep = "")) if (length(.package.list) > 0) for (package in .package.list) detach(package, character.only = TRUE) # packages loaded via namespaces # .tounload <- setdiff(loadedNamespaces(), .kept.packages) # while( ! length(.tounload) == 0 ){ # for(i in seq_along(.tounload)){ # cat("unloading ", .tounload[i], "\n") # suppressWarnings(tryCatch(unloadNamespace(.tounload[i]), error = function(x) return(NA))) # } # .nowloaded <- setdiff(loadedNamespaces(), .kept.packages) # .tounload <- sample(.nowloaded); # randomimze list order # } cat("cleaned up!\n") } clear_all()
clear_all()
class(sessionInfo()) containerit::dockerfile(from = sessionInfo(), env = ls())
clear_all()
This example uses the rgdal package because it has system library dependencies, namely GDAL and PROJ. Code snippets are taken from the sp gallery. Here is some regular R code loading a file and plotting it.
library("rgdal") library("maptools") nc <- readOGR(system.file("shapes/", package = "maptools"), "sids", verbose = FALSE) proj4string(nc) <- CRS("+proj=longlat +datum=NAD27") plot(nc)
The code is not executed but dynamically saved to a temporary file, which is then used to create a Dockerfile
.
scriptFile <- tempfile(pattern = "containerit_", fileext = ".R") writeLines(text = c('library("sp")', 'library("rgdal")', 'nc <- readOGR(system.file("shapes/", package="maptools"), "sids", verbose = FALSE)', 'proj4string(nc) <- CRS("+proj=longlat +datum=NAD27")', 'plot(nc)'), con = scriptFile) print( containerit::dockerfile(from = scriptFile) )
This examples packages a workspace directory.
list.files("../inst")
containerit
looks for files in a directory that can be executed and creates a Dockerfile based on the first document found, in this case an R Markdown document.
df <- containerit::dockerfile(from = "../inst") print(df)
Dockerfile
You can skip available packages and choose your own base image.
```{bash pull_geospatial, include=FALSE} docker pull rocker/geospatial:3.5.2
```r df <- containerit::dockerfile(from = "../inst", image = "rocker/geospatial:3.5.2", filter_baseimage_pkgs = TRUE) print(df)
For extended configuration options see the vignettes online at https://o2r.info/containerit/articles/.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.