149

I tried the following command in my Dockerfile: COPY * / and got mighty surprised at the result. Seems the naive docker code traverses the directories from the glob and then dumps the each file in the target directory while respectfully ignoring my directory structure.

At least that is how I understand this ticket and it certainly corresponds to the result I got.

I guess the only reason this behavior can still exist must be that there is some other way this should be done. But it is not so easy for a bear of very little brain to understand how, does anyone know?

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
jonalv
  • 5,706
  • 9
  • 45
  • 64

10 Answers10

99

Use ADD (docs)

The ADD command can accept as a <src> parameter:

  1. A folder within the build folder (the same folder as your Dockerfile). You would then add a line in your Dockerfile like this:
ADD folder /path/inside/your/container

or

  1. A single-file archive anywhere in your host filesystem. To create an archive use the command:
tar -cvzf newArchive.tar.gz /path/to/your/folder

You would then add a line to your Dockerfile like this:

ADD /path/to/archive/newArchive.tar.gz  /path/inside/your/container

Notes:

  • ADD will automatically extract your archive.
  • presence/absence of trailing slashes is important, see the linked docs
Patryk
  • 22,602
  • 44
  • 128
  • 244
ryanrain
  • 4,473
  • 3
  • 21
  • 21
  • 3
    Thank you sir. Excellent solution. The only odd thing I found via trail & error is that the container path should reflect folder name. E.g ADD myFolder /container/myFolder , then myFolder and it's content will be in the expected place. – Leo Ufimtsev Feb 10 '19 at 19:23
  • 2
    I cannot emphasise how important under Point 1 is that the 1st argument of `ADD` _must be within the build folder_ . – András Aszódi Mar 02 '21 at 16:30
  • In the event you're building stuff on Windows and need to get a folder structure inside the Dockerfile folder, there's a great command called "robocopy /mir" that will mirror the contents of a directory. When you're done with the build, just "erase /s /q" and "rmdir /s /q" and it's like it was never there. Robocopy is awesome. – Jason Hughes Nov 01 '21 at 20:50
  • 1
    If I put the archive in /tmp and then try ADD /tmp/file.tar.gz it does not resolve. Maybe the archive also needs to be in the build directory. – Christopher King Jul 24 '22 at 01:20
  • 1
    Part #1 is incorrect, at least as of now. The Dockerfile reference (https://docs.docker.com/engine/reference/builder/#add) is very clear that if the `` is a directory, it will copy the contents of the directory and explicitly NOT copy the directory. This is the same for both `COPY` and `ADD`. – mtalexan Mar 08 '23 at 17:22
40

Like @Vonc said, there is no possibility to add a command like as of now. The only workaround is to mention the folder, to create it and add contents to it.

# add contents to folder
ADD src $HOME/src

Would create a folder called src in your directory and add contents of your folder src into this.

Balasubramani M
  • 7,742
  • 2
  • 45
  • 47
31

use ADD instead of COPY. Suppose you want to copy everything in directory src from host to directory dst from container:

ADD src dst

Note: directory dst will be automatically created in container.

Hin Fan Chan
  • 1,543
  • 10
  • 11
  • 8
    What is 'b'? And https://github.com/docker/docker/issues/18396 suggests ADD does not create subfolders. – VonC Jun 13 '16 at 16:40
  • 2
    Your answer is not clear, but I could get the point you are trying to say and figured out my answer above. It works well. – Balasubramani M Jul 22 '17 at 04:47
  • this seems incorrect, if I do that I just get an empty folder. – Vincent Gerris Mar 18 '21 at 15:30
  • 1
    The original answer was from 2016. Nowadays https://docs.docker.com/engine/reference/builder/ should be the source of truth on usage. The original problem of this thread was `COPY * /` didn't behave as expected, where people expect it to behave like `cp` in bash or `copy` in powershell, which it doesn't. The author should have used `COPY . /` or `ADD . /`, which by itself is a problem as `/` refers to the root, which is not likely to be intentional. `COPY` should not be use as it causes confusion to the copy function of different OSes. – Hin Fan Chan Mar 19 '21 at 02:38
  • At least in 2021, it does now work and creates all subfolders in the tree below src – blissweb Dec 30 '21 at 06:23
  • According to the documentation in 2023, and testing. it does not create subfolders unless you include the `.` on the source folder. So `ADD src/. dst/` will copy all files and folders from within `src` into `dst`, but will not copy the `src` folder itself. Using `src/` instead of `src/.` will copy all files from within `src` into `dst` without any of the directory structure within `src`. – mtalexan Mar 08 '23 at 17:26
23

As mentioned in your ticket:

You have COPY files/* /test/ which expands to COPY files/dir files/file1 files/file2 files/file /test/.
If you split this up into individual COPY commands (e.g. COPY files/dir /test/) you'll see that (for better or worse) COPY will copy the contents of each arg dir into the destination directory. Not the arg dir itself, but the contents.

I'm not thrilled with that fact that COPY doesn't preserve the top-level dir but its been that way for a while now.

so in the name of preserving a backward compatibility, it is not possible to COPY/ADD a directory structure.

The only workaround would be a series of RUN mkdir -p /x/y/z to build the target directory structure, followed by a series of docker ADD (one for each folder to fill).
(ADD, not COPY, as per comments)

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 3
    The workaround is to use `ADD` correctly. I've tried to clarify usage in my answer below. – ryanrain Oct 09 '18 at 16:15
  • 2
    COPY can't do it, but ADD can. This answer is misleading since the suggestion is to manually create structure instead of using ADD. As per @ryanrain, folders & content can be added. I've successfully been able to do so via ADD (but not COPY). I suggest updating this answer or removing it. – Leo Ufimtsev Feb 10 '19 at 19:05
17

COPY . <destination>

Which would be in your case:

COPY . /

Klaus
  • 1,171
  • 1
  • 11
  • 16
  • 7
    [Indeed](https://github.com/moby/moby/issues/15858#issuecomment-330511914): Don't use `COPY * /app`, it doesn't do what you'd expect it to do. Use `COPY . /app` instead to preserve the directory tree. – kadee Jan 18 '19 at 08:16
12

I don't completely understand the case of the original poster but I can proof that it's possible to copy directory structure using COPY in Dockerfile.

Suppose you have this folder structure:

folder1
  file1.html
  file2.html
folder2
  file3.html
  file4.html
  subfolder
    file5.html
    file6.html

To copy it to the destination image you can use such a Dockerfile content:

FROM nginx

COPY ./folder1/ /usr/share/nginx/html/folder1/
COPY ./folder2/ /usr/share/nginx/html/folder2/

RUN ls -laR /usr/share/nginx/html/*

The output of docker build . as follows:

$ docker build --no-cache .
Sending build context to Docker daemon  9.728kB
Step 1/4 : FROM nginx
 ---> 7042885a156a
Step 2/4 : COPY ./folder1/ /usr/share/nginx/html/folder1/
 ---> 6388fd58798b
Step 3/4 : COPY ./folder2/ /usr/share/nginx/html/folder2/
 ---> fb6c6eacf41e
Step 4/4 : RUN ls -laR /usr/share/nginx/html/*
 ---> Running in face3cbc0031
-rw-r--r-- 1 root root  494 Dec 25 09:56 /usr/share/nginx/html/50x.html
-rw-r--r-- 1 root root  612 Dec 25 09:56 /usr/share/nginx/html/index.html

/usr/share/nginx/html/folder1:
total 16
drwxr-xr-x 2 root root 4096 Jan 16 10:43 .
drwxr-xr-x 1 root root 4096 Jan 16 10:43 ..
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file1.html
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file2.html

/usr/share/nginx/html/folder2:
total 20
drwxr-xr-x 3 root root 4096 Jan 16 10:43 .
drwxr-xr-x 1 root root 4096 Jan 16 10:43 ..
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file3.html
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file4.html
drwxr-xr-x 2 root root 4096 Jan 16 10:33 subfolder

/usr/share/nginx/html/folder2/subfolder:
total 16
drwxr-xr-x 2 root root 4096 Jan 16 10:33 .
drwxr-xr-x 3 root root 4096 Jan 16 10:43 ..
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file5.html
-rwxr-xr-x 1 root root    7 Jan 16 10:32 file6.html
Removing intermediate container face3cbc0031
 ---> 0e0062afab76
Successfully built 0e0062afab76
Mike Eshva
  • 1,078
  • 15
  • 17
  • Try adding more subfolders into "folder2". You may find that not all of them are copied... – Nagev Feb 05 '20 at 11:53
  • Helpful answer! Be aware though - I have found that files/folders that are listed in `.gitignore` (and of course `.dockerignore`) are not copied over – Jannie Theunissen Apr 08 '22 at 06:20
2
FROM openjdk:8-jdk-alpine
RUN apk update && apk add wget openssl lsof procps curl
RUN apk update
RUN mkdir -p /apps/agent
RUN mkdir -p /apps/lib
ADD ./app/agent /apps/agent
ADD ./app/lib /apps/lib
ADD ./app/* /apps/app/
RUN ls -lrt /apps/app/
CMD sh /apps/app/launch.sh

Within my Dockerfile, I'm copying my ./apps/agent and ./apps/lib directories to /apps/agent and /apps/lib directories.

domdambrogia
  • 2,054
  • 24
  • 31
0

Replace the * with a /

So instead of

COPY * <destination>

use

COPY / <destination>

rayscott
  • 49
  • 1
  • 2
  • 14
    Bad idea. COPY / will copy your root volume into the docker image – jarlef Oct 18 '18 at 05:55
  • 1
    @jarlef This behavior seems to vary between windows and linux. In Windows it takes the build context just fine. – duct_tape_coder Feb 13 '19 at 16:01
  • 12
    COPY / will NOT copy your root volume into the docker image on linux either. It will copy the root of the build context. You can never copy anything into an image from outside the build context. – dpwr Jun 05 '19 at 10:31
-1

Suppose you want to copy the contents from a folder where you have docker file into your container. Use ADD:

RUN mkdir /temp
ADD folder /temp/Newfolder  

it will add to your container with temp/newfolder

folder is the folder/directory where you have the dockerfile, more concretely, where you put your content and want to copy that.

Now can you check your copied/added folder by runining container and see the content using ls

Learning
  • 9
  • 6
-5

the simplest way:

sudo docker cp path/on/your/machine adam_ubuntu:/root/path_in_container

Note putting into the root path if you are copying something that needs to be picked up by the root using ~.

Adam Liu
  • 1,288
  • 13
  • 17
  • 4
    I hope you understand by now why this answer is not appropriate :) It's neither the simplest, it's the worst practice possible as you shouldn't interfere with the actual containers, and it's not even related to OP's question, since OP asks regarding the Dockerfile, not a shell command. – Eksapsy Nov 18 '19 at 03:26