Reputation: 32378
I would like to copy whitelisted folders from filesystem into target container.
Basically I'd like to perform "complex" operation cp -r app vendor target
, where target
is a Docker container.
I have simple Docker file:
FROM alpine
COPY app/* /www/
COPY vendor /www/
For reasons unknown the first command doesn't copy the app
directory itself. It seems that Docker doesn't distinguish the difference between app
and app/
which is quite irritating.
For testing purposes I've created following structure:
.
├── app
│ ├── foo
│ └── second
│ └── barf
├── Dockerfile
└── vendor
└── bar
docker build -t test . && docker run -it test ash
:
Result? Directory structure is not kept and parent directories not copied.
/www/
├── bar
├── barf
└── foo
docker info
:
Server Version: 1.12.1
Storage Driver: overlay2
Backing Filesystem: extfs
Can anyone explain me why Docker's COPY . /target
and COPY app/* /target
behaves differently? What's the motivation? Why Docker doesn't used standard semantic of UNIX cp
command?
Upvotes: 8
Views: 6721
Reputation: 32378
This seems to be a known issue in Docker which won't get fixed any time soon.
There are several workaround how to specify multiple folder and copy folder itself and desired content. Note that you can't use asterisk (e.g. app/*
which would cause flattening directory structure.
Multiple COPY
commands
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
In some cases this produce quite a long list and each command creates a separate layer in the image tree.
Using tar
Using tar
and Makefile
has an advantage that it behaves like a proper UNIX program (you can define exclude patterns, slashes, *
etc.).
Makefile
:
all:
tar -cf files.tar app bin config db lib public
docker build -t image-name .
rm files.tar
then in Dockerfile
you have to use ADD
command in order to extract files into desired structure:
ADD files.tar /www
Using .dockerignore
In Dockerfile
simply copy everything
COPY . /www
and in .dockeringnore
list all patterns that should not be copied:
.git
test/
doc/
log/
tmp/
Dockerfile
Makefile
note that once you're ignoring parent folder, there's no way how to manually copy single file from a folder that's already ignored (related Docker issue):
COPY doc/README /www
just won't be executed.
Upvotes: 2
Reputation: 1539
Generally, COPY instruction copy files and/or directories from "/app" and adds them to the container at path "/www/". If you want to have a "app" directory inside of "/www/" then your COPY instruction should looks like:
COPY /app /www/app/
You can read more about COPY instruction in documentation. Here I paste explanation of this behaviour from it:
If is a directory, the entire contents of the directory are copied, including filesystem metadata. Note:The directory itself is not copied, just its contents.
Regarding to your update:
COPY . /target
and COPY app /target
behaves the same. It takes entire contents from source directory ( from app
or from .
directory ) and copy it to the /target
directory.
You can see slightly different behaviour when you use wildcards, eg. COPY app/* /www/
. It copy all files from app/
to /www/
but then it treat every single directory from app/
like a source and copy its contents to /www/
.
Why in Docker COPY
is not implemented in the same way like it is in UNIX's cp
command? I don't know, but if you want you can create pull request with own implementation :)
Upvotes: 7