To decide what files to include or exclude for Docker deployments, we honor
.dockerignoreif present, or fall back to
Until today, we treated these two files as if they had the same semantics. As of Now 11.1.15, however, we now feature full support for the
.dockerignorespecification, which introduces the ability to use it as a whitelist.
We are also introducing a new package on npm:
@zeit/dockerignorewhich makes the newly implemented filtering logic available for everyone to reuse.
On the surface, both files allow for defining what paths are not part of your stage. In other words, most people use them as blacklists. Some differences start to emerge when you start using capabilities that allow to turn them into whitelists, which is a pattern we have begun to use at ZEIT for all our Docker containers.
Here's an example of a
.dockerignorefile using this technique. Instead of serving as a blacklist of things to ignore, we ignore everything by default and only whitelist the precise requirements we need for our project.
* !include !these/things
All files are ignored, except for the ones starting with
Consider the many files in your project that exist but aren't important for building or executing your project:
.dockerignorefiles themselves, etc. Perhaps without realizing it, every time you invoke
docker build, these files are being unnecessarily uploaded to the build stage (a process that can be particularly slow when using Docker for Mac).
There are a few differences between how the same definition above works with
.gitignorematches everything, whereas in
.dockerignoreit only matches things in the current directory (like glob). This difference is important when whitelisting after a * rule.
includein .gitignore matches all
includefiles and directories, however deeply nested. In .dockerignore however,
includespecifically matches on
./includebut does not match nested files/directories like
.gitignore, when a parent directory is ignored, subdirectories (like
these/things) cannot be re-added (using
gitsimply avoids walking through the subtree as an optimization, whereas with
.dockerignorea subdirectory can be re-added even if a parent directory has been ignored.
- For a complete list of differences, check out the gitignore spec and the dockerignore spec.
We forked the existing ignore package and added a few test cases for the changes we made. We also implemented a test suite such that, when run in CI, we make real
docker builds with the test case's
.dockerignoreand compare our output to what
After implementing the comprehensive test suite, the differences between the 2 specs became clear and it was evident that we had to rewrite parts of the parsing logic. In doing so, we ended up making the parser logic much simpler and also ended up mimicking
docker's existing logic to do the same.
The API is the same as
ignore(Check the README for examples and documentation).
To learn more, here are some helpful links:
Having a robust
.dockerignoreparser is important as we continue to focus on Serverless Docker Deployments that are extremely quick to spin up and scale.
As an example, using the whitelisting technique we outlined above will help you avoid deploying images that include unnecessary artifacts or inadvertently grow in size over time. Not to mention the security benefits associated with preventing accidental leaks.