Dockerfile中的条件COPY / ADD?

时间:2015-07-21 00:16:52

标签: 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

if test -e requirements.txt; then
    COPY requiements.txt /destination;
fi
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi

8 个答案:

答案 0 :(得分:46)

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

COPY foo file-which-may-exist* /target

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

如果存在file-which-may-exist,它也会被复制。

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

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

COPY foo file-which-may-exis[t] /target

答案 1 :(得分:14)

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

仍在issue 13045使用通配符请求“COPY foo/* bar/" not work if no file in foo”(2015年5月)。
它现在(2015年7月)在Docker中不会实现,但是像 bocker 这样的其他构建工具可以支持这一点。

答案 2 :(得分:7)

this comment所述,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

ONBUILD指令可确保仅在BUILD_ENV选择了“分支”的情况下才复制文件。在调用docker build

之前,使用一些小脚本设置此变量

答案 3 :(得分:6)

解决方案

我要求基于ENV变量将FOLDER复制到服务器。我拿了空的服务器图像。在本地文件夹中创建所需的部署文件夹结构。然后将以下行添加到 DockerFile 将文件夹复制到容器。我 n最后一行在docker启动服务器之前添加了执行init file.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"]

然后使用下面的脚本在本地创建 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;

docker-compose 文件下面的行。

环境:        - BUILD_EVN = TEST

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

答案 4 :(得分:3)

我想我对此Dockerfile

提出了有效的解决方法
FROM alpine
COPy always_exist_on_host.txt .
COPY *sometimes_exist_on_host.txt .

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

例如:

.
├── Dockerfile
└── always_exist_on_host.txt

构建成功

docker build . -t copy-when-exists --no-cache
[+] Building 1.0s (7/7) FINISHED                                                                                                                            
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 36B                                                                                                                    0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                                                       1.0s
 => [internal] load build context                                                                                                                      0.0s
 => => transferring context: 43B                                                                                                                       0.0s
 => CACHED [1/2] FROM docker.io/library/alpine@sha256:c0e9560cda118f9ec63ddefb4a173a2b2a0347082d7dff7dc14272e7841a5b5a                                 0.0s
 => [2/2] COPY always_exist_on_host.txt *sometimes_exist_on_host.txt .                                                                                 0.0s
 => exporting to image                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                0.0s
 => => writing image sha256:e7d02c6d977f43500dbc1c99d31e0a0100bb2a6e5301d8cd46a19390368f4899                                                           0.0s               

.
├── Dockerfile
├── always_exist_on_host.txt
└── sometimes_exist_on_host.txt

构建仍然成功

docker build . -t copy-when-exists --no-cache
[+] Building 1.0s (7/7) FINISHED                                                                                                                            
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 36B                                                                                                                    0.0s
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                                                       0.9s
 => [internal] load build context                                                                                                                      0.0s
 => => transferring context: 91B                                                                                                                       0.0s
 => CACHED [1/2] FROM docker.io/library/alpine@sha256:c0e9560cda118f9ec63ddefb4a173a2b2a0347082d7dff7dc14272e7841a5b5a                                 0.0s
 => [2/2] COPY always_exist_on_host.txt *sometimes_exist_on_host.txt .                                                                                 0.0s
 => exporting to image                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                0.0s
 => => writing image sha256:4c88e2ffa77ebf6869af3c7ca2a0cfb9461979461fc3ae133709080b5abee8ff                                                           0.0s
 => => naming to docker.io/library/copy-when-exists                                                                                                    0.0s

答案 5 :(得分:0)

将所有文件复制到一个可丢弃的目录中,手动选择一个文件,其余文件丢弃。

COPY . /throwaway
RUN cp /throwaway/requirements.txt . || echo 'requirements.txt does not exist'
RUN rm -rf /throwaway

答案 6 :(得分:0)

尝试了其他想法,但没有一个满足我们的要求。这个想法是为子静态Web应用程序创建基本的nginx图像。出于安全性,优化和标准化的原因,基本映像必须能够对子映像添加的目录执行RUN命令。基本映像不控制子映像添加哪些目录。假设子图像将COPY的资源COMMON_DEST_ROOT下的某个位置。

此方法是一种技巧,但是基本映像将支持COPY指令,用于由子映像添加的1到N个目录。 ARG PLACEHOLDER_FILEENV UNPROVIDED_DEST用于满足不需要的任何<src>指令的<dest>COPY要求。

#
# base-image:01
#
FROM nginx:1.17.3-alpine
ENV UNPROVIDED_DEST=/unprovided
ENV COMMON_DEST_ROOT=/usr/share/nginx/html
ONBUILD ARG PLACEHOLDER_FILE
ONBUILD ARG SRC_1
ONBUILD ARG DEST_1
ONBUILD ARG SRC_2
ONBUILD ARG DEST_2
ONBUILD ENV SRC_1=${SRC_1:-PLACEHOLDER_FILE}
ONBUILD ENV DEST_1=${DEST_1:-${UNPROVIDED_DEST}}
ONBUILD ENV SRC_2=${SRC_2:-PLACEHOLDER_FILE}
ONBUILD ENV DEST_2=${DEST_2:-${UNPROVIDED_DEST}}

ONBUILD COPY ${SRC_1} ${DEST_1}
ONBUILD COPY ${SRC_2} ${DEST_2}

ONBUILD RUN sh -x \
    #
    # perform operations on COMMON_DEST_ROOT
    #
    && chown -R limited:limited ${COMMON_DEST_ROOT} \
    #
    # remove the unprovided dest
    #
    && rm -rf ${UNPROVIDED_DEST}

#
# child image
#
ARG PLACEHOLDER_FILE=dummy_placeholder.txt
ARG SRC_1=app/html
ARG DEST_1=/usr/share/nginx/html/myapp
FROM base-image:01

此解决方案具有明显的缺点,例如伪PLACEHOLDER_FILE和受支持的COPY指令的硬编码数量。同样,也没有办法摆脱COPY指令中使用的ENV变量。

答案 7 :(得分:-9)

也许你只是不需要!让我们再看一下你的代码:

COPY (requirements.txt if test -e requirements.txt; fi) /destination
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi

也许你可以切换到:

COPY requirements.txt /requirements.txt
RUN  if test -e /requirements.txt; then pip install -r /requirements.txt; fi

现在你有了这个:

  • 如果文件存在,它将被COPY复制并在RUN中由PIP处理
  • 如果该文件不存在,COPY将失败(我想是默默地),并且因为条件而PIP不会运行