【问题标题】:How do I 'copy' installed R-packages from the 1ste stage to 2nd stage using multistage building on a R-base image?如何使用基于 R 的映像上的多阶段构建将已安装的 R 包从第一阶段“复制”到第二阶段?
【发布时间】:2019-10-28 20:09:45
【问题描述】:

我正在尝试按照多阶段方法在 R-base 上构建图像库。如何将安装的软件包从第一阶段复制到第二阶段?没有别的?

当前文件基本上给了我一个“无包”R-base 版本。所以第一阶段安装的包在某处“丢失”了。

我认为这与制作和选择正确的目录有关。这对我来说是一个令人困惑的部分,因为我对 dockerizing 应用程序还很陌生。

感谢您的帮助!

在我当前的文件下面:

# Base image
FROM rocker/r-base:latest AS stage1

## install binary, build and dependend packages
RUN apt-get update && apt-get install -y -qq --no-install-recommends --purge \
r-cran-pdftools \
r-cran-dplyr \
r-cran-stringr \
libxml2-dev \
libssl-dev && \
echo "r <- getOption('repos');r['CRAN'] <- 'http://cran.us.r-project.org'; options(repos = r);" > ~/.Rprofile && \
Rscript -e "install.packages(c('AzureStor'))"

##2nd stage, pulling 'fresh' base image
FROM rocker/r-base:latest

#COPY packages from 1st stage
COPY --from=stage1 /usr/local/lib/R/site-library /usr/local/lib/R/site-library

## create directories
RUN mkdir -p /script \

#Copy scripts
COPY /script /script

## Set workdir
WORKDIR /script

【问题讨论】:

  • 你的目标是什么?已安装的包还需要安装所有它们的运行时依赖项(R 包和系统库)。您唯一可以摆脱的是构建时依赖项,通常是系统依赖项的开发包。
  • @RalfStubner 感谢您的回复。我的目标是让这个图像“准备好生产”并消除任何多余的“重量”。所以我需要构建包,但我不需要在图像中运行应用程序。所以你已经回答了:我想摆脱构建时的依赖关系(如果不需要它们来正确运行应用程序)。希望这能回答您的问题。

标签: docker build dockerfile r-package multistage


【解决方案1】:

在 cmets 中,您注意到您想要摆脱任何多余的“重量”。后者通常来自安装了开发工具和软件包。现在rocker/r-base 图像已经带来了相当大的权重,因为它具有安装了依赖项的r-base-devel。但是,我们可以通过摆脱构建时依赖项,在最终映像中仅保留运行时依赖项来尝试不进一步增加权重。 R 包在运行时不需要的构建时依赖项通常是开发文件,例如系统库的头文件,例如您在运行时不需要 libxml2-dev 包。 libxml2 包就足够了。 我看到了几种可能的方法。

首先,您可以将二进制包用于需要针对系统库进行编译的包。我没有检查 AzureStor 的依赖关系,但很可能所有必需的 R 包都作为已编译的 Debian 包存在。这些将仅取决于运行时依赖项,以保持图像尺寸小且构建时间短。你的 Dockerfile 看起来像这样:

FROM rocker/r-base:latest

## install binary, build and dependend packages
RUN apt-get update && apt-get install -y -qq --no-install-recommends --purge \
    r-cran-pdftools \
    r-cran-dplyr \
    r-cran-stringr \
    r-cran-... \
    r-cran-... && \
    Rscript -e "install.packages(c('AzureStor'))" && \
    apt-get clean %% \
    rm -rf /var/lib/apt/lists/* && \
    rm -rf /tmp/*

## create directories
RUN mkdir -p /script 

#Copy scripts
COPY /script /script

## Set workdir
WORKDIR /script

其次,您可以在从源代码安装 R 包之前安装构建和运行时依赖项,然后在一个命令中删除构建时依赖项:

FROM rocker/r-base:latest

## install binary, build and dependend packages
RUN apt-get update && apt-get install -y -qq --no-install-recommends --purge \
    r-cran-pdftools \
    r-cran-dplyr \
    r-cran-stringr \
    libxml2-dev libxml2 \
    libssl-dev libssl1.1 && \
    Rscript -e "install.packages(c('AzureStor'))" && \
    apt-get purge --yes libxml2-dev libssl-dev && \
    apt-get clean %% \
    rm -rf /var/lib/apt/lists/* && \
    rm -rf /tmp/*


## create directories
RUN mkdir -p /script 

#Copy scripts
COPY /script /script

## Set workdir
WORKDIR /script

最后,您可以使用具有三个阶段的多阶段构建:

  1. 添加运行时依赖项。
  2. 添加构建时依赖项并将软件包安装到/usr/local/lib/R/site-library
  3. 使用 1. 作为基础并添加来自 2. 的包。

所以是这样的:

# Base image
FROM rocker/r-base:latest AS stage1

## install binary, build and dependend packages
RUN apt-get update && apt-get install -y -qq --no-install-recommends --purge \
r-cran-pdftools \
r-cran-dplyr \
r-cran-stringr \
libxml2 \
libssl1.1 && \
apt-get clean %% \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/*

FROM stage1 AS stage2
RUN apt-get update && apt-get install -y -qq --no-install-recommends --purge \
libxml2-dev \
libssl-dev && \
Rscript -e "install.packages(c('AzureStor'))"


FROM stage1

COPY --from=stage2 /usr/local/lib/R/site-library /usr/local/lib/R/site-library

## create directories
RUN mkdir -p /script \

#Copy scripts
COPY /script /script

## Set workdir
WORKDIR /script

我个人使用过第一种和第二种方法。我还没有测试过第三种方法,我希望它也能工作。

【讨论】:

  • 非常感谢您的回答。所有方法都对我有用。您的第三个 Dockerfile 多阶段示例正是我正在寻找的答案。它很好地展示了如何限制安装了各种软件包的精简 R Base Docker 的图像大小。
猜你喜欢
  • 2020-08-24
  • 2020-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
相关资源
最近更新 更多