Automatically Reduce your Docker Container Size Using SlimToolkit

John Amaral
← Slim Blog

Prerequisites to complete this example

  • Basic knowledge of Linux commands and a terminal
  • Docker Desktop is installed on your host machine.
  • A text editor or browser to view JSON files

For video instructions click here: Automatically reduce container image size using SlimToolkit

Many tech stacks struggle with large Docker container sizes, and common web frameworks are no exception. Python’s Flask microframework is one of the world’s most popular open source set-ups for RESTful web services and APIs. However, common Python-Flask Docker images can weigh in at close to 1 GB in size.

Slimming an application built with Python-Flask using SlimToolkit is easy, automatic, and quick. Here’s a step-by-step tutorial using SlimToolkit’s build functionality.

1. Download and test SlimToolkit

Download SlimToolkit from here: https://slimtoolkit.org/

We developed this example on macOS.

Create a folder and copy the files from the SlimToolkit download into the folder. We’ll create one called SlimToolkit.

├── Slim
| ├── slim
| ├── slim-sensor

If you plan to use SlimToolkit frequently, we recommend you add your folder path to the /etc/paths file or otherwise add it to your PATH so you can run the slim command from anywhere.

# /etc/paths
## some paths
/<pathtomyslimfolder>/Slim

Restart terminal for the changes to be active.

Otherwise, you’ll need to run your slim commands from the directory where you extracted them. You can type ./slim help to run SlimToolkit in this case. We’ll generally assume that you’ve added the slim binaries to your path.

Run SlimToolkit to check if it’s working by typing slim help (or ./slim help if you did not add it to your PATH above).

slim help

Output

NAME:
slim - optimize and secure your Docker containers!

USAGE:
slim [global options] command [command options] [arguments...]

VERSION:
darwin|Transformer|1.35.0|6eca3ad331720c31a7e398ffaf002a896dc9a70a|2021-04-15_02:48:03AM

COMMANDS:
build, b Analyzes, profiles and optimizes your container image auto-generating Seccomp and AppArmor security profiles
containerize, c Containerize the target artifacts
convert, k Convert container image
edit, e Edit container image
help, h Show help info
lint, l Analyzes container instructions in Dockerfiles
probe, prb Probe target
profile, p Collects fat image information and generates a fat container report
run, r Run one or more containers
server, s Run as an HTTP server
update, u Updates slim
version, v Shows slim and docker version information
xray, x Shows what's inside of your container image and reverse engineers its Dockerfile

GLOBAL OPTIONS:
--report value command report location (enabled by default; set it to "off" to disable it) (default: "slim.report.json")
--check-version check if the current version is outdated [$SLIM_CHECK_VERSION]
--debug enable debug logs
--verbose enable info logs
--log-level value set the logging level ('debug', 'info', 'warn' (default), 'error', 'fatal', 'panic') (default: "warn")
--log value log file to store logs
--log-format value set the format used by logs ('text' (default), or 'json') (default: "text")
--tls use TLS
--tls-verify verify TLS
--tls-cert-path value path to TLS cert files
--host value Docker host address
--state-path value Slim state base path
--in-container Slim is running in a container
--archive-state value archive Slim state to the selected Docker volume (default
volume - slim-state). By default, enabled when Slim is running in a
container (disabled otherwise). Set it to "off" to disable explicitly.
--no-color disable color output
--version, -v print the version

SlimToolkit has an excellent menu-driven command line. To try that, simply run slim with no additional arguments. You can get to the help menu by typing help in the command line at the interactive prompt.

2. Prepping a Container to Slim

We’ll use the SlimToolkit build command for this exercise and pull one of the SlimToolkit example containers. The container houses a simple Python/Flask service. You can pull the container from the slimexamples repo on DockerHub.

docker pull slimexamples/server-python2-flask-standard

After the pull command completes, check to see that the image is loaded using the docker images command.

Output

Using default tag: latest
latest: Pulling from slimexamples/server-python2-flask-standard
741437d97401: Pull complete
34d8874714d7: Pull complete
0a108aa26679: Pull complete
7f0334c36886: Pull complete
49ea0d2b5c48: Pull complete
2f697d8eb8c9: Pull complete
19e57c082018: Pull complete
62a638f5d7ed: Pull complete
5bceaf33fb03: Pull complete
72d2aabda994: Pull complete
9bb059401bdd: Pull complete
d3940358526e: Pull complete
Digest: sha256:0b1ba4d668a86479b927ff522bab220a27ece1c40a1d1dc89bc15b81a44b7f8b
Status: Downloaded newer image for slimexamples/server-python2-flask-standard:latest
docker.io/slimexamples/server-python2-flask-standard:latest

3. Verifying the output container

A vital step when minifying a container is verifying that the output container from SlimToolkit functions correctly. We will use curl to perform a simple before and after functional verification on the example container.

To perform the simple validation test, we first need to run the example container. Run the following command in the terminal window.

docker run -it --rm -p 1300:1300 --name slimflask slimexamples/server-python2-flask-standard

Output

* Serving Flask app "server" (lazy loading)
* Environment: production
  WARNING: This is a development server. Do not use it in a production deployment.
  Use a production WSGI server instead.
* Debug mode: on
* Running on http://0.0.0.0:1300/ (Press CTRL+C to quit)

This command starts the Python/Flask container interactively (see the -it flags) and attaches the container's open port to 1300 on localhost.

Open a second terminal window and use CURL to send a request to the running container. (Note: You will need CURL installed on your local machine and available via your PATH.)

curl http://127.0.0.1:1300

This curl command performs an HTTP GET on the root method of the Python/Flask REST service running in the container we just started. The Python/Flask service will respond by returning a JSON object with a “success” status. The service also logs an access record (see the terminal window in the background of the following image) to the terminal with IP Address, Date, Time, method (GET /HTTP 1.1), and 200 success status code.

This sequence (successfully) performs a basic web service test to verify that the example container functions as expected.

Press CTRL+C in the window where the Python/Flask server container runs to exit the service to stop the container.

4. Building the container from SlimToolkit

Next, we will minify the container using the SlimToolkit build command. The SlimToolkit build command takes a container image reference as input. The input container image must be available on the local Docker Desktop in order for SlimToolkit to be able to access it.

In the terminal window where you previously started the Python/Flask container, enter the following.

slim build --copy-meta-artifacts . slimexamples/server-python2-flask-standard

Here, the --copy-meta-artifacts . argument will copy several files produced by SlimToolkit into the current working directory. You can change . to any path you choose.

a. SlimToolkit Build Steps and Output

As you can see here, the output from the SlimToolkit build command is fairly robust.

But what’s actually happening?

The minification process includes performing a combination of static and dynamic analysis of the input container image to determine which files, libraries, executables, etc., are required for the regular operation of the container.

SlimToolkit runs the input container using the Docker engine. While the container is running, SlimToolkit attempts to understand how the application(s) present in the container function by using a set of built-in probes to inspect various facets of the container.

Here are some of the more pertinent stages of the minification process:

SlimToolkit detects the open ports available for the input container and attempts to execute a sequence of web requests and web crawler actions intended to exercise the underlying web service running in the container. It then observes the application dependencies, files, and executables necessary for the application to function in response to probes, recording these dependencies and using this knowledge to compose the output container.

SlimToolkit does not modify the original input container. The output of the build command is a new container image produced by SlimToolkit (renamed by adding ‘.slim’ to the original container image name) constructed to include only the files necessary for the container's functional operation. This new container contains a subset of the input container’s files. SlimToolkit does not inject any new files into the output container. However, SlimToolkit flattens the output container layer structure.

Note: SlimToolkit has several other built-in methods to test and stimulate a containerized application. SlimToolkit also includes several advanced commands and options to perform minification for a wide variety of Linux-based containerized applications.

You can find details about SlimToolkit advanced build commands here:

https://github.com/slimtoolkit/slim#build-command-options

b. Verifying our results from the slimmed container

When SlimToolkit finishes, use docker images to see the new slim container produced by SlimToolkit. It can be found with the .slim extension to the original container name.

Note: The .slim image is 28MB vs 932MB (33X smaller)!

We will verify the ‘.slim’ version of the container using the same curl command we used previously. Run the .slim container by executing the following command in the terminal.

docker run -it --rm -p 1300:1300 --name slimflask slimexamples/server-python2-flask-standard.slim

The Python/Flask service starts normally and produces outputs identical to that of the input container when we ran it previously.

Just like before, we can open a second terminal window to do our CURL test on the running, and now slimmed, container.

curl http://127.0.0.1:1300

The web service returns a success response and logs the access in the terminal as before.

In this case, SlimToolkit has produced a much smaller, minified output container that functions equivalently to the original input container.

And just like that, you have a 28 MB container that does all the same things as your previous image.

Looking for similar examples to play around with? Check out a wide variety of different containerized applications in the SlimToolkit examples Github, and follow our Twitch Live Stream, where we review a new container type each week.

Embarking on a New Journey

Farewell, Slim — Transitioning to a new and larger mission!

We're excited to share some big news from Slim.AI. We're taking a bold new direction, focusing all our energy on software supply chain security, now under our new name root.io. To meet this opportunity head-on, we’re building a solution focused on transparency, trust, and collaboration between software producers and consumers.

When we started Slim.AI, our goal was to help developers make secure containers. But as we dug deeper with our early adopters and key customers, we realized a bigger challenge exists within software supply chain security ​​— namely, fostering collaboration and transparency between software producers and consumers. The positive feedback and strong demand we've seen from our early customers made it crystal clear: This is where we need to focus.

This new opportunity demands a company and brand that meet the moment. To that end, we’re momentarily stepping back into stealth mode, only to emerge with a vibrant new identity, and a groundbreaking product very soon at root.io. Over the next few months, we'll be laser-focused on working with design partners and building up the product, making sure we're right on the mark with what our customers need.

Stay informed and up-to-date with our latest developments at root.io. Discover the details about the end of life for Slim services, effective March 31, 2024, by clicking here.

Embarking on a New Journey

Farewell, Slim — Transitioning to a new and larger mission!

We're excited to share some big news from Slim.AI. We're taking a bold new direction, focusing all our energy on software supply chain security, now under our new name root.io. To meet this opportunity head-on, we’re building a solution focused on transparency, trust, and collaboration between software producers and consumers.

When we started Slim.AI, our goal was to help developers make secure containers. But as we dug deeper with our early adopters and key customers, we realized a bigger challenge exists within software supply chain security ​​— namely, fostering collaboration and transparency between software producers and consumers. The positive feedback and strong demand we've seen from our early customers made it crystal clear: This is where we need to focus.

This new opportunity demands a company and brand that meet the moment. To that end, we’re momentarily stepping back into stealth mode, only to emerge with a vibrant new identity, and a groundbreaking product very soon at root.io. Over the next few months, we'll be laser-focused on working with design partners and building up the product, making sure we're right on the mark with what our customers need.

Stay informed and up-to-date with our latest developments at root.io. Discover the details about the end of life for Slim services, effective March 31, 2024, by clicking here.