Small Docker Images with erlang/elixir

Posted on Fri 18 March 2016 in docker

Premise

It is mainly the first time that I am playing with docker

Objective

I wanted to create a docker image from scratch (not using Docker HUB) and I wanted to be small enough. For instance, small enough means less than 100mb, ideally around 50mb with everything that I need

Creating the first docker image from scratch

First I tried to build a minimal debian image trying to use directly debootstrap by doing:

1
2
sudo /usr/sbin/debootstrap jessie ./jessie-chroot
sudo tar -C jessie -c . | docker import - jessie

However it generated an image which was around 250mb

It's since a long time that I do not pay attention to the base disk space of debian, I remembered a less fat base system. I might have a brain fart although ;)

Second try

Using the script provided by docker, I executed:

1
sudo .../mkimage.sh -t $USER/minbase debootstrap --variant=minbase stable

mkimage.sh under debian based distributions should be located here: /usr/share/docker-engine/contrib/mkimage.sh After few minutes (coffee and smoke time) I was pleasantly surprised that the image was cut by a half.

1
beatpanic/minbase   latest              3601280024d7        5 seconds ago       123.6 MB

Most probably because of the --variant=minbase option, however my objective was not yet reached.

Third try

Thanks to a friend of mine (hello @the_mindflayer!) I discovered a Linux distribution called Alpine Linux The basic distribution is based on busybox, so it's quite small. A mere 7mb (I guess it can be smaller).

The beauty of Alpine Linux resides on the fact that it is small for sure, however the thing that caught my eye was the apk package manager, which, contains also.. erlang and elixir!

The docker-engine package contains already an mkimage-alpine.sh script, so I gave it an instant try:

1
sudo /usr/share/docker-engine/contrib/mkimage-alpine.sh

And that's it for this step!

The alpine image is big as 7mb!

1
alpine              latest              a6ad3e89bcdd        22 hours ago        7.206 MB

7mb should be enough for my Objective I thought!

So, let's give it a try in installing erlang plus elixir

Thanks to bitwalker repo I was able to bootstrap quickly my image with his Dockerfile You can check it here https://github.com/bitwalker/alpine-elixir-phoenix/blob/master/Dockerfile However when re-building the image with this Dockerfile it was fat again

"Stripped down" Dockerfile

I decided to remove a bunch of things that I do not need and adapter the Dockerfile of bitwalker in this way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
FROM alpine:latest
MAINTAINER Fancy Maintaner <fancy@fancy.org>

# Important!  Update this no-op ENV variable when this Dockerfile
# is updated with the current date. It will force refresh of all
# of the base images and things like `apt-get update` won't be using
# old cached versions when the Dockerfile is built.
ENV REFRESHED_AT 2016-03-18
ENV ELIXIR_VERSION 1.2.3
ENV HOME /root

# Install Erlang/Elixir
RUN echo 'http://dl-4.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories && \
  echo 'http://dl-4.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories && \
  apk --update add ncurses-libs ca-certificates \
                  erlang erlang-dev erlang-kernel erlang-hipe erlang-compiler \
                  erlang-stdlib erlang-erts erlang-tools erlang-syntax-tools erlang-sasl \
                  erlang-crypto erlang-public-key erlang-ssl erlang-ssh erlang-asn1 erlang-inets \
                  erlang-inets erlang-mnesia erlang-odbc \
                  erlang-erl-interface erlang-parsetools erlang-eunit && \
  wget https://github.com/elixir-lang/elixir/releases/download/v${ELIXIR_VERSION}/Precompiled.zip && \
  mkdir -p /opt/elixir-${ELIXIR_VERSION}/ && \
  unzip Precompiled.zip -d /opt/elixir-${ELIXIR_VERSION}/ && \
  rm Precompiled.zip && \
  rm -rf /var/cache/apk/*

# Add local node module binaries to PATH
ENV PATH $PATH:node_modules/.bin:/opt/elixir-${ELIXIR_VERSION}/bin

# Install Hex+Rebar
RUN mix local.hex --force && \
  mix local.rebar --force

CMD ["/bin/sh"]

Which bumps to the current latest elixir version (1.2.3) and removes python, g++, wget, git, make.

Conclusion

The generated image satisfies my initial Objective since it is a mere 43mb:

1
elixir             latest              cf6bef978aa3        8 hours ago         42.88 MB

Mission complete for now!

1
2
3
4
5
$ docker run -ti d3adb33f iex
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.2.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 

That's it!