Please note DockerSlim cannot be used with Red Hat Enterprise Linux. Red Hat does not support DockerSlim with Podman and no longer provides Docker in RHEL or Red Hat OpenShift.
Containers are a great way to package your applications. Packaging your application codebase together with its dependencies creates a container image. The smaller the container image is, the faster your application will spin up for the first time, and the faster it will scale. But many container images are quite large, in the hundreds of megabytes—just search Docker Hub and prepare to be amazed at the image sizes.
In this article, you'll learn how to optimize Docker container images for size using a project called DockerSlim. DockerSlim, which is open sourced under the Apache 2.0 license, won't change anything in your container image, but can still reduce its size—or minify it—by up to a factor of 30. For applications written in compiled languages, the size reduction can be even more dramatic. DockerSlim also makes your packages more secure by reducing the available attack surface.
Using DockerSlim
DockerSlim uses various techniques to optimize and secure container images. For one, it disposes of packages and files from the container image that your application does not need to serve the business logic. Removing additional files helps to reduce the container's attack surface. Using DockerSlim is a simple two-step process.
Step 1: Install DockerSlim
The installation steps for DockerSlim are explained in the DockerSlim GitHub repository. Here's how you would install DockerSlim on macOS using brew
:
brew install docker-slim
Step 2: Minify your Docker image
Once you have DockerSlim installed, you can use it to minify your Docker image by running docker-slim
against existing container images. Start by running docker images
to list the container images currently available:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-hello-world-ubi latest 50c12e1ca549 13 days ago 169MB
Next, run docker-slim build
against an existing container image to minify it:
$ docker-slim build python-hello-world-ubi
docker-slim: message='join the Gitter channel to ask questions or to share your feedback' info='https://gitter.im/docker-slim/community'
docker-slim: message='join the Discord server to ask questions or to share your feedback' info='https://discord.gg/9tDyxYS'
docker-slim: message='Github discussions' info='https://github.com/docker-slim/docker-slim/discussions'
cmd=build info=param.http.probe message='using default probe'
cmd=build state=started
cmd=build info=params rt.as.user='true' keep.perms='true' tags='python-hello-world-ubi.slim ' target.type='image' target='python-hello-world-ubi' continue.mode='probe'
cmd=build state=image.inspection.start
...
...
...
cmd=build state=done
cmd=build info=commands message='use the xray command to learn more about the optimize image'
...
...
docker-slim
will generate an optimized image from your source image and store that with a .slim
file extension:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-hello-world-ubi latest 50c12e1ca549 13 days ago 169MB
python-hello-world-ubi.slim latest 17ba0fab2e4e 13 days ago 25.8MB
In this case, the original image is 169MB, and the newly optimized image is 25.8MB—a 600 percent reduction in size.
Get a DockerSlim container report
If you're curious, you can use the docker-slim xray
command to get the details about a package's size. The command performs a static analysis on the target container image and reverse-engineers the Dockerfile from the image, telling you what's inside of your container image and why it is so big:
$ docker-slim xray python-hello-world-ubi
The xray
option on docker-slim
generates a slim.report.json
file that includes all the details on your container image and provides a great resource for investigating what's inside of it. Here is partial output from an example file:
...
...
cmd=xray info=image id='sha256:50c12e1ca549655293c8148359bf80d551cec739c34556d4506f49602f9ea203' size.bytes='168702969' size.human='169 MB'
cmd=xray info=image.stack index='0' name='python-hello-world-ubi:latest' id='sha256:50c12e1ca549655293c8148359bf80d551cec739c34556d4506f49602f9ea203' instructions='8' message='see report file for details'
...
...
cmd=xray info=layer.objects.top.start
A: mode=-rw-r--r-- size.human='6.9 MB' size.bytes=6949250 uid=0 gid=0 mtime='2021-03-05T16:50:01Z' H=[A:0] '/usr/lib/locale/C.utf8/LC_COLLATE'
A: mode=-rw-r--r-- size.human='5.2 MB' size.bytes=5194744 uid=0 gid=0 mtime='2021-01-29T16:23:30Z' H=[A:0] '/usr/share/misc/magic.mgc'
A: mode=-rw-r--r-- size.human='4.8 MB' size.bytes=4837376 uid=0 gid=0 mtime='2021-09-14T16:20:29Z' H=[A:0/M:2] '/var/lib/rpm/Packages'
A: mode=-rwxr-xr-x size.human='3.2 MB' size.bytes=3167976 uid=0 gid=0 mtime='2021-03-05T17:03:03Z' H=[A:0] '/usr/lib64/libc-2.28.so'
A: mode=-rwxr-xr-x size.human='3.1 MB' size.bytes=3071456 uid=0 gid=0 mtime='2021-03-25T16:49:50Z' H=[A:0] '/usr/lib64/libcrypto.so.1.1.1g'
A: mode=-rwxr-xr-x size.human='2.2 MB' size.bytes=2191840 uid=0 gid=0 mtime='2021-03-05T17:03:04Z' H=[A:0] '/usr/lib64/libm-2.28.so'
A: mode=-rwxr-xr-x size.human='2.1 MB' size.bytes=2052344 uid=0 gid=0 mtime='2021-04-01T13:15:58Z' H=[A:0] '/usr/lib64/libgnutls.so.30.28.0'
A: mode=-rwxr-xr-x size.human='2.0 MB' size.bytes=1975976 uid=0 gid=0 mtime='2021-03-08T15:43:28Z' H=[A:0] '/usr/lib64/libdnf.so.2'
A: mode=-rwxr-xr-x size.human='1.9 MB' size.bytes=1869272 uid=0 gid=0 mtime='2021-09-09T06:45:53Z' H=[A:0] '/usr/lib64/libdb-5.3.so'
A: mode=-rwxr-xr-x size.human='1.8 MB' size.bytes=1770160 uid=0 gid=0 mtime='2021-07-26T13:46:03Z' H=[A:0] '/usr/lib64/libgio-2.0.so.0.5600.4'
A: mode=-rwxr-xr-x size.human='1.8 MB' size.bytes=1760264 uid=0 gid=0 mtime='2018-08-17T20:47:18Z' H=[A:0] '/usr/lib64/libunistring.so.2.1.0'
A: mode=-rwxr-xr-x size.human='1.7 MB' size.bytes=1661376 uid=0 gid=0 mtime='2020-09-29T22:13:10Z' H=[A:0] '/usr/lib64/libstdc++.so.6.0.25'
A: mode=-rwxr-xr-x size.human='1.5 MB' size.bytes=1503528 uid=0 gid=0 mtime='2021-05-19T08:14:20Z' H=[A:0] '/usr/lib64/libxml2.so.2.9.7'
A: mode=-rwxr-xr-x size.human='1.5 MB' size.bytes=1503456 uid=0 gid=0 mtime='2019-06-14T08:41:36Z' H=[A:0] '/usr/lib64/libgmp.so.10.3.2'
A: mode=-rwxr-xr-x size.human='1.4 MB' size.bytes=1367288 uid=0 gid=0 mtime='2021-07-28T11:56:34Z' H=[A:0] '/usr/lib64/libsystemd.so.0.23.0'
A: mode=-rwxr-xr-x size.human='1.3 MB' size.bytes=1321808 uid=0 gid=0 mtime='2021-03-05T17:03:06Z' H=[A:0] '/usr/sbin/ldconfig'
A: mode=-rwxr-xr-x size.human='1.3 MB' size.bytes=1304120 uid=0 gid=0 mtime='2020-04-14T12:13:07Z' H=[A:0] '/usr/bin/coreutils'
A: mode=-rwxr-xr-x size.human='1.2 MB' size.bytes=1246520 uid=0 gid=0 mtime='2021-01-11T13:56:24Z' H=[A:0] '/usr/lib64/libp11-kit.so.0.3.0'
A: mode=-rwxr-xr-x size.human='1.2 MB' size.bytes=1188080 uid=0 gid=0 mtime='2020-06-15T16:21:33Z' H=[A:0] '/usr/lib64/libgcrypt.so.20.2.5'
A: mode=-rwxr-xr-x size.human='1.2 MB' size.bytes=1167784 uid=0 gid=0 mtime='2021-07-26T13:46:03Z' H=[A:0] '/usr/lib64/libglib-2.0.so.0.5600.4'
cmd=xray info=layer.objects.top.end
cmd=xray info=layer.end
...
...
Conclusion
Bloated container images can negatively impact application performance. If you suspect your container image is getting too big, after reading this article you should know how to use DockerSlim to minify it. It's a nice addition to your toolbox.
Please note DockerSlim cannot be used with Red Hat Enterprise Linux. Red Hat does not support DockerSlim with Podman and no longer provides Docker in RHEL or Red Hat OpenShift.
Last updated: September 20, 2023