如何在 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
...
通过这种方法,我能够:
- 查询 Nexus 以提供在
docker build
期间注销的 ${PROJECT_VERSION}
的最新 SNAPSHOT 版本
- 使用该版本下载相应的安装程序二进制文件
- 执行二进制安装程序
- 执行后立即删除安装程序二进制文件,不要将其存储在创建的 Docker 映像层中
缺少什么:
- 每当将新安装程序部署到 Nexus 时,我都必须使用
docker build --no-cache
构建 Docker 映像。否则 Docker 无法 使其缓存失效 并重新 运行 安装同时部署到 Nexus 的较新安装程序的步骤。
所以我尝试了一种使用 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
...
该方法不起作用,因为:
- 无法将
Dockerfile
中的 ${VERSION}
环境变量设置为 version.txt
文件中存储的版本。
- 无法阻止将安装程序存储在图像层中。
但至少这将使用适当的缓存来为旧安装程序版本重新使用现有图像层,并在 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
和随后执行 curl
的 RUN
指令将从图像层缓存中获取。在 RUN
中,可以一步下载、执行和删除临时大安装程序文件,而无需将其存储在任何映像层中。
我们的 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
...
通过这种方法,我能够:
- 查询 Nexus 以提供在
docker build
期间注销的 - 使用该版本下载相应的安装程序二进制文件
- 执行二进制安装程序
- 执行后立即删除安装程序二进制文件,不要将其存储在创建的 Docker 映像层中
${PROJECT_VERSION}
的最新 SNAPSHOT 版本
缺少什么:
- 每当将新安装程序部署到 Nexus 时,我都必须使用
docker build --no-cache
构建 Docker 映像。否则 Docker 无法 使其缓存失效 并重新 运行 安装同时部署到 Nexus 的较新安装程序的步骤。
所以我尝试了一种使用 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
...
该方法不起作用,因为:
- 无法将
Dockerfile
中的${VERSION}
环境变量设置为version.txt
文件中存储的版本。 - 无法阻止将安装程序存储在图像层中。
但至少这将使用适当的缓存来为旧安装程序版本重新使用现有图像层,并在 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
和随后执行 curl
的 RUN
指令将从图像层缓存中获取。在 RUN
中,可以一步下载、执行和删除临时大安装程序文件,而无需将其存储在任何映像层中。