Dockerfile中的条件COPY/ADD?

der*_*end 79 docker dockerfile

在我的Dockerfiles里面我想将一个文件复制到我的图像中(如果它存在),pip的requirements.txt文件似乎是一个很好的候选者,但是如何实现呢?

COPY (requirements.txt if test -e requirements.txt; fi) /destination
...
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi
Run Code Online (Sandbox Code Playgroud)

要么

if test -e requirements.txt; then
    COPY requiements.txt /destination;
fi
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi
Run Code Online (Sandbox Code Playgroud)

jdh*_*deb 63

这是一个简单的解决方法:

COPY foo file-which-may-exist* /target
Run Code Online (Sandbox Code Playgroud)

确保foo存在,因为COPY至少需要一个有效的来源.

如果file-which-may-exist存在,它也将被复制.

注意:您应该注意确保您的通配符不会拾取您不打算复制的其他文件.为了更加小心,您可以使用file-which-may-exist?(?仅匹配单个字符).

或者甚至更好,使用这样的字符类来确保只能匹配一个文件:

COPY foo file-which-may-exis[t] /target
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。奇怪的是我们需要如此奇怪的解决方法...... (7认同)
  • 所以答案是“确保有一个文件”,然后演示如何使用 COPY 运算符?我不明白这与原来的问题有什么关系。 (6认同)
  • 你能用文件夹做同样的事情吗? (2认同)
  • 这很好。对于具有多个目标的文件,我将其复制到一个临时目录中,然后将其移动到需要的位置。COPY --from = docker / usr / bin / docker /usr/lib/libltdl.so* / tmp / docker /`RUN mv / tmp / docker / docker / usr / bin / docker` RUN mv / tmp / docker / libltdl.so.7 /usr/lib/libltdl.so.7 || true(共享库是未知实体)。 (2认同)

Von*_*onC 19

这当前不受支持(因为我怀疑它会导致不可重现的图像,因为相同的Dockerfile会复制或不复制文件,具体取决于它的存在).

问题13045中仍然使用通配符请求这样做:" COPY foo/* bar/" not work if no file in foo"(2015年5月).
它现在(2015年7月)在Docker中不会实现,但像bocker这样的另一个构建工具可以支持这个.

  • 很好的答案,但是码头工人的逻辑,IMO,是有缺陷的.如果您使用不同的构建上下文运行相同的dockerfile,您将获得不同的图像.这是可以预料的.使用相同的构建上下文将给出相同的图像.如果在同一构建上下文中插入条件COPY/ADD指令,您将获得相同的图像.所以检查出来.那只是我的2美分. (23认同)
  • @AndrewMcLagan例如,如果前端`dev`环境与webpack开发服务器一起运行,并且等效的`prod`环境与`/ dist`静态文件夹一起工作会怎么样?今天大多数前端设置都是这种情况,显然`dev`和`prod`在这里不一样.那怎么处理呢? (3认同)

Aid*_*len 15

我想我想出了一个有效的解决方法 Dockerfile

FROM alpine
COPy always_exist_on_host.txt .
COPY *sometimes_exist_on_host.txt .
Run Code Online (Sandbox Code Playgroud)

always_exist_on_host.txt文件将始终被复制到映像,并且sometimes_exist_on_host.txt当文件不存在时,构建不会无法复制该文件。此外,它会在sometimes_exist_on_host.txt文件存在时复制文件。

例如:

.
??? Dockerfile
??? always_exist_on_host.txt
Run Code Online (Sandbox Code Playgroud)

构建成功

FROM alpine
COPy always_exist_on_host.txt .
COPY *sometimes_exist_on_host.txt .
Run Code Online (Sandbox Code Playgroud)
.
??? Dockerfile
??? always_exist_on_host.txt
??? sometimes_exist_on_host.txt
Run Code Online (Sandbox Code Playgroud)

构建仍然成功

.
??? Dockerfile
??? always_exist_on_host.txt
Run Code Online (Sandbox Code Playgroud)

  • @corwin.amber 我添加了 `COPY always_exist_on_host.txt .` 来演示 COPY 通常如何使用。`COPY *sometimes_exist_on_host.txt .` 就是您所需要的。 (3认同)
  • 有趣的选择,在我回答五年后。已投赞成票。 (2认同)
  • 5 年 - 最终解决方案起作用了:-) (2认同)

Siy*_*iyu 11

该评论所述,Santhosh Hirekerur的答案仍会复制文件,要归档真正的条件副本,则可以使用此方法。

ARG BUILD_ENV=copy

FROM alpine as build_copy
ONBUILD COPY file /file

FROM alpine as build_no_copy
ONBUILD RUN echo "I don't copy"

FROM build_${BUILD_ENV}
# other stuff
Run Code Online (Sandbox Code Playgroud)

这些ONBUILD说明确保仅在通过选中“分支”时才复制文件BUILD_ENV。在调用之前使用一些脚本设置此变量docker build

  • @paulecoyote我确信您已经弄清楚了,但是为了在“FROM”中使用“ARG”,必须在第一个“FROM”之前定义“ARG”。如果您还想在“FROM”中使用相同的“ARG”(例如“ENV”),那么您还必须在“FROM”的范围内定义它。[了解 ARG 和 FROM 如何交互](https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact) (12认同)
  • 我刚刚尝试了类似的操作并得到:来自守护程序的错误响应:Dockerfile 解析错误第 52 行:构建阶段的名称无效:“site_builder_${host_env}”,名称不能以数字开头或包含符号 (3认同)
  • 我喜欢这个答案,因为它不仅让我看到了 ONBUILD,这非常方便,而且它似乎也是最容易与传入的其他变量集成的,例如,如果您想基于 BUILD_ENV 设置标签,或者在中存储一些状态环境。 (2认同)

cdo*_*orn 9

将所有文件复制到一次性目录,手动选择您想要的文件,丢弃其余文件。

COPY . /throwaway
RUN cp /throwaway/requirements.txt . || echo 'requirements.txt does not exist'
RUN rm -rf /throwaway
Run Code Online (Sandbox Code Playgroud)

您可以使用依赖于相同解决方案的构建阶段来实现类似的东西,cp用于有条件地复制。通过使用构建阶段,您的最终图像将不会包含初始COPY.

FROM alpine as copy_stage
COPY . .
RUN mkdir /dir_for_maybe_requirements_file
RUN cp requirements.txt /dir_for_maybe_requirements_file &>- || true

FROM alpine
# Must copy a file which exists, so copy a directory with maybe one file
COPY --from=copy_stage /dir_for_maybe_requirements_file /
RUN cp /dir_for_maybe_requirements_file/* . &>- || true
CMD sh
Run Code Online (Sandbox Code Playgroud)


San*_*rur 6

解决方案

我对基于ENV变量将FOLDER复制到服务器有要求。我拍摄了空的服务器映像。在本地文件夹中创建所需的部署文件夹结构。然后将以下行添加到DockerFile中,将文件夹复制到容器中。在最后一行中,添加了入口点以在docker启动服务器之前执行initfile.sh。

#below lines added to integrate testing framework
RUN mkdir /mnt/conf_folder
ADD install /mnt/conf_folder/install
ADD install_test /mnt/conf_folder/install_test
ADD custom-init.sh /usr/local/bin/custom-init.sh
ENTRYPOINT ["/usr/local/bin/custom-init.sh"]
Run Code Online (Sandbox Code Playgroud)

然后使用以下脚本在本地创建 custom-init.sh文件

#!/bin/bash
if [ "${BUILD_EVN}" = "TEST" ]; then
    cp -avr /mnt/conf_folder/install_test/* /mnt/wso2das-3.1.0/
else
    cp -avr /mnt/conf_folder/install/* /mnt/wso2das-3.1.0/
fi;
Run Code Online (Sandbox Code Playgroud)

docker-compose文件下面的行中。

环境:-BUILD_EVN = TEST

这些更改在Docker构建期间将文件夹复制到容器。当我们执行docker-compose up时 ,在服务器启动之前将实际所需的文件夹复制或部署到服务器。

  • 但是,码头工人图像是分层的。无论您提到的if语句如何,ADD都会将这些内容复制到映像中。 (8认同)