Slimming a Rails Application with DockerSlim

Dissect a simple Rails application container using DockerSlim to analyze, optimize, and deploy your product more quickly.
Theofanis Despoudis
Mar 15, 2022

Photo by Alex wong on Unsplash

One of the best ways to improve the build times of container images is to analyze the final image and trim off unwanted and unnecessary files. Traditionally, this process is performed with a .dockerignore file by combining RUN commands and squashing layers.

Sometimes, however, you don’t want to change anything in your Docker container image (or Dockerfile instructions), but you do want to minify it more intelligently. In that case, you want to use DockerSlim

In this tutorial, we will explore some practical ways to slim a container using DockerSlim. DockerSlim is like a Swiss Army knife for dissecting container internals, and the insights that it provides enable you to analyze, optimize, and deploy your product quickly. We will start by showing you how to containerize a simple Rails application. Then, we’ll include extra files and directories while handling the rest of the final build. Finally, we will introduce you to some additional options for slimming containers.

Let’s get started.

Slimming a Simple Rails Application Container

DockerSlim is very versatile. It can be used in containers running Node.js, Python, Ruby, Java, Golang, Rust, Elixir, or PHP on Ubuntu, Debian, CentOS, Alpine, or even Distroless. In this tutorial, we will show you how to slim a simple Rails application.

First, you need to create a new Rails app. We’ll use the following command:

$ env RBENV_VERSION=2.7.4 rbenv exec rails new /Users/theo.despoudis/Workspace/hello-world --webpack=react --skip --database=postgresql

We also specified a Ruby and Rails version to use and created a new React + Rails app with Postgres database provider.

Next, you need to delete and then create an empty Gemfile.lock: (This will fix issues when you run the bundler install command inside the container.)

    $ cd hello-world
    $ rm Gemfile.lock
    $ touch Gemfile.lock

Then, create a Dockerfile that uses the official Ruby image to install Rails dependencies:


    # syntax=docker/dockerfile:1
    FROM ruby:2.7.4
    RUN curl -sS | apt-key add -
    RUN echo "deb stable main" | tee
    RUN apt-get update -qq && apt-get install -y nodejs postgresql-client yarn
    WORKDIR /myapp
    COPY . /myapp/
    COPY Gemfile /myapp/Gemfile
    COPY Gemfile.lock /myapp/Gemfile.lock
    RUN bundle install

    EXPOSE 3000
    ENTRYPOINT ["./scripts/"]

We used the following starting script:


    set -e

    bundle exec puma -C config/puma.rb

Now, build the image:

    $ docker build -t app .

Use the official Postgres image to provision the database:

    $ docker run --name postgresql-container -p 5432:5432 -e
    POSTGRES_PASSWORD=somePassword -d postgres

    $ psql --u postgres -h
    Password for user postgres:
    psql (13.4, server 14.1 (Debian 14.1-1.pgdg110+1))
    WARNING: psql major version 13, server major version 14.
        Some psql features might not work.
    Type "help" for help.
    postgres=# create database hello_world_development
    postgres=# exit;

Then, run the application to verify that it works:

    $ docker run -e
    "DATABASE_URL=postgres://postgres:somePassword@" -p 3000:3000 app

Using docker inspect, you can see that the image takes up 1.1GB of storage:

    $ docker inspect app | jq '.[] | .Size' | numfmt --to iec --format "%8.4f"

Now you can use DockerSlim to reduce the image size. For this tutorial, we will use the official Docker image to run the experiments. First, you need to pull the latest image:

    $ docker pull dslim/docker-slim

Then, run the build command to slim the container image down in just one step:

    $ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock dslim/docker-slim build app --http-probe=false

We disabled http-probing using the --http-probe=false flag because we just wanted to minify the image without probing the live container. Later on, we will enable http-probe with the --continue-after flag to continue executing the build command. This will help us control the completion of the build.

Now you can use the newly created image to inspect your cost savings:

    $ docker inspect app.slim | jq '.[] | .Size' | numfmt --to iec --format "%8.4f"

Wow! Now it's only 80MB total!

You can also run the application in the container to verify that it works:

    $ docker run -e "DATABASE_URL=postgres://postgres:somePassword@" -p 3000:3000 app.slim
      ! Unable to load application: LoadError: cannot load such file -- zlib

Oops! It looks like we need to enable the http-probe in this case, since the Rails application lazy-loads native modules like zlib and the Postgres shared libraries at runtime. Not all applications behave this way, but some (such as Rails and Django) do. The DockerSlim tool does not know this unless it probes the application to verify that it is up and running and that all of its runtime modules were loaded properly. If a module was not loaded, DockerSlim can remove it from the final build.

Now, you need to run the full-fledged build command to make it work with Rails:

    $ docker run -e "DATABASE_URL=postgres://postgres:somePassword@" -it --rm -v /var/run/docker.sock:/var/run/docker.sock dslim/docker-slim build app
    cmd=build state=http.probe.starting message=WAIT FOR HTTP PROBE TO
    cmd=build info=http.probe.summary total='2' failures='1'

In the above command, DockerSlim created a temp container and probed the containerized application so that it knows which essential modules to keep in the final image. You can inspect the size again at this point (notice that it’s just a few MB larger):

    $ docker inspect app.slim | jq '.[] | .Size' | numfmt --to iec --format "%8.4f"

Now, run the slimmed image:

    $ docker run -e "DATABASE_URL=postgres://postgres:somePassword@" -p 3000:3000 app.slim

Figure 1: Rails App Running in a Minified Image

It works!

Now that you know the basics of DockerSlim and HTTP probes, we’ll explain how to control the execution of the build command using the --continue-after flag.

Controlling When to Finish Executing the Build Command

HTTP probes give DockerSlim the ability to detect lazy loaded modules that are required for the application at runtime. There are various flags that can control its behavior, including:

  • --http-probe-retry-count: This controls the number of retries for each HTTP probe. If you want to make sure that the probe will hit a valid endpoint after a certain period of time, give this a higher number and control the wait period with the --http-probe-retry-wait flag.
  • --http-probe-ports: This allows you to specify a list of ports to probe. By default, DockerSlim will use the EXPOSE ports as defined in the DockerFile image.
  • --http-probe-apispec: This runs a probe for an API specification like Swagger, which improves discoverability of endpoints and resources.

Although these flags are useful, it takes a lot of time to figure them out, which is particularly inefficient when you are still developing the application or when you want to test specific scenarios. If you want to have better control over when the build process completes, you can just manually send a keystroke or a signal to finish building the image with the --continue-after flag.

Let’s run the previous build command with the --continue-after flag:

    $ docker run -e
            "DATABASE_URL=postgres://postgres:somePassword@" -it --rm -v
            /var/run/docker.sock:/var/run/docker.sock dslim/docker-slim build
            --copy-meta-artifacts . --continue-after=enter app

    cmd=build info=continue.after message='provide the expected input to
    allow the container inspector to continue its execution' mode='enter'

(You will be able to review the info message describing the procedure.) It will start probing the endpoints as specified, but now it will wait for a trigger to complete. We used the enter flag in this case, which means that we have to press the enter key to continue. If you’ve been following along, press it now to see the build process finish:

    cmd=build state=container.inspection.finishing

The --continue-after flag allows for different combinations of flags out of enter | signal | probe | exec | timeout-number-in-seconds | container.probe.

You can emit an OS signal from the command line, for example, or wait for an executable to finish or a specified timeout (in seconds) to be reached. In this way, you will gain finer control over the build process and the accuracy of the minification. In practice, you will find that you must use flags very efficiently to deliver the most optimized image using DockerSlim. Next, we will show you how to include extra files in the finished image.

Including Extra Files and Directories in Your Minified Image

Sometimes your application container needs to contain specific files, directories, executables, or binary images in the final form. If DockerSlim trims them from the final build as part of the minification process for some reason, you’ll want to put them back. For example, it might remove erb templates or migrations folders if it detects that are unused.

For that, DockerSlim offers an extensive list of flags to control which resources should be included. For example, it offers the following –include-* flags:

  • --include-path: This includes all contents of the specified folder path into the final image. For instance, to include the migrations folder in our example, you would run:
    $ docker run -e
            "DATABASE_URL=postgres://postgres:somePassword@" -it
            \--rm -v /var/run/docker.sock:/var/run/docker.sock
            dslim/docker-slim build --include-path /myapp/db/migrate app
  • --include-path-file: This includes a specific file into the final image.
  • --include-bin: This includes a specific binary into the final image. DockerSlim will check its dependencies and include them into the final build.
  • --include-exe: This includes a specific executable into the final image. DockerSlim will check its dependencies and include them into the final build.
  • --include-cert-all: This will try to keep any certificates installed in the image. For example, it will use detectors to copy certificates from known locations. If you’re using an Ubuntu image, it will copy them from the /etc/ssl/certs folder.

External modules or shared libraries that the application needs (such as elastic search modules or a Postgres shared library that must be loaded) are examples of included files. DockerSlim might not always deem them necessary when you include them in the Dockerfile, so it might filter them out from the final image.

Other Useful Flags

You can also try experimenting with the following flags:

  • --http-probe-crawl: This will transform your HTTP probe into a web crawler that will follow all the links it finds in the target endpoint.
  • --pull: This pulls an image from a registry instead of the local image list.
  • --new-entrypoint, --new-cmd, --new-expose, --new-workdir, --new-env, --new-label, and --new-volume: Each one of these flags lets you customize the DockerFile’s respective instructions (entrypoint, cmd, expose, workdir, env, label, and volume).

Moreover, you can also specify the container runtime (via the --cro-runtime flag) or any step of the Docker build process. This fine-grained control is extremely valuable, making DockerSlim a must-use tool for modern teams using containers in production.

Next Steps with DockerSlim

DockerSlim offers many other flags and tools for inspecting, optimizing, and refining container images. You can start by reviewing some of the Slim.AI tutorials, as they are the main providers of DockerSlim and have deep knowledge of container development and optimization. You should also review DockerSlim’s official README, since it is essentially a reference guide for the tool. Finally, you can join the Slim SaaS Early Access program to analyze thousands of public container images or scan your own using the online panel.

About the Author

Theo Despoudis is a Senior Software Engineer, a consultant and an experienced mentor. He has a keen interest in Open Source software Architectures, Cloud Computing, best practices and functional programming. He occasionally blogs on several publishing platforms and enjoys creating projects from inspiration. Follow him on Twitter @nerdokto.

Related Articles

5 Most Commonly Asked DockerSlim Questions

We enlisted DockerSlim expert and Slim.AI Developer Experience Engineer to dive into how container slimming works.

Primož Ajdišek

Technical Staff

Automatically reduce Docker container size using DockerSlim

REST Web Service example using Python/Flask

John Amaral


Automating DockerSlim in Your CICD Pipeline

Using GitHub Actions, you can refine container images automatically making them smaller, faster to load, and more secure by default – all without sacrificing any capabilities.

Nicolas Bohorquez


Building DockerSlim into a Jenkins Pipeline

A step by step tutorial on building DockerSlim into your CI/CD pipeline.

Comparing Container Versions with DockerSlim and Slim.AI

See differences between your original and slimmed images

Pieter van Noordennen


Explore and analyze a Docker container with DockerSlim X-Ray

Understanding container composition

Martin Wimpress


In the Media: DockerSlim and Slim.AI

Latest Mentions

Slim.AI and OSI: Why We Advocate for Open Source

Slim.AI continues its support of OSI and sponsors the OSI licensing API as a part of its ongoing advocacy for open source

Pieter van Noordennen


The DockerSlim Origin Story

How DockerSlim got its start at Docker's Global Hack Day, and the creation of Slim.AI.

Kyle Quest


What DockerSlim Users Get Out of Slim's SaaS Platform

Scaling Your Container Game

Martin Wimpress


5 Ways Slim Containers Save You Money

Do slim containers really save you money on your cloud bill? Are there cost advantages to smaller containers? Find out here.

Chris Tozzi

Building Apps Using Cloud Native Buildpacks

Getting started with this innovative technique

Vince Power


Clarifying the Complex: Meet Ivan Velichko, Container Dude at Slim.AI

Ivan recently joined the team at Slim.AI, and we sat down with him to learn more about the path that led him here.

Ivan Velichko

Container Dude

Container Insights: Dissecting the World's Most Popular Containers

Join Ayse Kaya in this series, as she creates her 2022 Container Report Chalk Full of Important Security Findings for Developers.

Ayse Kaya

Analytics & Strategy

Container of the Week: Python & Flask

Our weekly breakdown of a popular container

What We Discovered Analyzing the Top 100 Public Container Images

Complexity abounds in modern development

Ayse Kaya

Analytics & Strategy

2022 Public Container Report

Vulnerabilities continue to increase and developers are struggling to keep up.

Ayse Kaya

Analytics & Strategy

Containerizing Python Apps for Lambda

A tutorial on deploying AWS Lambda using containers, Python edition.

Docker Containers for Your Raspberry Pi

Compact PCs need compact apps

Martin Wimpress


Five Proven Ways to Debug a Container

When Things Just Are Not Working

Theofanis Despoudis


Five Things You Should Never Ship to Production in a Container

Here is our take on five things to avoid when creating a container or shipping it to production.

Chris Tozzi

Increasing Your CI/CD Velocity with Slim Containers

We’ll explain what Slim Containers are, how they speed up the build process, and how they can improve the efficiency of your testing.

Mike Mackrory


Integrate Testing into Your Container Pipeline

A closer look at testing within container pipelines, CI/CD, software delivery, and containerization.

Faith Kilonzi

Software Engineer

Reducing Docker Image Size - Slimming vs Compressing

Know the difference

Pieter van Noordennen


Serverless Applications and Docker

How to Scale the Latest Trend in Infrastructure

Pieter van Noordennen


Slim.AI Docker Extension for Docker Desktop

How to access our Docker Extension and try it for yourself.

Josh Viney


Where Do You Store Your Container Images?

Container Registry Options are Growing in Number and Complexity

Pieter van Noordennen


Using AppArmor and SecComp Profiles for Security Audits

Conduct better container security audits using tools like SecComp, NGINX, and Docker.

What’s in your container?

Why Docker Layers matter for container optimization

Pieter van Noordennen


Why Developers Shouldn't Have to Be Infrastructure Experts, Too

Simplifying processes required to containerize and deploy cloud-native apps.

Chris Tozzi

A New Workflow for Cloud Development

Leverage the benefits of containerization without the headaches & hassle

John Amaral


Why Don’t We Practice Container Best Practices?

Container best practices are easy to understand, hard to do

John Amaral


Better Security Audits with AppArmor and SecComp via DockerSlim

Combine the power of tools like SecComp, NGINX, and Docker.