Skip to content

.dockerignore file is not honored by ImageFromDockerfile #1534

Open

Description

@aguibert

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

It appears that the underlying docker-java API does support .dockerignore files:
https://github.com/docker-java/docker-java/blob/master/src/test/java/com/github/dockerjava/cmd/BuildImageCmdIT.java#L176

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:

  1. Add invalid content in a .dockerignore file like this:
*~
[a-b-c]
  1. Run docker build . and verify it fails
  2. Run equivalent command through TC API and it passes (it should fail due to invalid syntax)
new ImageFromDockerfile()
                        .withFileFromPath(".", Paths.get(".")))

Activity

  1. aguibert commented on Jun 6, 2019

    @aguibert
    ContributorAuthor

    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

  2. Pentadome commented on Dec 22, 2023

    @Pentadome

    I have the same problem with dotnet testcontainers. Any workarounds?

  3. sargue commented on Aug 19, 2024

    @sargue

    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.

  4. kiview commented on Aug 19, 2024

    @kiview
    Member

    I guess if someone wants to have a look at it, starting with the suggestion by @aguibert sounds promising: #1534 (comment)

  5. DPUkyle commented on Oct 15, 2026

    @DPUkyle

    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

    1. 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.
    2. 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).
    3. 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.
    4. Explicit API: withDockerignore(String rules) and withDockerignore(Path file). Rules are parsed in resolve(), so call order relative to withFile* doesn't matter.
    5. 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.
    6. 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)):

    Option Pros Cons
    A. Auto-apply Matches docker build; fixes #1534 as reported 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?

    Out of scope

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions