Reputation: 1293
Consider the following docker build context:
src/
hi
there
bye
and Dockerfile:
FROM ubuntu
RUN mkdir test
COPY src/hi src/there test/
This works just fine but I would like to make the list of files to copy an ARG
, something like:
FROM ubuntu
ARG files
RUN mkdir test
COPY ${files} test/
Unfortunately calling with docker build --build-arg files='src/hi src/there' some_path
fails because it treats src/hi src/there
as a single item. How can I "expand" the files
argument into multiple files to copy?
On a whim I tried specifying the files arg multiple times: docker build --build-arg files='src/hi' --build-arg files='src/there' some_path
, but this only copies "there".
Upvotes: 7
Views: 3159
Reputation: 1293
I have run into this again years later but now found an adequate solution, assuming the files can be grouped into a fixed set of categories.
The answer is basically combining the answers of Docker COPY files using glob pattern? and https://unix.stackexchange.com/questions/59112/preserve-directory-structure-when-moving-files-using-find
Conceptually, the idea is to separate the groups of files in one stage, then copy each group one by one (or ignoring it).
In code:
# Create dummy stage for splitting up files
FROM ubuntu AS src
RUN mkdir /groups
WORKDIR /groups
RUN mkdir group1 group2
# Makes `group2` the de-facto default, can be any though
COPY src group2
RUN rsync --recursive --remove-source-files --prune-empty-dirs \
--include='hi' \
--include='there' \
--exclude='*' \
group2/ group1/
# Create the image we actually care about
FROM ubuntu
COPY --from=src /groups/group1 test/
RUN commands requiring only `group1` files
COPY --from=src /groups/group2 test/
RUN commands requiring all files
Upvotes: 1
Reputation: 641
Although COPY
doesn't accept a list of files in a variable, the cp
command does. Here is a solution I used.
# Create an image with all files from src/ copied into it.
FROM ubuntu as builder
COPY src/ /src/
# Copy only the files specified in the `ARG` to a separate folder files_to_copy/
ARG files
RUN mkdir /files_to_copy && cp $files /files_to_copy/
# Create new image with files that were copied to files_to_copy/
FROM ubuntu
RUN mkdir src
COPY --from=builder /files_to_copy/* src/
Build like this:
docker build . --build-arg files='src/hi src/there'
Upvotes: 0
Reputation: 315
As a possible workaround, you can try to use .dockerignore
file
*
!src/hi
!src/there
with
COPY . test/
https://docs.docker.com/engine/reference/builder/#dockerignore-file
Finally, you may want to specify which files to include in the context, rather than which to exclude. To achieve this, specify * as the first pattern, followed by one or more ! exception patterns.
Update:
Using wildcards in .dockerignore
is limited because of bug:
https://github.com/moby/moby/issues/30018
Upvotes: 1
Reputation: 1959
From the Docker documentation, for your information.
If you have multiple Dockerfile steps that use different files from your context, COPY them individually, rather than all at once. This ensures that each step’s build cache is only invalidated (forcing the step to be re-run) if the specifically required files change.
Upvotes: 0
Reputation: 1325137
because it treats
src/hi src/there
as a single item.
How can I "expand" the files argument into multiple files to copy?
That seems unlikely considering the Dockerfile format mentions, regarding arguments:
whitespace in instruction arguments, such as the commands following
RUN
, are preserved
And that is not limited to RUN
.
COPY
, however, also includes:
Each
<src>
may contain wildcards and matching will be done using Go’sfilepath.Match
rules.
It would not work in your case.
Remain the multi-stage builds approach
COPY src
(the all folder)
Remove everything you don't want:
RUN find pip ${files} -maxdepth 1 -mindepth 1 -print | xargs rm -rf
Build your actual image based on the resulting state of the first image.
You can pass as one argument the folders you want to preserve
docker build --build-arg="files=! -path "src/hi" ! -path "src/there"" .
See an example in "Docker COPY
files using glob pattern?".
Upvotes: 2