futile.logger::flog.threshold(futile.logger::INFO)

Introduction

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.

tl;dr

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()

Dockerfile examples

Create Dockerfile from session

class(sessionInfo())
containerit::dockerfile(from = sessionInfo(), env = ls())
clear_all()

Create Dockerfile from script

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)
)

Create Dockerfile from directory

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)

Configure 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/.



o2r-project/containerit documentation built on June 28, 2021, 2:46 p.m.