我正在创建一个 docker 容器,以接受来自客户端的输入数据,然后将一个 R 脚本作为源码,在给定的数据上运行分析,并将三张图以 PDF 格式输出到工作目录中。 我遇到的问题是,在Docker文件中需要两个CMD语句,这是不被Docker引擎允许的。 我需要在运行时读取用户的数据,这样数据集就可以根据用户的情况进行更改。然后,R脚本需要在R工作空间中以表对象的形式读取用户的数据后,再进行源码。 出现的情况是,数据读进去就好了,但是错误信息显示,第二行CMD行,要来源R脚本,找不到刚刚读进去的数据。 我理解这是因为Dockerfile的每一行在构建时都是单独执行的,但我不知道如何解决这个问题。 我研究了卷,使用supervisor,以及使用多个容器的可能性。 我也有可能做一个Python脚本来动态编程我的R脚本,但这可能还是需要两行CMD。 我还没有找到一个足够具体的例子来说明我的情况。 你们谁能解决这个问题?
这是我的R脚本,从一个数据框架 "x "中创建3个图。
library(iq)
norm_data <- iq::preprocess(x, median_normalization = FALSE, pdf_out = NULL)
protein_list <- iq::create_protein_list(norm_data)
# basic protein plot
pdf(file = "Protein P00366.pdf")
iq::plot_protein(protein_list$P00366, main = "Protein P00366", split = NULL)
dev.off()
protein_table <- iq::create_protein_table(protein_list)
#MaxLFQ plot
pdf(file = "MaxLFQ quantification of P00366.pdf")
iq::plot_protein(rbind(protein_list$P00366,
MaxLFQ = iq::maxLFQ(protein_list$P00366)$estimate),
main = "MaxLFQ quantification of P00366",
col = c(rep("gray", nrow(protein_list$P00366)), "green"),
split = NULL)
dev.off()
# ground truth
MaxLFQ_estimate <- iq::maxLFQ(protein_list$P12799)$estimate
ground_truth <- log2(rep(c(200, 125.99, 79.37, 50, 4, 2.52, 1.59, 1), each = 3))
ground_truth <- ground_truth - mean(ground_truth) + mean(MaxLFQ_estimate)
#ground truth plot
pdf(file = "P12799 MaxLFQ versus groundtruth.pdf")
iq::plot_protein(rbind(MaxLFQ = MaxLFQ_estimate,
Groundtruth = ground_truth),
main = "P12799 - MaxLFQ versus groundtruth",
split = 0.75,
col = c("green", "gold"))
dev.off()
这是我的Docker文件
FROM r-base:latest
ENV SCRIPT=""
ENV DATA=""
RUN R -e "install.packages('iq', repos='http://cran.rstudio.com/')"
WORKDIR /home/iq/
CMD R -e "x <- read.table(\"$DATA\", header = TRUE, sep = ",", fill = TRUE)" \
&& R -e "source('$SCRIPT')"
在一个路径为homeiq的文件夹里 我有一个叫iqTest.R的脚本 Dockerfile和data.csv 我一直在用下面的命令构建和运行我的容器。
$ cd iq
$ docker build -t my_image .
$ docker run -it -v /home/user/iq:/home/iq --env DATA=data.csv --env SCRIPT=iqTest.R my_image:latest
在尝试运行后,我从R工作区得到以下错误信息。
> source('iqTest.R')
Error in iq::preprocess(x, median_normalization = FALSE, pdf_out = NULL) :
object 'x' not found
Calls: source -> withVisible -> eval -> eval -> <Anonymous>
编辑:我最近发现,这个问题更多的是与R有关:你可以使用一个 ;
来连接多行R代码,这样就解决了多条CMD语句的问题。愿以此为例,给正在连接R和Docker.例如新的Dockerfile,用分号连接行。
FROM r-base:latest
ENV SCRIPT=""
ENV DATA=""
RUN mkdir /home/analysis/
RUN R -e "install.packages('iq', repos='http://cran.rstudio.com/')"
WORKDIR /home/analysis/
CMD R -e "x = read.csv(\"$DATA\", header = TRUE, sep = ",", fill = TRUE); source('$SCRIPT')"
如果你想通过一个环境变量来配置数据路径,那么我建议在你的脚本中用以下方法来访问这个变量 Sys.getenv()
. 这也允许你使用 Rscript
而不是 R -e "source...
.
下面是我的工作原理。
script.R
cat(Sys.getenv('SCRIPT'), '\n');
cat(Sys.getenv('DATA'), '\n')
Docker文件
FROM r-base:latest
ENV SCRIPT="script.R"
ENV DATA="data.csv"
WORKDIR /workspace
CMD R -q -e "source('$SCRIPT')"
# alternative: CMD Rscript $SCRIPT
使用方法
daniel@nuest /tmp/stackoverflow []$ docker build --tag stackoverflow .
Sending build context to Docker daemon 4.608kB
Step 1/5 : FROM r-base:latest
---> 46edce0e80af
Step 2/5 : ENV SCRIPT="script.R"
---> Using cache
---> 8f26d34d9c0a
Step 3/5 : ENV DATA="data.csv"
---> Using cache
---> 16c83c16a4c8
Step 4/5 : WORKDIR /workspace
---> Running in fce8619af30b
Removing intermediate container fce8619af30b
---> a8278f609d9a
Step 5/5 : CMD R -q -e "source('$SCRIPT')"
---> Running in 765bafeb8681
Removing intermediate container 765bafeb8681
---> ff7d7b09dffb
Successfully built ff7d7b09dffb
Successfully tagged stackoverflow:latest
daniel@nuest /tmp/stackoverflow []$ docker run --rm -it -v $(pwd):/workspace stackoverflow
> source('script.R')
script.R
data.csv
>
>
或者,你可以尝试将数据路径作为参数传递给你的脚本文件,参见 https:/swcarpentry.github.IOR-novice-inflammation05-cmdline。
顺便说一句:钉一个特定的R版本比使用 :latest
,以保证重复性。