You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
.dockerignore file is not honored by ImageFromDockerfile #1534
For Docker build performance, it can be very important for certain projects to have a .dockerignore file so that extra content is not sent to the Docker daemon (which may be on a different machine).
However, if I try an invalid .dockerignore in one of my Testcontainers projects, then it does not appeared to be honored. I was able to confirm this with the following steps:
Add invalid content in a .dockerignore file like this:
*~
[a-b-c]
Run docker build . and verify it fails
Run equivalent command through TC API and it passes (it should fail due to invalid syntax)
new ImageFromDockerfile()
.withFileFromPath(".", Paths.get(".")))
The problem here seems to be that we always call BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream) which doesn't set a Dockerfile in the docker-java layer. Setting an explicit Dockerfile is what causes the corresponding .dockerignore to be read.
To resolve this issue, we can call withDockerfile(File) on the underlying docker-java API
Hi, I'd like to work on this. Here's the approach I have in mind; feedback welcome before I open a PR.
Why the context isn't filtered today
Applying .dockerignore is the client's job: the Docker CLI filters the context before sending it, and the Engine builds whatever tar it receives. ImageFromDockerfile assembles and streams its own tar from the withFile* entries, so nothing ever reads the .dockerignore.
#1535 added withDockerfile(Path), following the suggestion above, which hands context assembly to docker-java and so applies .dockerignore. That works, but only when the Dockerfile sits at the root of the context directory, and mixing it with withFile* can hang on large contexts (#2771). It doesn't help the original repro, withFileFromPath(".", dir).
Proposal
Filter while writing the tar. Every entry passes through the loop in resolve(). Pass an include predicate to a new default method, Transferable.transferTo(tar, destination, include), which by default writes the entry only if its destination is included. Existing Transferables keep working unchanged.
Skip ignored files without reading them.MountableFile overrides that method so its recursive walk checks each relative path before opening a file or listing a directory, and skips an excluded directory entirely when no later ! rule could re-include something under it. This also keeps large ignored files from being streamed at all (see Huge MountableFiles result in OutOfMemoryError #1348).
Docker CLI semantics. Last matching rule wins, ! re-includes, **, comments, blank lines, path cleaning, and excluded directories exclude their contents. The Dockerfile and .dockerignore are still sent even when matched, as the CLI does. Invalid patterns fail the build with the same message docker-java uses today ("Invalid pattern '…' on line … in .dockerignore file"). Tests will be a table whose expected values come from moby/patternmatcher / docker build. Pattern matching reuses the shaded docker-java GoLangFileMatch (no new dependency), with that table pinning its behavior against Docker's.
Explicit API:withDockerignore(String rules) and withDockerignore(Path file). Rules are parsed in resolve(), so call order relative to withFile* doesn't matter.
Accurate reporting: the "Transferred … to Docker daemon" log and the 50 MB warning use the bytes actually written, not the sum of the transferables' sizes.
No rules, no change: without rules, the tar is identical to today's. withDockerfile(Path) is untouched.
Open question: auto-apply a .dockerignore already in the context?
If a .dockerignore is at the root of the assembled context (for example via withFileFromPath(".", dir)):
Behavior change: files sent today disappear; an invalid .dockerignore starts failing builds
B. Auto-apply with an opt-out (e.g. withDockerignore(false))
Docker semantics by default, escape hatch for anyone affected
One more method
C. Explicit API only
No behavior change
The #1534 repro still doesn't honor the file unless you opt in
My preference is B: the issue is labeled as a bug, users expect docker build semantics, and the opt-out covers the compatibility risk. Either way it deserves a mention in the release notes. Which do you prefer?
Dockerfile-specific ignore files (Dockerfile.dockerignore, a BuildKit feature).
The motivating case for me is a ~560 MB, ~3,000-file Gradle cache used as a build context, minus its lock files, which today needs hand-written filtering while adding files.
Activity
aguibert commentedon Jun 6, 2019
The problem here seems to be that we always call
BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream)which doesn't set a Dockerfile in the docker-java layer. Setting an explicit Dockerfile is what causes the corresponding.dockerignoreto be read.To resolve this issue, we can call
withDockerfile(File)on the underlying docker-java APIPentadome commentedon Dec 22, 2023
I have the same problem with dotnet testcontainers. Any workarounds?
sargue commentedon Aug 19, 2024
I'm also affected from this issue.
As this hasn't been resolved for several years now, does anyone know of a workaround?
Apart from the obvious one to not include everything and "manually" filtering out resources.
kiview commentedon Aug 19, 2024
I guess if someone wants to have a look at it, starting with the suggestion by @aguibert sounds promising: #1534 (comment)
DPUkyle commentedon Oct 15, 2026
Hi, I'd like to work on this. Here's the approach I have in mind; feedback welcome before I open a PR.
Why the context isn't filtered today
Applying
.dockerignoreis the client's job: the Docker CLI filters the context before sending it, and the Engine builds whatever tar it receives.ImageFromDockerfileassembles and streams its own tar from thewithFile*entries, so nothing ever reads the.dockerignore.#1535 added
withDockerfile(Path), following the suggestion above, which hands context assembly to docker-java and so applies.dockerignore. That works, but only when the Dockerfile sits at the root of the context directory, and mixing it withwithFile*can hang on large contexts (#2771). It doesn't help the original repro,withFileFromPath(".", dir).Proposal
resolve(). Pass an include predicate to a new default method,Transferable.transferTo(tar, destination, include), which by default writes the entry only if its destination is included. ExistingTransferables keep working unchanged.MountableFileoverrides that method so its recursive walk checks each relative path before opening a file or listing a directory, and skips an excluded directory entirely when no later!rule could re-include something under it. This also keeps large ignored files from being streamed at all (see Huge MountableFiles result in OutOfMemoryError #1348).!re-includes,**, comments, blank lines, path cleaning, and excluded directories exclude their contents. The Dockerfile and.dockerignoreare still sent even when matched, as the CLI does. Invalid patterns fail the build with the same message docker-java uses today ("Invalid pattern '…' on line … in .dockerignore file"). Tests will be a table whose expected values come frommoby/patternmatcher/docker build. Pattern matching reuses the shaded docker-javaGoLangFileMatch(no new dependency), with that table pinning its behavior against Docker's.withDockerignore(String rules)andwithDockerignore(Path file). Rules are parsed inresolve(), so call order relative towithFile*doesn't matter.withDockerfile(Path)is untouched.Open question: auto-apply a
.dockerignorealready in the context?If a
.dockerignoreis at the root of the assembled context (for example viawithFileFromPath(".", dir)):docker build; fixes #1534 as reported.dockerignorestarts failing buildswithDockerignore(false))My preference is B: the issue is labeled as a bug, users expect
docker buildsemantics, and the opt-out covers the compatibility risk. Either way it deserves a mention in the release notes. Which do you prefer?Out of scope
withDockerfile(Path)combined withwithFile*). With this change,withFileFromPath(".", dir)plus.dockerignorebecomes the recommended route, so ImageFromDockerfile#withDockerfile can't be used with any other withFile* methods #2771 matters less; a follow-up could address it.Dockerfile.dockerignore, a BuildKit feature).The motivating case for me is a ~560 MB, ~3,000-file Gradle cache used as a build context, minus its lock files, which today needs hand-written filtering while adding files.
Add a .dockerignore pattern matcher that follows the Docker CLI