What's in your Docker image? "Dive" in to find out
Bob is asked to optimize Docker images for improving performance.
Docker Images are a great way to package software applications along with their libraries, tools, files, and other dependencies and run them as lightweight containers.
But the question is does it always remain lightweight?
In reality, a Docker image is made up of layers. and with every layer you add on, more space will be taken up by the image. Therefore, the more layers in the image, the more space the image will require.
Or you can say each line in the Dockerfile, (like a separate RUN instruction) adds a new layer to your image.
In case you want to know more about Dockerfiles and containerizing applications, give our post, Dockerising an application a read.
Why do we need smaller images? Here are a few reasons:
- Faster transfer & deployment in CI/CD server
- Less layers fewer chances for attackers to attack
So how can you ensure that Docker images occupy minimal space?
To analyze a Docker image we can use Dive. Dive is a tool by Alex Goodman. It is used for exploring a docker image, layer contents, and discovering ways to shrink the size of your Docker/OCI image.
What does Dive help us with?
- Breaks down the image contents in the Docker image layer by layer
- Shows the contents of each layer in details
- Shows the total size of the image
- Shows how much space was potentially wasted -> the lower the better & “this is that was want to reduce”
- Shows the efficiency score of the image -> the higher the better
How to install:
curl -OL https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.rpm rpm -i dive_0.9.2_linux_amd64.rpm
Available as dive in the Arch User Repository (AUR).
yay -S dive
The above example assumes
yay as the tool for installing AUR packages.
If you use Homebrew:
brew install dive
If you use MacPorts:
sudo port install dive
Or download the latest Darwin build from the releases page.
Download the latest release.
How to use Dive
To analyze a Docker image simply run dive with an image tag/id/digest:
$ dive <your-image-tag>
or if you want to build your image then jump straight into analyzing it:
$ dive build -t <some-tag> .
When you run the dive command on a docker file what you see is something like this on the terminal. In the below command we fetch the mongo:3.6 image file.
➜ ~ dive mongo:3.6
Image Source: docker://mongo:3.6
Fetching image... (this can take a while for large images)
Handler not available locally. Trying to pull 'mongo:3.6'...
In the left panel, we can see the layers of the given image. The selected layer is in purple color. You can move through the layers with up & down arrow keys. When you have selected a layer then the right panel shows all the files that are present in that layer.
The files are further shown in 3 colors.
green - New files
yellow - Edited files
red - Deleted files
In the above image, the second layer is selected and it shows the files newly added in green and modified files in yellow in the right pane
In the above image, the third layer is selected and it shows the files modified in yellow and files deleted in red in the right pane.
You can toggle between the options as shown at the bottom of the window
A few tips to keep your Docker images slim
- Use a small base image (Alpine) wherever possible.
Alpine image is only 5 MB in size and has access to a package repository that is much more complete than other BusyBox based images
- Use ".dockerignore"
Just the way you have .gitignore, Docker has a .dockerignore file. This excludes files that are not necessary for your image thus reducing the size of the image
- Use multi-stage builds
With multi-stage builds, you use multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artifacts from one stage to another, leaving behind everything you don’t want in the final image. To know more about multi-stage builds read our post on multistage-docker-builds.
- Avoid unnecessary layering.
Avoid unnecessary layering. Each RUN instruction in a Dockerfile adds a new layer to your image. Combining multiple RUN commands into one using && option helps in reducing the number of layers.
- Always use the latest versions of the platform whenever possible.
- To avoid unnecessary recommended packages and to use only the main dependencies add --no-install-recommends option to the install command
- Caching - It doesn’t affect the size of the image but definitely helps faster builds. Place instructions that are likely to change as low in the Dockerfile as possible.
Read More on Dive and related topics :