How to reduce the size of RHEL/Centos/Fedora Docker image
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
RHEL, CentOS, and Fedora images can become large quickly because package managers, metadata, docs, and build tooling all add layers and files. The most effective way to reduce size is to combine a smaller base image with disciplined package installation and multi-stage builds. The goal is not just a smaller download, but a cleaner runtime image with fewer unnecessary components.
Start From the Smallest Reasonable Base
The easiest size win is choosing the right base image. If you only need a minimal runtime, use one of the reduced variants instead of a full distribution image.
Typical options include:
- '
registry.access.redhat.com/ubi9/ubi-minimal' - '
registry.access.redhat.com/ubi9/ubi-micro' - '
fedora-minimal'
For example:
Using a smaller base matters more than almost any later micro-optimization.
Install Only What the Runtime Actually Needs
A common mistake is leaving compilers, development headers, and debugging tools in the final image. If the container only runs an already-built app, the runtime image should usually contain just:
- the app binary or source needed at runtime
- the runtime libraries
- configuration or certificates that the app actually uses
Avoid installing package groups or generic utility bundles unless they are genuinely required.
Clean Package Metadata in the Same Layer
Package managers leave caches and metadata behind unless you remove them. On minimal Fedora or UBI images, that usually means cleaning in the same RUN instruction.
Doing the cleanup in a later layer does not help much, because the earlier layer still contains the original files.
Use Multi-Stage Builds
If you compile code inside the image, build it in one stage and copy only the result into a smaller runtime stage.
This pattern avoids shipping the compiler, package manager metadata, and source tree in the final image.
Combine Related Commands Carefully
Every RUN instruction creates a layer. Combining related package installation and cleanup steps reduces wasted layers.
That said, readability still matters. Do not collapse unrelated logic into one unreadable line just to save a tiny amount of space.
Avoid Copying More Than Necessary
Large build contexts often bloat images more than the base OS does. Use a .dockerignore file to exclude things such as:
- '
.git' - local caches
- test data
- node_modules created on the host
- build artifacts that will be regenerated
Example .dockerignore:
This reduces both build time and image size.
Consider UBI Micro for Strict Runtime Images
If you do not need a shell or package manager in the final container, ubi-micro can be a strong option. It is much smaller, but that also means debugging inside the container becomes harder. That tradeoff is often worth it for production runtime images where repeatable builds matter more than interactive troubleshooting.
Measure the Result
Optimization should be verified, not guessed. Useful commands include:
docker history helps identify unexpectedly large layers. It often reveals that one COPY or one package install step dominates the final size.
Common Pitfalls
The biggest mistake is starting from a full distribution image when a minimal variant would work. Another is installing build dependencies into the final runtime stage. Developers also clean package caches in a later layer, which does not remove the bytes from earlier layers. Copying the entire repository into the image without a .dockerignore file is another common source of bloat. Finally, shrinking the image too aggressively can remove tools that the app truly needs, so size reduction still has to respect runtime correctness.
Summary
- Pick a minimal base image such as
ubi-minimal,ubi-micro, orfedora-minimalwhen possible. - Install only the packages needed at runtime.
- Clean package metadata in the same
RUNlayer as installation. - Use multi-stage builds to keep compilers and build tools out of the final image.
- Keep the build context small with a good
.dockerignore. - Measure size changes with
docker imagesanddocker history.

