Overview
We could reduce the size of the image the generated Dockerfile produces by omitting useless gem files.
By default, the generated Dockerfile includes files that are not going to be needed in production:
- gem .c and .o files
- gem along tests and test data.
This is a waste of space. We can shave off some megabytes by deleting them.
Example
Create a new rails project and build it’s docker image (using the generated Dockerfile
):
> rails new blog
> docker build -t image1 .
> docker images image1
REPOSITORY TAG IMAGE ID CREATED SIZE
image1 latest 3123093e3c64 6 hours ago 566MB
If we update the generated Dockerfile from:
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
to
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
# remove unneeded files (cached *.gem, *.o, *.c) (as per https://ledermann.dev/blog/2018/04/19/dockerize-rails-the-lean-way/)
find "${BUNDLE_PATH}"/ruby/3.3.0/gems/ -name "*.c" -delete && \
find "${BUNDLE_PATH}"/ruby/3.3.0/gems/ -name "*.o" -delete && \
# delete the test and spec directories from all the gems
find "${BUNDLE_PATH}"/ruby/3.3.0/gems/ -mindepth 2 -maxdepth 2 -type d \( -name spec -o -name test \) -exec rm -rf {} + && \
bundle exec bootsnap precompile --gemfile
> docker images image2
REPOSITORY TAG IMAGE ID CREATED SIZE
image2 latest 2974a492e5c3 19 seconds ago 563MB
This reduces the image size by 3Mb. It’s not much, but it will increase as more dependencies with more tests are introduces. Some dependencies may have fixtures and test files that could increase the size by a lot.
If others feel it’s a good tradeoff (added complexity vs reduced docker image size), I could open a PR for review, or an issue over at Github.
System configuration
Rails version: 8.0.1
Ruby version: ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [arm64-darwin24]