我想将文件系统中列入白名单的文件夹复制到目标容器中。
基本上我想执行“复杂”操作cp -r app vendor target
,其中target
是Docker容器。
我有简单的Docker文件:
FROM alpine
COPY app/* /www/
COPY vendor /www/
由于未知原因,第一个命令不会复制app
目录本身。似乎Docker没有区分app
和app/
之间的区别,这是非常恼人的。
出于测试目的,我创建了以下结构:
.
├── 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 . /target
和COPY app/* /target
行为不同吗?动机是什么?为什么Docker不使用UNIX cp
命令的标准语义?
答案 0 :(得分:1)
通常,COPY指令从" / app"复制文件和/或目录。并将它们添加到路径" / www /"的容器中。如果你想拥有一个" app"目录里面的" / www /"那么你的COPY指令应该是:
COPY /app /www/app/
您可以在documentation中阅读有关COPY指令的更多信息。在这里,我从it粘贴此行为的解释:
如果是目录,则复制目录的全部内容,包括文件系统元数据。 注意:不复制目录本身,只复制其内容。
关于你的更新:
COPY . /target
和COPY 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
使用tar
和Makefile
的优势在于它的行为类似于正确的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
刚刚被执行了。