Reputation: 229371
Is there any way to copy multiple directories in one command, to reduce the number of layers? E.g., instead of:
COPY dirone ./dirone
COPY dirtwo ./dirtwo
COPY dirthree ./dirthree
I want to do:
COPY dirone/ dirtwo/ dirthree/ ./
However, this copies the contents of the directories... but I want to copy the directories themselves.
Upvotes: 130
Views: 77292
Reputation: 21
There is recent update that enables such functionality - https://github.com/moby/buildkit/releases/tag/dockerfile/1.7.0-labs
To work with it - add comment in the beginning of the Dockerfile
# syntax=docker.io/docker/dockerfile:1.7-labs
And use --parents flag in COPY command. Example:
FROM python
WORKDIR src/
COPY --parents moo/ foo/ ./
Upvotes: 2
Reputation: 1042
Dockerfile
COPY . ./
.dockerignore
/dirfour
/dirfive
/file.txt
Dockerfile
COPY . ./
.dockerignore
/**
!/dirone
!/dirtwo
!/dirthree
Upvotes: 37
Reputation: 8719
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.
Upvotes: 2
Reputation: 167
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:
RUN cp -r /tmp/dirone/ /tmp/dirtwo/ /tmp/dirthree/ ./
/
Upvotes: -4
Reputation: 74720
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
Upvotes: 21
Reputation: 263856
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.
Upvotes: 72