Docker COPY行为不一致

时间:2016-11-05 08:37:47

标签: docker dockerfile

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

基本上我想执行“复杂”操作cp -r app vendor target,其中target是Docker容器。

我有简单的Docker文件:

FROM alpine

COPY app/* /www/
COPY vendor /www/

由于未知原因,第一个命令不会复制app目录本身。似乎Docker没有区分appapp/之间的区别,这是非常恼人的。

出于测试目的,我创建了以下结构:

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

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 . /targetCOPY app/* /target行为不同吗?动机是什么?为什么Docker不使用UNIX cp命令的标准语义?

2 个答案:

答案 0 :(得分:1)

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

COPY /app /www/app/


您可以在documentation中阅读有关COPY指令的更多信息。在这里,我从it粘贴此行为的解释:

  

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



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


使用通配符时,您可以看到略有不同的行为,例如。 COPY app/* /www/。它会将所有文件从app/复制到/www/,然后将app/中的每个目录视为源,并将其内容复制到/www/

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

答案 1 :(得分:0)

这似乎是known issue in 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

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

使用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

请注意,一旦您忽略了父文件夹,就无法从已经忽略的文件夹(related Docker issue)手动复制单个文件:

COPY doc/README /www

刚刚被执行了。