-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathbasic.Rmd
172 lines (128 loc) · 5.9 KB
/
basic.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
---
title: "Basic introduction to package containerit"
author: "Daniel Nüst"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteEngine{knitr::rmarkdown}
%\VignetteIndexEntry{Introduction to package \texttt{containerit}}
%\VignetteEncoding{UTF-8}
---
<!-- Copyright 2018 Opening Reproducible Research (https://o2r.info) -->
```{r disable_logger, include=FALSE, results='hide'}
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](https://en.wikipedia.org/wiki/Operating-system-level_virtualization), more specifically [Docker](http://docker.com/).
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](https://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](https://github.com/rocker-org/rocker) (on [Docker Hub](https://hub.docker.com/u/rocker/)). Eventually it should/could be possible to create images from scratch?
Dockerfile generation relies on the [sysreqs](https://github.com/r-hub/sysreqs) package.
To build images and run containers, this package integrates with the [harbor](https://github.com/wch/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.
```{r tldr}
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.
```{r format,results='markup', comment=FALSE}
cat(as.character(format(my_environment)), sep = "\n")
```
```{r write}
write(my_environment, file = tempfile())
```
```{r clear_all,results='hide',echo=FALSE}
# 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()
```
```{r,results='hide',echo=FALSE}
clear_all()
```
## Dockerfile examples
### Create Dockerfile from session
```{r example_session}
class(sessionInfo())
containerit::dockerfile(from = sessionInfo(), env = ls())
```
```{r clear_again,results='hide',echo=FALSE}
clear_all()
```
### Create Dockerfile from script
This example uses the [rgdal](https://CRAN.R-project.org/package=rgdal) package because it has system library dependencies, namely GDAL and PROJ.
Code snippets are taken from the [sp gallery](https://edzer.github.io/sp/).
Here is some regular R code loading a file and plotting it.
```{r example_geo, eval=FALSE}
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`.
```{r example_script}
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.
```{r example_workspace_list}
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.
```{r example_workspace}
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 example_configure}
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/.