我在Windows 11上使用WSL2和Ubuntu。我有以下文件夹设置:
Code
|--- Dockerfile
|--- iris.R
R
|--- Dockerfile
|--- packages.R
|--- packages.txt
Results (an empty folder)
我的目标是:
- 基于R文件夹创建一个容器,生成一个卷。
- 将卷挂载到第二个容器上。
- 让它检测软件包已经从卷中安装。
- 执行iris.R。
- 将其输出保存到结果文件夹,挂载到我的本地结果文件夹(我暂时不担心这一步,但如果你想告诉我如何做这一步,尽一切可能)。
我明白最终的目标应该是把这些放到一个docker-compose文件中,但是在我去那里之前,我想让它们直接在CLI中工作。
步骤1R/Dockerfile:
#### INITIAL SETUP
FROM r-base:4.2.2
# Define the date (YYYY-MM-DD) at build time
ARG WHEN
ENV WHEN = $WHEN
# Copy packages.txt
COPY . /home/
# Define the working directory
WORKDIR /home/
# Execute R from the terminal
CMD ["Rscript", "packages.R"]
R/包。R:
when <- gsub("= ", "", Sys.getenv("WHEN"))
options(repos = list(CRAN = paste0('http:/mran.revolutionanalytics.com/snapshot/', when)))
install.packages(readLines('packages.txt'))
R/packages.txt:
ggplot2
以下是我在R文件夹中执行的命令:
docker build --network=plot-network:first --build-arg WHEN=2022-12-29 -t package:first .
docker volume create packages
docker run -d --network=plot-network:first -v packages:/home --rm package:first
我知道这会创建一个packages
卷,这是必要的,因为一旦容器完成,数据(即已安装的包)就不会保留。
步骤2 - 3
这就是我被卡住的地方。现在我们进入Code文件夹:
代码/Dockerfile:
#### INITIAL SETUP
FROM r-base:4.2.2
# Set an environment variable at runtime for the separate directory
ENV MAINDIR /home/
# Copy the file to a path in the container
COPY . ${MAINDIR}
# Set working directory
WORKDIR $MAINDIR
# Append Rscript to code
ENTRYPOINT ["Rscript"]
代码/虹膜。R:
library(ggplot2)
args <- commandArgs(trailingOnly = TRUE)
p <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width,
color = Species)) +
geom_point() +
geom_smooth(method = "lm") +
theme_bw() +
theme(panel.grid = element_blank()) +
xlab("Sepal Length") +
ylab("Sepal Width") +
scale_x_continuous(limits = c(4, 8), breaks = seq(4, 8, 0.5)) +
scale_y_continuous(limits = c(2, 5), breaks = 2:5)
ggsave(filename = args[1])
显然第一个要执行的命令是
docker build -t plot:first .
第二个命令不那么明显。Rscript iris.R
应该执行iris.R
,但是我还没有弄清楚如何正确地挂载卷,以便检测到iris.R
。
docker run --network=plot-network:first -v packages:/home/ plot:first iris.R
Fatal error: cannot open file 'iris.R': No such file or directory
我注释掉了上面的ENTRYPOINT ["Rscript"]
,并试图找出为什么iris.R
没有显示,因为Rscript iris.R
告诉我它不在目录中,并执行以下命令:
docker run --network=plot-network:first -v packages:/home/ plot:first R -e "list.files()"
这列出了目录中的文件,并给了我以下内容:
list.files()
[1] "docker" "Dockerfile" "packages.R" "packages.txt"
不检测虹膜。
它似乎检测到原来在R文件夹中的文件。但值得关注的是,它没有检测到我认为我放入packages
卷中的已安装的软件包。
步骤1中的docker run
命令在安装包时,R告诉我:
Installing package into ‘/usr/local/lib/R/site-library’
(as ‘lib’ is unspecified)
,显然这个/usr/
目录没有被带入卷(如上面的list.files()
所证明的)。
我在这里做错了什么?
为什么这样做?
我被其他人问过这个问题,他们给了我一些帮助:这样做的原因是因为包安装很耗时,最好只引用一个已经安装了包的容器,这样我就不必每次构建新容器时都重新安装包。
从"为什么这样做"我理解你想在构建新容器时跳过安装包。
因此,我建议跳过卷部分,只使用第一个容器作为第二个容器的源。
Code/Dockerfile的第一行应该是:
From package:first
卷用于同时在多个容器之间共享数据,所以除非您想要,否则我不建议在这种情况下使用它。
它似乎检测到原来在R文件夹中的文件。但令人担忧的是,它没有检测到我认为我扔进包卷的已安装的包。
这是因为卷挂载到/home目录,在这里,包被下载并安装在不同的目录中。从包容器的日志中:
安装/usr/local/lib/R/site-library/00 lock-tibble/00新/宠物猫/libs
和
下载的源包在"/tmp/Rtmp7ow0xd/downloaded_packages">
使用卷将增加不必要的复杂性,因为安装的包将被分成多个文件夹。
最后是虹膜。没有找到R文件,因为卷挂载用包容器的文件覆盖了它。
我建议如下:
- 保持R/Dockerfile原样
- 构建包容器。
- 使用packages容器作为plot容器 的源
- 建立地块容器
- 运行没有卷的plot容器(/home目录)还会有文件的包容器,可以添加一个在复制虹膜之前,要把线清理干净。