Using .dockerignore files to build better Docker images
Purpose
The purpose of this post is to learn how to use .dockerignore file in order to build smaller and more secure Docker images. These are some possible scenarios:
- Docker daemon is on a remote machine and sending the build context is too slow.
- We don’t want to build an image with passwords in it and Docker should ignore them.
- Build smaller Docker images: Log files and other non-application related files are too heavy making the Docker image size too big.
- See how Docker ignore files and folders that you don’t really want in the final Docker image.
Without using a .dockerignore file
Folder structure example:
$ tree -a
.
├── Dockerfile
├── logs
│ └── example.log
├── MY_SECRET_PASSWORDS.txt
└── src
└── app.py
Dockerfile:
FROM alpine:3.7
ADD . /var/opt/
CMD sleep infinity
Command to build the image:
$ docker build -t testing .
Get current image size:
$ docker images | grep testing
testing latest 5f1dbed20708 2 seconds ago 154MB
Container content in /var/opt/:
$ docker run -it testing ls -la /var/opt
total 24
drwxr-xr-x 4 root root 4096 Apr 25 05:45 .
drwxr-xr-x 12 root root 4096 Apr 25 05:45 ..
-rw-rw-r-- 1 root root 52 Apr 25 05:30 Dockerfile
-rw-rw-r-- 1 root root 0 Apr 25 05:27 MY_SECRET_PASSWORDS.txt
-rw-rw-r-- 1 root root 8 Apr 25 05:39 dockerignore
drwxrwxr-x 2 root root 4096 Apr 25 05:27 logs
drwxrwxr-x 2 root root 4096 Apr 25 05:31 src
Using a .dockerignore file
We want to reduce the Docker image size preventing to upload 150MB of logs and avoiding to upload passwords (or other unnecessary files) to build a more secure artifact.
touch .dockerignore
.dockerignore example file, preventing to upload logs, passwords and .dockerignore itself:
logs/
MY_SECRET_PASSWORDS.txt
.dockerignore
We can use UNIX glob patterns in a Docker ignore file. For example to ignore all files starting by
bkp*
, ending with*.md
or ignore all compiled Python files in all folders recursively**/*.pyc
.
Result:
$ docker build -t testing .
$ docker run -it testing ls -la /var/opt
total 16
drwxr-xr-x 3 root root 4096 Apr 25 05:35 .
drwxr-xr-x 12 root root 4096 Apr 25 05:35 ..
-rw-rw-r-- 1 root root 52 Apr 25 05:30 Dockerfile
drwxrwxr-x 2 root root 4096 Apr 25 05:31 src
But we can do a better .dockerignore file disallowing everything and just allowing src folder. Dockerfile example:
$ cat .dockerignore
**
!src
Container content in /var/opt:
$ docker build -t testing .
$ docker run -it testing ls -la /var/opt
total 12
drwxr-xr-x 3 root root 4096 Apr 25 05:39 .
drwxr-xr-x 12 root root 4096 Apr 25 05:39 ..
drwxrwxr-x 2 root root 4096 Apr 25 05:31 src
Final image size:
$ docker images | grep testing
testing latest b14a907cb76d 12 minutes ago 4.15MB
More info about .dockerignore syntax here: https://docs.docker.com/engine/reference/builder/#dockerignore-file
Bonus track: .dockerignore is not .gitignore
.dockerignore should be placed in the root of the Docker context, otherwise doesn’t work because Docker doesn’t allow us to have multiple recursive .dockerignore files:
https://github.com/moby/moby/issues/20944
Using previous example command:
$ docker build -t testing .
.dockerignore must be in the current folder . like ./dockerignore
If you have a Dockerfile in a subfolder for example ./build/Dockerfile you can still build the image specifying where is the Dockerfile and which is the context:
$ docker build -t testing -f build/Dockerfile .
As you can see .dockerignore should be placed in ./dockerignore, never in build/.dockerignore.
Finally, you should definitely take a look at these books to fuel your Docker knowledge:
DevOps books:
Cloud providers:
DigitalOcean offers affordable pricing for VMs and many other public cloud services. You can sign up for DigitalOcean and receive a $100 free credit using this referral link.