680

In a Dockerfile, I have

COPY . .

I want to exclude an entire directory, in my case, node_modules directory.

Something like this:

   COPY [all but **/node_modules/**] .

Is this possible with Docker?

6
  • 82
    How about .dockerignore ? Commented May 2, 2017 at 21:50
  • I am looking for answer to this related question: stackoverflow.com/questions/50547489/… Commented May 26, 2018 at 22:34
  • 4
    @AnthonySottile dockerignore prevents files being part of the build context. Commented Nov 26, 2021 at 15:55
  • 1
    i have .venv directory in the .dockerignore (.venv and **/.venv) and it still gets copied with COPY . . in dockerfile Commented Jul 21, 2022 at 23:16
  • 2
    My project has 50 directories, and takes around 20 minutes to compile. Part of the build script also includes other minor compilations at the end (executed by other scripts), which currently fail. I essentially only want to separate these two compilation processes and debug those extra scripts. Without writing 50+ COPY statements, specifying everything but these scripts. The key point here is wanting to cache the result of the first compilation. Commented Nov 7, 2022 at 2:29

11 Answers 11

990

Create file .dockerignore in your docker build context directory (so in this case, most likely a directory that is a parent to node_modules) with one line in it:

**/node_modules

although you probably just want:

node_modules

Info about dockerignore: https://docs.docker.com/engine/reference/builder/#dockerignore-file

Sign up to request clarification or add additional context in comments.

13 Comments

thanks, so the "COPY . ." command does not need to change, I guess
Just node_modules does not work in subdirectories.
This doesn't really solve the problem if you want to have it COPY'd but just not in that layer...
This answer is fundamentally wrong. .dockerignore prevents files being sent to the Docker server, thus excludes them from the build context. What would be useful instead is the ability to copy a folder excluding some of the content of that folder.
@PeterKionga-Kamau If that's the case, could you explain why the .dockerignore docs say "This helps to avoid unnecessarily sending large or sensitive files and directories to the daemon and potentially adding them to images using ADD or COPY." in the first paragraph?
|
173

For those who can't use a .dockerignore file (e.g. if you need the file in one COPY but not another):

Yes, but you need multiple COPY instructions. Specifically, you need a COPY for each letter in the filename you wish to exclude.

COPY [^n]*    # All files that don't start with 'n'
COPY n[^o]*   # All files that start with 'n', but not 'no'
COPY no[^d]*  # All files that start with 'no', but not 'nod'

Continuing until you have the full file name, or just the prefix you're reasonably sure won't have any other files.

5 Comments

This won't wort because you wil get a COPY failed: no source files were specified when there are no files starting with 'no', but not 'nod'.
Alternatively, you could use two different sub-directories (for different copy targets), so that e.g. in my nginx setup, I would have src/ will go to /var/www and /conf/nginx.conf go to /etc/nginx/conf.d/default.conf. Also, you could copy everything, and RUN rm -r conf later (too keep the source tree as it was). I would like to hear if someone has another suggestion.
What would be a solution for specific file types or file endings if I would do it like this?
The only downside of this approach is that your folder structure is flattened
If you have only few directories to be copied (say only '/app' or '/src'). A simpler way would be to copy directories individually (to keep their structure) and then you only need one COPY [^node_modules]* to copy all top level files.
75

Dockerfile 1.7.0 (Q1 2024) now supports an --exclude flag for ADD and COPY.
See PR moby/buildkit 4561 and the documentation on COPY [--exclude=<path>.

COPY --exclude

Will be included in docker/dockerfile:1.7-labs.

COPY [--exclude=<path> ...] <src> ... <dest>

The --exclude flag lets you specify a path expression for files to be excluded.

The path expression follows the same format as <src>, supporting wildcards and matching using Go's filepath.Match rules. For example, to add all files starting with "hom", excluding files with a .txt extension:

COPY --exclude=*.txt hom* /mydir/

You can specify the --exclude option multiple times for a COPY instruction. Multiple --excludes are files matching its patterns not to be copied, even if the files paths match the pattern specified in <src>. To add all files starting with "hom", excluding files with either .txt or .md extensions:

COPY --exclude=*.txt --exclude=*.md hom* /mydir/

As noted by BMitch in the comments

This needs a syntax line since it's experimental:

# syntax=docker.io/docker/dockerfile:1.7-labs

As noted by rrauenza in the comments:

The # syntax=docker.io/docker/dockerfile:1.7-labs line must be the FIRST line!
Even comments above will disable it.

4 Comments

This needs a syntax line since it's experimental: # syntax=docker.io/docker/dockerfile:1.7-labs
@PixnBits Thank you for your feedback. I have added that link to the answer.
Note: the # syntax=docker.io/docker/dockerfile:1.7-labs line must be the FIRST line! Even comments above will disable it.
@rrauenza Good point, thank you for this feedback. I have included your comment in the answer for more visibility.
17

Excluding node_modules from current directory

node_modules

Excluding node_modules in any immediate subdirectories

*/node_modules

Here is the official docs

8 Comments

You can do both with **/node_modules
@PeterKionga-Kamau They do have an effect. The ADD and COPY command are explicitly mentioned as being affected by dockerignore: docs.docker.com/engine/reference/builder/#dockerignore-file
@PeterKionga-Kamau Tried multiple times. Today I've re-verified with Docker v20.10.16 and any files that match .dockerignore entries are not picked up by COPY or ADD commands I've added to Dockerfile.
@PeterKionga-Kamau v20.10.16 was the most recent version as of May 16. I've just retried once more with a fresh dockerfile and all patterns/files I have in my .dockerignore are not picked up by to the COPY or ADD command. Do you have an example of when it did not work?
@PeterKionga-Kamau Here you go: github.com/leonluc-dev/dockerignoreexample After building and running the docker image, inspecting it should show that the entry in the dockerignore file (testfile1.txt in this case) was not copied to the docker image.
|
17

FOR A ONE LINER SOLUTION, type the following in Command prompt or Terminal at project root.

echo node_modules >> .dockerignore

This command appends "node_modules" in the .dockerignore file. If the .dockerignore does not exist already, it will create a new one. Replace node_modules with the folder you want to exclude.

Warning: If you are new to Docker ecosystem and/or you already have the .dockerignore file in your project, please take a backup before proceeding.

BONUS: (as pointed out by Joey Baruch)

(To CREATE/OVERWRITE the .dockerignore file via PowerShell, which can be handled by Docker):
>> echo node_modules | Out-File -Encoding UTF8 .dockerignore

11 Comments

Don't do this in PowerShell, it outputs UTF-16 by default, and I don't think docker can handle that
Do you really want people to lost their .dockerignore contents ? :) echo node_modules >> .dockerignore if so :)
I don't know why this answer has so many upvotes, when it's dangerous if people just copy-paste it in a project that already has a .dockerignore. Also, without explaining what's the functionality of the .dockerignore file, someone could think that this is a way of saying Docker to don't use that folder in the next build. Take into account you answer to people who doesn't usually know how Docker works.
@JoeyBaruch Thanks for mentioning it. I updated my answer for the PowerShell as well. :)
@NaveenKumarV Correction: if you use volume mapping, it will map everything in spite of anything you put the .dockerignore file. If you don't use volume mapping, then you can use .dockerignore to keep host files out of the image.
|
16

I used a multi stage build approach since I needed one stage to have access to the file but not another stage so .dockerignore wouldn't work:

FROM ruby AS builder

COPY app/ app/

# Do stuff with app

# remove the stuff you don't want
RUN rm -Rf app/assets

FROM ruby AS publish

# In my real version I needed the absolute path to builder WORKDIR.
# Since I'm copying from the builder stage, app/assets won't exist
# and neither will it be part of the publish image.
COPY --from=builder app app

8 Comments

this is wrong. app/assets is still in the image - though in a layer not visible.
@AndreasWittig, in a multi stage build only what you copy in the final stage is kept. In my example we have a builder stage which removes some files. Those files would still exist in a layer on the builder image but as you say, are no longer part of that layer. When we copy into the publish stage, since those files aren't visible they won't be included in the image from the publish stage.
I think this is the cleanest way for now. Lots of people just don't want to maintain two ignore files. (gitignore, dockerignore).
It's only clean with a multi stage build. Unless that, @AndreasWittig is right: the ignored files are still in a layer of the image.
@jtlz2, according to docs.docker.com/build/building/multi-stage, using a multistage build allows you to copy what you want from another stage and it discards the rest. There are two images built, the builder image has all the bloat but the publish images, which is the one you would deploy wouldn't have it since you are only copying what wasn't removed.
|
6

For those using gcloud build:

gcloud build ignores .dockerignore and looks instead for .gcloudignore

Use:

cp .dockerignore .gcloudignore

Source

2 Comments

are the file formats the same between the two?
"The syntax of .gcloudignore borrows heavily from that of .gitignore; see git-scm.com/docs/gitignore or man gitignore for a full reference" - cloud.google.com/sdk/gcloud/reference/topic/gcloudignore @edjm
5

I hit this problem recently, and there is good news on the horizon.

The COPY and ADD commands will soon have an --exclude option: see https://docs.docker.com/reference/dockerfile/#copy---exclude

COPY --exclude Note

Not yet available in stable syntax, use docker/dockerfile:1.7-labs version.

COPY [--exclude= ...] ... The --exclude flag lets you specify a path expression for files to be excluded.

As noted, it's not yet available in the stable release of the 1.7 syntax. However, adding this line

# syntax=docker/dockerfile:1.7-labs

at the top of your Dockerfile will make it available.

Comments

4

Adding .dockerignore works for me. One additional point Those who are trying this solution on Windows , windows will not let you create .dockerignore file (as it doesn't by default allows creating file starting with .)

To create such file starting with . on Windows, include an ending dot also, like : .dockerignore. and hit enter ( provided you have enabled view extension options from folder options )

1 Comment

You can create a file in windows that starts with a dot by also ending it with a dot.
4

.dockerignore is not always a solution as it applies only for build context dir.

A more generic solution is to pack outside dependencies to the build context in TAR archive and keep the context clean of garbage (like source files):

cd ~/my/ui-proj
npm run build
cd ~/my/oci-proj
tar -zcf ui.tar.gz --exclude=.git --exclude=node_modules -C ../ui-proj/out .
docker build --tag test .

and use the magic of ADD command which automatically extracts TAR archives:

RUN mkdir -p /work
WORKDIR /work
ADD my.tar.gz .

Comments

0

The best approach I found is to keep all your code inside src folder, so you Dockerfile is as easy as

COPY package*.json ./

RUN npm install

COPY ./src ./src

that will

a. help you with CI/CD later and testing because your tests are better to be stored in test dir and

b. you will not copy all other unnecessary files like Dockerfile, .git, etc. in your image

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.