针对 R 用户的 docker 简介

针对 R 用户的 docker 简介

其实,我一直不知道 docker 具体怎么用…… 本文是学习 An Introduction to Docker for R Users 的笔记。

什么是 Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

更简单的说,Docker 是一个允许在你的机器上操作(启动和停止)多个操作系统(称为容器)的程序(你的机器将被称为主机)。

为什么要使用 Docker

Docker 旨在将镜像/容器内的环境封闭起来。例如,这允许在 Macbook 上安装 Linux 系统,或者在主计算机安装了 R 3.5 时使用 R 3.3 版本。此外,这意味着您可以将旧版本的软件包用于特定任务,同时仍保持计算机上的软件包是最新的。

通过这种方式,你可以“解决”依赖性问题:如果你担心依赖关系会在更新软件包时破坏您的分析,请构建一个始终具有所需软件版本的容器:无论是 Linux,R 还是任何软件包。

Docker 镜像与 Docker 容器

在你的电脑上,你需要两个东西:镜像和容器。镜像是 OS 的定义,而容器是镜像中运行的实例。镜像只需要安装一次,而容器需要在你需要某个实例的时候启动。当然,同一镜像中的多个容器可以同时运行。

对比与 R,这和安装 R 包一样,R 包只需要安装一次,每次需要它的时候你需要先加载它。你可以在几个 R 窗口使用同一个 R 包。install.packages() 就像是构建镜像而 library() 就像是运行镜像。

Dockerfile

Docker 镜像是使用 Dockerfile 进行构建的,这是一个配置文件,它描述了一些配置,如你是基于那个镜像构建的这个镜像?你如何配置操作系统?当你运行这个镜像的时候会发生什么?从某种意义上说,它有点像 R 包的 DESCRIPTION+ NAMESPACE 文件,它描述了哪些是包的依赖关系,元信息,并说明哪些功能和数据可供 library()包用户使用。

下面我们为 R 构建一个非常基础的 Dockerfile。

首先创建一个文件夹和一个 Dockerfile:

1
2
3
mkdir mydocker
cd mydocker
touch Dockerfile

假如我们想运行 mydocker 文件夹下面的 myscript.R 文件,内容如下:

tidystringdist 包的使用参考 tidystringdist

1
2
3
4
library(tidystringdist)
df <- tidy_comb_all(iris, Species)
p <- tidy_stringdist(df)
write.csv(p, "p.csv")

FROM

每一个 Dockerfile 文件都以一个 FROM 开头, FROM 描述了我们从那里构建镜像。有很多官方镜像,你也可以从本地进行构建。

如果你想构建一个基于 R 的镜像,你可以使用 Dirk Eddelbuettel & Carl Boettiger 维护的 rocker 里面包含了很多 R 的 Docker 镜像。最常用的就是 rocker/r-base 了,但是我们想让我们的镜像是可重复的,也就是说,我们希望每次我们运行它的时候都能返回一样的结果。因此,我们使用 rocker/r-ver 这个镜像中包含一个固定版本的 R: R 3.1.0。

首先你可以查看你当前的 R 版本:

1
2
R.Version()$version.string
# [1] "R version 3.5.2 (2018-12-20)"

因此,让我们使用下面的 FROM 语句开始编写我们的 Dockerfile:

1
FROM rocker/r-ver:3.5.2

RUN

接下来,我们需要添加一些 RUN 语句,是一些命令行的命令。

1
2
3
FROM rocker/r-ver:3.5.2

RUN mkdir /home/analysis

安装我们的 R 包

使 R 从终端执行某些操作的命令是 R -e “my code”,让我们使用它来安装我们脚本的依赖项,不过时从特定日期开始的。我们将模仿 rocker/r-ver 从特定日期构建时的工作方式:options(“repos”) 使用 MRAN 图像设置到此特定日期,例如 https://mran.microsoft.com/snapshot/1979-01-01。

1
2
3
4
5
6
7
FROM rocker/r-ver:3.5.2

RUN mkdir /home/analysis

RUN R -e "options(repos = \
list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/2019-01-06/')); \
install.packages('tidystringdist')"

ARG 语句

In our last Dockerfile, the date can’t be modified at build time - something we can change if we use an ARG variable, that will be set when we’ll do docker build, with –build-arg WHEN=

在 Dockerfile 的最后,日期是不能在构建的时候修改的,但是如果我们使用了 ARG 变量我们就可以更改了,这样,在我们运行 docker build 的时候,我们可以使用 --build-arg WHEN= 选项。

1
2
3
4
5
6
7
8
9
FROM rocker/r-ver:3.5.2

ARG WHEN

RUN mkdir /home/analysis

RUN R -e "options(repos = \
list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
install.packages('tidystringdist')"

这样,tidystringdist 将安装我们在构建容器时指定的日期的版本,即使我们在一年,或两年,或四年内构建此镜像。

COPY

COPY 语句可以将主机上的脚本拷贝到容器中:

1
2
3
4
5
6
7
8
9
10
11
FROM rocker/r-ver:3.5.2

ARG WHEN

RUN mkdir /home/analysis

RUN R -e "options(repos = \
list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
install.packages('tidystringdist')"

COPY myscript.R /home/analysis/myscript.R

CMD

CMD 语句是我们每次启动 docker 时都会运行的命令。我们想要运行 myscript.R 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM rocker/r-ver:3.5.2

ARG WHEN

RUN mkdir /home/analysis

RUN R -e "options(repos = \
list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
install.packages('tidystringdist')"

COPY myscript.R /home/analysis/myscript.R

CMD R -e "source('/home/analysis/myscript.R')"

构建和运行

现在在终端中将工作目录切换至 Dockfile 所在目录然后运行:

Shell
1
docker build --build-arg WHEN=2019-01-06 -t analysis .

然后你只需要运行:

Shell
1
docker run analysis

你的代码就会被运行。

导出容器内容

接下来你需要做的一件事情是,你想要查看 p.csv 的内容(就是你的 R 脚本运行的结果),而它现在还在容器里面,所以我们需要使主机和容器共享一个文件夹。为此,我们将使用所谓的 Volume(粗略地说),这是一种告诉 Docker 容器将主机中的文件夹用作容器内的文件夹的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM rocker/r-ver:3.5.2

ARG WHEN

RUN mkdir /home/analysis

RUN R -e "options(repos = \
list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
install.packages('tidystringdist')"

COPY myscript.R /home/analysis/myscript.R

CMD R -e "source('/home/analysis/myscript.R')"

CMD cd /home/analysis \
&& R -e "source('myscript.R')" \
&& mv /home/analysis/p.csv /home/results/p.csv

最后运行:

Shell
1
2
mkdir results
docker run -v ~/Desktop/mydocker/results:/home/results analysis

再看 results 中的东西:

1
2
3
4
5
6
$ tree
.
├── Dockerfile
├── myscript.R
└── results
└── p.csv

就是我们需要的 p.csv

还能做什么

如果你想使用 remotes 安装 R 包,你可以这样:

1
2
3
4
5
6
FROM rocker/r-ver:3.4.4

RUN R -e "install.packages('remotes'); \
remotes::install_version('tidystringdist', '0.1.2')"

......

你还可以使用 Volume 将数据导入容器,以便在同一环境中分析任何数据。

删除 Docker 镜像

Docker 镜像多的时候很占用电脑内存,所以还是把没用的删除掉:

1
2
3
4
5
6
7
# 查看docker镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rocker/r-ver 3.5.2 341936da7c68 5 weeks ago 605MB
# 使用 IMAGE ID 删除镜像
$ docker rmi 341936da7c68 -f
# -f 表示强制删除
# R

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×