jonalv
jonalv

Reputation: 6116

How to copy folders to docker image from Dockerfile?

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?

Upvotes: 168

Views: 455790

Answers (11)

VonC
VonC

Reputation: 1323045

2016: 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 argument dir into the destination directory. Not the argument 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)


2023: moby/buildkit PR 3001 proposes adding --parents opt-in flag for ADD/COPY, merged with commit 9dd188b:

COPY [--parents[=<boolean>]] <src>... <dest>

The --parents flag preserves parent directories for src entries. This flag defaults to false.

# syntax=docker/dockerfile:1.7-labs
FROM scratch

COPY ./x/a.txt ./y/a.txt /no_parents/
COPY --parents ./x/a.txt ./y/a.txt /parents/

# /no_parents/a.txt
# /parents/x/a.txt
# /parents/y/a.txt

The results are encouraging:

I just tried the feature and I have to say to everyone who has been involved: Thank you so much!
We have a JS monorepo and so far to split dependency installation and building into 2 stages, we had to either manually specify all package.json and lock files manually or use scripts to isolate these files in a separate folder before copying it into the build context.

Now it's just a COPY --parents pnpm-workspace.yaml **/package.json **/pnpm-lock.yaml ./ away, and I get a super nice tree that I can just pnpm install.

But also:

The behavior was confusing because it copied files relative to the destination directory, even when the dst was specified as an absolute path and had a common path prefix with the src directory. I'm guessing this is the intended behavior.

For example, the following command copied the files into /usr/src/app/packages/**usr/src/app/packages**/**/dist.

COPY --parents --from=build /usr/src/app/packages/**/dist /usr/src/app/packages

I managed to fix it with the following command:

COPY --parents --from=build /usr/src/app/packages/**/dist /

See COPY --parents, not yet available in stable syntax, use docker/dockerfile:1.7-labs version.

Upvotes: 27

user2138149
user2138149

Reputation: 16484

If you want to copy a subdirectory, you must repeat the name of the subdirectory in the destination.

For example, I wanted to copy the directory example_subdirectory into the working directory on the Docker container side.

This does not work:

workdir /example
copy ./example_subdirectory .

It does not work because it copies the contents of example_subdirectory but not the directory example_subdirectory itself.

To fix it:

copy ./example_subdirectory ./example_subdirectory

This will create a directory called example_subdirectory in the destination on the Docker side.

The copy command has different semantics to the Linux (and also Windows) cp command, which is confusing.

Upvotes: 0

ChandraSen Sriramoju
ChandraSen Sriramoju

Reputation: 51

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.

Upvotes: 4

ryanrain
ryanrain

Reputation: 4837

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

Upvotes: 117

Hin Fan Chan
Hin Fan Chan

Reputation: 1643

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.

Upvotes: 35

Learning
Learning

Reputation: 15

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

Upvotes: -3

Adam Liu
Adam Liu

Reputation: 1346

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 ~.

Upvotes: -7

Mike Eshva
Mike Eshva

Reputation: 1160

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

Upvotes: 16

Klaus
Klaus

Reputation: 1191

COPY . <destination>

Which would be in your case:

COPY . /

Upvotes: 18

rayscott
rayscott

Reputation: 49

Replace the * with a /

So instead of

COPY * <destination>

use

COPY / <destination>

Upvotes: 0

Balasubramani M
Balasubramani M

Reputation: 8328

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.

Upvotes: 41

Related Questions