用一个命令复制多个目录

有没有办法在一个命令中复制多个目录,从而减少图层的数量? 例如:

COPY dirone ./dirone
COPY dirtwo ./dirtwo
COPY dirthree ./dirthree

我想做的是:

COPY dirone/ dirtwo/ dirthree/ ./

但是,这复制了目录的 内容... 但是我想复制 目录本身

52052 次浏览

That's the documented behavior of the copy command:

If <src> is a directory, the entire contents of the directory are copied, including filesystem metadata.

Note: The directory itself is not copied, just its contents.

Best workaround I can suggest is to change your directory layout in your build folder, move the three folders under one parent folder and add the parent.

As BMitch answered, that is expected COPY behaviour.

An alternative would be to ADD the contents of a tarball.

Create the initial tarball

tar -cvf dirs.tar dirone/ dirtwo/ dirthree/

Add it to the build

FROM busybox
ADD dirs.tar /
CMD find /dirone /dirtwo /dirthree

The tarball is automatically extracted

○ →docker run c28f96eadd58
/dirone
/dirone/one
/dirtwo
/dirtwo/two
/dirthree
/dirthree/three

Note that every time you update the tar file you are invalidating the Docker build cache for that step. If you are dealing with a lot of files you might want to be smart about when you do the tar -c. You could also use tar -u if you can deal with files not being automatically deleted from the tarball.

[ -f dirs.tar ] && tar -uf dirs.tar something || tar -cf dirs.tar something

The actual solution, that will not change your code and will use only dockerfile

COPY . /tmp/
WORKDIR /tmp/
RUN cp -r dirone/ dirtwo/ dirthree/ /full_path_to_app/
WORKDIR /full_path_to_app/

Be aware, that:

  • You need to change your workdir back for something useful, after /tmp.
  • You can do it without workdir, but then you will need to repeat path RUN cp -r /tmp/dirone/ /tmp/dirtwo/ /tmp/dirthree/ ./
  • Destination path must be absolute, otherwise, it will be related to workdir
  • Destination should end with /

Along the lines of the previous answers, but with the (relatively modern) multiple FROM support:

FROM alpine AS src
RUN mkdir -p /src /dst/a /dst/b /dst/rest
WORKDIR /src
COPY . .
RUN true \
&& mv a aa aaa /dst/a/ \
&& mv b bb bbb /dst/b/ \
&& mv * /dst/rest/




FROM realbaseimage


COPY --stage=src /dst/a .
RUN do stuff that needs only a


COPY --stage=src /dst/b .
RUN do stuff that needs only b


COPY --stage=src /dst/rest .
RUN do stuff that needs the rest

This will layer and cache properly: the layers created in the src stage won't be pushed, so the copy/run layers in the final image will be sized and cached according to the contents of parts rather than having duplication and cache invalidation of the whole when changing one thing.

You can change the src stage's base image to whatever, but it needs to have the mv binary, obviously.

  1. You can copy entire parent directory and exclude all other folders/files in .dockerignore file

Dockerfile

COPY . ./

.dockerignore

/dirfour
/dirfive
/file.txt
  1. Or you can ignore entire parent folder in .dockerignore and include only folders you want to copy

Dockerfile

COPY . ./

.dockerignore

/**
!/dirone
!/dirtwo
!/dirthree