Docker的COPY行为不一致

我想将文件系统中的白名单文件夹复制到目标容器中。

基本上我想执行“复杂”操作cp -r app vendor target ,其中target是一个docker集装箱。

我有简单的Docker文件:

 FROM alpine COPY app/* /www/ COPY vendor /www/ 

由于未知的原因,第一个命令不会复制app目录本身。 看起来Docker并没有区分appapp/之间的区别,这是相当令人恼火的。

出于testing目的,我创build了以下结构:

 . ├── app │  ├── foo │  └── second │  └── barf ├── Dockerfile └── vendor └── bar 

docker build -t test . && docker run -it test ash docker build -t test . && docker run -it test ash

结果? 不保留目录结构,不复制父目录。

 /www/ ├── bar ├── barf └── foo 

docker info

 Server Version: 1.12.1 Storage Driver: overlay2 Backing Filesystem: extfs 

任何人都可以解释为什么docker的COPY . /target COPY . /targetCOPY app/* /target行为有所不同? 什么动机? 为什么Docker不使用UNIX cp命令的标准语义?

通常,COPY指令从“/ app”复制文件和/或目录,并将它们添加到path为“/ www /”的容器中。 如果你想在“/ www /”里面有一个“app”目录,那么你的COPY指令应该是这样的:

 COPY /app /www/app/ 

您可以在文档中阅读有关COPY指令的更多信息。 我在这里贴上这个行为的解释:

如果是目录,则会复制目录的全部内容,包括文件系统元数据。 注意: 目录本身不被复制,只是它的内容。

关于你的更新:
COPY . /target COPY . /targetCOPY app /target行为相同。 它源目录(从app.目录)获取全部内容,并将其复制到/target目录。

当你使用通配符时,你可以看到稍微不同的行为,例如。 COPY app/* /www/ 。 它将所有文件从app/复制到/www/但是然后它将每个单独的目录从app/源文件中复制到/www/

为什么在Docker中COPY的实现方式与UNIX中的cp命令不同? 我不知道,但如果你想要你可以创build自己的执行拉请求:)

这似乎是Docker中的一个已知问题,不会很快得到解决。

有几个解决方法如何指定多个文件夹和复制文件夹本身和所需的内容。 请注意,你不能使用星号(例如app/*这会导致平坦的目录结构。

多个COPY命令

 RUN mkdir -p app bin config db lib public COPY app/ app COPY bin/ bin COPY config/ config COPY db/ db COPY lib/ lib COPY public/ public 

在某些情况下,这会产生相当长的列表,每个命令在图像树中创build一个单独的图层。

使用tar

使用tarMakefile有一个好处,就像一个合适的UNIX程序(你可以定义排除模式,斜线, *等)。

Makefile

 all: tar -cf files.tar app bin config db lib public docker build -t image-name . rm files.tar 

那么在Dockerfile您必须使用ADD命令才能将文件解压缩到所需的结构中:

 ADD files.tar /www 

使用.dockerignore

Dockerfile只需复制一切

 COPY . /www 

并在.dockeringnore列出所有不应复制的模式:

 .git test/ doc/ log/ tmp/ Dockerfile Makefile 

请注意,一旦忽略父文件夹,就无法手动复制已经被忽略的文件夹中的单个文件( 相关的Docker问题 ):

 COPY doc/README /www 

只是不会被执行。