Docker的COPY行为不一致
我想将文件系统中的白名单文件夹复制到目标容器中。
基本上我想执行“复杂”操作cp -r app vendor target
,其中target
是一个docker集装箱。
我有简单的Docker文件:
FROM alpine COPY app/* /www/ COPY vendor /www/
由于未知的原因,第一个命令不会复制app
目录本身。 看起来Docker并没有区分app
和app/
之间的区别,这是相当令人恼火的。
出于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 . /target
和COPY app/* /target
行为有所不同? 什么动机? 为什么Docker不使用UNIX cp
命令的标准语义?
通常,COPY指令从“/ app”复制文件和/或目录,并将它们添加到path为“/ www /”的容器中。 如果你想在“/ www /”里面有一个“app”目录,那么你的COPY指令应该是这样的:
COPY /app /www/app/
您可以在文档中阅读有关COPY指令的更多信息。 我在这里贴上这个行为的解释:
如果是目录,则会复制目录的全部内容,包括文件系统元数据。 注意: 目录本身不被复制,只是它的内容。
关于你的更新:
COPY . /target
COPY . /target
和COPY 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
使用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
请注意,一旦忽略父文件夹,就无法手动复制已经被忽略的文件夹中的单个文件( 相关的Docker问题 ):
COPY doc/README /www
只是不会被执行。