5 Reasons You Need Microcontainers

Make Docker containers smaller Make Docker containers run faster Make Docker containers more secure Make Docker containers more reliable Take up fewer resources

Introducing Microcontainers: Shrink Docker Containers Down to Size

Docker lets you package an application (and all of the application’s dependencies) into a nice, neat self-contained image and place it in containers. Good. The problem is, you end up with a large image and even larger containers. Bad.

Introducing Microcontainers — a simple hack to shrink containers down to size! Think of Microcontainers as tiny, portable Docker containers.

In this guide, learn how to make Docker containers smaller, safer, and smarter.

Schedule a call today to learn how to customize your microcontainers with IronWorker for true cloud elasticity.

Table of Contents

Docker Containers Issues

Most people use Docker’s official repositories as their language of choice. But there’s an issue. A big one. Users end up with images bigger than the Empire State Building. Seriously.

Use Docker’s official Node image. Build a Node image for your app. It’s going to be 643MB at a minimum. Why? That’s the size of the official Node image.

Evidence: We created a simple Hello World Node app and built it on top of the official Node image. It weighs in at a colossal 644MB. Yep, 644MB. That’s huge!

Our app is less than 1MB with dependencies and the Node.js runtime is ~20MB. So what’s taking up the other ~620MB?

There has to be an alternative…

What Are Microcontainers?

A Microcontainer only contains:

The OS libraries and language dependencies required to run an application, and

The application itself.

Nothing more.

Our advice: Start with the bare minimum and add dependencies as you go.

We tried it with IronWorker, a serverless container management solution, built from the ground up, that’s so easy to use. It’s the only platform of its kind built for the modern cloud. (Get a FREE 14-day trial. No cards. No commitment. Sign up right here.)

This is what we did…

We took the same Node app as before.

We used a really small base image and installed just the essentials. (Primarily Node.js and its dependencies.)

It came out as 29MB. That’s 22 times smaller!

Regular Image vs Micro Image

Run both of these right now and see for yourself:

docker run –rm -p 8080:8080 treeder/tiny-node:fat

docker run –rm -p 8080:8080 treeder/tiny-node:latest

The same app. Significantly different sizes. All thanks to IronWorker.

Other people love IronWorker too. It has 4.6/5 stars on the business software review website G2. Find out what people think here.

Why Are Microcontainers Awesome?

There are many reasons:

Microcontainers are small . As you can see above, the image is 22 times smaller than a typical image without changing any code. This is great for container management.

. As you can see above, the image is 22 times smaller than a typical image without changing any code. This is great for container management. Microcontainers are fast. Because the size is so much smaller, downloading the image from a Docker registry (for example, Docker Hub) is so much quicker. You can distribute it to different machines much quicker too.

Because the size is so much smaller, downloading the image from a Docker registry (for example, Docker Hub) is so much quicker. You can distribute it to different machines much quicker too. Microcontainers are safer. With less code/fewer programs in the container, there’s less attack surface. Plus, the base OS can be more secure.

These benefits are similar to those of Unikernels, but with none of the drawbacks.

How to Build Microcontainers

The base image for Docker images is the “scratch” image. Essentially, it has nothing in it. This might sound useless, but it’s not. If you compile your app to a static binary with zero dependencies (like you can with Go or C), you can use the base image to create the smallest possible image for your app with IronWorker. Simple.

For instance, our treeder/static-go image contains a Go web app and the entire image (including our app) is 5MB. That’s about as small as you can get. (The scratch image + the application binary.) But not everyone’s using Go. If you’re not, you probably have more dependencies and want something with more than the scratch image.

Enter Alpine Linux. We won’t bore you with the details, but its tagline says:

Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.

Read what each of these things means here, but let’s just focus on the “lightweight” part. Did you know the base Alpine image is just 5MB?

So now we have a nice OS as a base with a nice package system to add dependencies. For our simple Node app, we only need Node itself so we add the Node package and nothing else. Our Dockerfile looks like this:

View the code on Gist.

Simple and clean. We only have:

Node, and

What the Node needs in the image.

Let’s add our code to the image. It’s just a few more lines in our Dockerfile:

View the code on Gist.

Grab sample code and see the full build instructions here, but you get the idea. We now have:

A very small OS, and

Only the dependencies we need, and

Our application code.

Nothing more.

With IronWorker, the same rules apply to all languages.

Base Images for All Languages

IronWorker has built base images for all major languages. Find them here:

We’ve done some optimizations to make them as small as possible, and we update these regularly. It’s better than doing it yourself.

Using the Iron.io base images, the Dockerfile above for the Node app changes to:

View the code on Gist.

For every language, we built two versions of the image:

One for building, and

One for running.

(The ones for building have all the build tools in them so are much bigger than the ones for running.)

To build Node dependencies, you’d use iron/node:dev like this:

View the code on Gist.

Then use iron/node in your Dockerfile. To run it…

View the code on Gist.

The same goes for all other languages, but you’d use their build/vendor/run commands.

To use a different version of a language, change the tag. For example, use iron/node:4.1 or iron/node:0.12. You can find all the version tags for reach language on Docker Hub:

Node tags are here: https://hub.docker.com/r/iron/node/tags/

Find links to other Docker Hub tags from the iron-io/dockers repo.

How to Build and Package for All Languages

IronWorker has examples of using the above base images for most major languages here:

If you look at the README files for each language in that repository, it tells you how to build your dependencies, test code, build a small Docker image, and test the image.

No Going Back

After reading this guide, you can now create Docker images for apps that contain nothing more than what’s required to run that app. A container is essentially an instance of an image, so once you start firing up containers using an image, you’ve entered the world of Microcontainers. There’s no going back!

Just used your “tiny image” technique on one of my golang repos. It’s awesome! Thanks for the great post. Shrunk it down to 5MB. Amazing. — Harlow Ward @ Clearbit

Ready For IronWorker?

IronWorker offers a FREE 14-day trial. No cards. No commitment. Sign up for a demo.