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?
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
node_modules does not work in subdirectories..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?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.
COPY failed: no source files were specified when there are no files starting with 'no', but not 'nod'.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.COPY [^node_modules]* to copy all top level files.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
--excludeflag 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.txtextension:COPY --exclude=*.txt hom* /mydir/You can specify the
--excludeoption multiple times for aCOPYinstruction. Multiple--excludesare 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.txtor.mdextensions: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-labsline must be the FIRST line!
Even comments above will disable it.
# syntax=docker.io/docker/dockerfile:1.7-labs# syntax=docker.io/docker/dockerfile:1.7-labs line must be the FIRST line! Even comments above will disable it.Excluding node_modules from current directory
node_modules
Excluding node_modules in any immediate subdirectories
*/node_modules
Here is the official docs
**/node_modulesFOR 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
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
For those using gcloud build:
gcloud build ignores .dockerignore and looks instead for .gcloudignore
Use:
cp .dockerignore .gcloudignore
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.
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 )
.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 .
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
.dockerignore?