如何在 Dockerfile 中添加大型 HTTP 文件并将它们从图像层中排除?

How do I add big HTTP files in a Dockerfile and exclude them from image layers?

我们的 Nexus server 为我们的 Java 项目提供构建工件,包括其安装程序。该安装程序非常大 (>1GB)。我想在 Dockerfile.

中检索并使用它

到目前为止我所做的如下:

FROM debian:jessie
...
RUN apt-get install -y curl xmllib-xpath-perl
ENV PROJECT_VERSION x.y.z-SNAPSHOT
...
RUN VERSION=`curl --silent "http://nexus:8081/service/local/artifact/maven/resolve?r=public&g=my.group.id&a=installer&v=${PROJECT_VERSION}&e=sh&c=linux64" | xpath -q -s '' -e '//data/version/text()'` \
    && echo Version:\'${VERSION}\' \
    && curl --silent http://nexus/content/groups/public/my/group/id/installer/${PROJECT_VERSION}/installer-${VERSION}-linux64.sh \
        --create-dirs \
        --output ${INSTALL_DIR}/installer.sh \
    && sh ${INSTALL_DIR}/installer.sh <someArgs> \
    && rm ${INSTALL_DIR}/installer.sh
...

通过这种方法,我能够:

缺少什么:

所以我尝试了一种使用 ADD 语句的不同方法,因为根据文档,它们具有 缓存功能 。但这不起作用,因为我需要向 ADD 语句提供参数,该语句由上一步查询 Nexus 以获取正确的 SNAPSHOT 版本设置:

FROM debian:jessie
...
RUN apt-get install -y curl xmllib-xpath-perl
ENV PROJECT_VERSION x.y.z-SNAPSHOT
...
ADD http://nexus:8081/service/local/artifact/maven/resolve?r=public&g=my.group.id&a=installer&v=${PROJECT_VERSION}&e=sh&c=linux64 ${INSTALL_DIR}/version.xml
RUN cat ${INSTALL_DIR}/version.xml | xpath -q -s '' -e '//data/version/text()' > ${INSTALL_DIR}/version.txt

# FIXME: Somehow do a `cat ${INSTALL_DIR}/version.txt to set the ENV ${VERSION} variable ?!

ADD http://nexus/content/groups/public/my/group/id/installer/${PROJECT_VERSION}/installer-${VERSION}-linux64.sh ${INSTALL_DIR}/installer.sh
RUN ${INSTALL_DIR}/installer.sh <someArgs> && rm ${INSTALL_DIR}/installer.sh
...

该方法不起作用,因为:

但至少这将使用适当的缓存来为旧安装程序版本重新使用现有图像层,并在 Nexus 上部署新安装程序版本时创建新图像层。

所以问题是:如何同时从Docker 图像层启用适当的缓存、缓存失效和排除大型安装程序文件?

编辑:我找到了一种通过使用其他 Nexus API:

使图像层缓存正常工作的方法
FROM debian:jessie
...
ENV PROJECT_VERSION x.y.z-SNAPSHOT
...
ADD http://nexus:8081/service/local/artifact/maven/content?r=public&g=my.group.id&a=installer&v=${PROJECT_VERSION}&e=sh&c=linux64 ${INSTALL_DIR}/installer.sh
RUN sh ${INSTALL_DIR}/installer.sh <someArgs> \
    && rm ${INSTALL_DIR}/installer.sh
...

但是 图像层中包含非常大的安装程序文件的问题仍然存在,因为在该代码中使用了 ADD 机制。

关于如何从 ADD 语句提供的缓存及其正确失效中获益但同时不将添加的文件包含到图像历史记录中的任何想法?

如何在一条长长的 运行 命令中执行 curl/wget、安装和删除?

Update 结合 ADD 更小的资源,参见 TC 的详细回答。

我接受了 Mykola Gurov 的回答,因为在他的一条评论中,他指出了一个帮助我解决这个问题的想法。

以下是我为实现适当的缓存和缓存失效以及排除大安装程序文件所做的工作:

FROM debian:jessie
...
RUN apt-get install -y curl
ENV PROJECT_VERSION x.y.z-SNAPSHOT
...
ADD http://nexus:8081/service/local/artifact/maven/resolve?r=public&g=my.group.id&a=installer&v=${PROJECT_VERSION}&e=sh&c=linux64 ${INSTALL_DIR}/installer.xml
RUN curl --silent "http://nexus:8081/service/local/artifact/maven/content?r=public&g=my.group.id&a=installer&v=${PROJECT_VERSION}&e=sh&c=linux64" \
        --output ${INSTALL_DIR}/installer.sh \
    && sh ${INSTALL_DIR}/installer.sh <someArgs> \
    && rm ${INSTALL_DIR}/installer.sh
...

第一个 ADD 下载所请求工件的 Maven 元数据。 XML 文件很小。它使用适当的缓存,因此只要 Nexus 上的元数据被修改,缓存就会失效。

在这种情况下,ADD 及其所有后续指令将在不重新使用任何缓存版本的情况下执行。

如果服务器上的元数据自上次下载以来未更改,则 ADD 和随后执行 curlRUN 指令将从图像层缓存中获取。在 RUN 中,可以一步下载、执行和删除临时大安装程序文件,而无需将其存储在任何映像层中。