gmile

gmile

Smallest docker container with elixir app

After docker released native support for multi-stage builds, I decided to make my own small docker container with app.

Below container is based on the one from @bitwalker. It is the smallest one I could come up with in one sitting, given quite limited knowledge of docker & distillery releases:

# Dockerfile
FROM bitwalker/alpine-elixir:1.4.4 as builder

ADD . /app

WORKDIR /app

ENV MIX_ENV=prod

RUN mix do deps.get, deps.compile, release

FROM alpine:3.6

RUN apk add --no-cache \
      ca-certificates \
      openssl-dev \
      ncurses-dev \
      unixodbc-dev \
      zlib-dev

WORKDIR /app

COPY --from=builder /app/_build/prod/rel/ritm/releases/0.0.1/ritm.tar.gz /app

ENV PORT=4000

RUN tar -xzf ritm.tar.gz; rm ritm.tar.gz

CMD ["bin/ritm", "foreground"]

It’s around 64Mb when pushed to docker hub. That’s a lot, although I don’t expect this to grow significantly (more app code & deps shouldn’t contribute that much).

I am aware guys from @Nerves-Core-Team build super-small linux images with the app installed, but I am not sure what could be derived from their work in order to build my own small container with docker.

How can I reduce the size of container even further?

First 10 of 26 Posts Switch mode

wmnnd

wmnnd

@gmile You don’t need the -dev libs on the release image.

This should suffice:

 add --no-cache \
      ncurses-libs \
      zlib \
      openssl \
      ca-certificates
gmile

gmile OP

@wmnnd this dropped the size to 56 MB, thanks!

cmkarlsson

cmkarlsson

How big is the actual release tar file you copy onto the image? The
reason I am asking is that I built alpine from scratch with our erlang
release and it was 18MB where 2/3 (if I remember correctly) was our release.

You should be able to shrink this significantly.

wmnnd

wmnnd

How do you suggest shrinking the release size?

cmkarlsson

cmkarlsson

Normally you don’t. You can exclude debug information which will make it
much smaller (half the size?). Without debug information you cannot
do things like tracing and other useful introspection in production. But
if you need the smallest available this is an option.

Generally the release size is the size your image will be + 5MB or so
for alpine.

bitwalker

bitwalker

Leader

If you depend on additional system libs that can add quite a bit of weight, depending on what they are. You can also double check to see which Erlang applications are being included, it should only be the subset your application depends on, not all of them.

A medium-sized application would probably depend on enough Erlang libs to hit that limit before any code from their own application was counted. A simple test project of mine hits 23mb with just libs, and here are the ones included in the release:


asn1-5.0/
certifi-1.1.0/
combine-0.9.6/
compiler-7.1/
crypto-4.0/
elixir-1.4.5/
gettext-0.13.1/
hackney-1.8.0/
idna-4.0.0/
iex-1.4.5/
kernel-5.3/
logger-1.4.5/
metrics-1.0.1/
mimerl-1.0.2/
poison-3.1.0/
public_key-1.4.1/
sasl-3.0.4/
ssl-8.2/
ssl_verify_fun-1.1.1/
stdlib-3.4/
test-0.1.0/
timex-3.1.13/
tzdata-0.5.12/

So either your app was extremely small or didn’t depend on much - in any case, I suspect most real-world applications will be much larger than 18mb. ERTS itself is only like 6mb, and anything in priv of your application or your dependencies will also be included.

I strongly recommend not stripping debug info - those cases you mentioned are some of the most powerful capabilities of the runtime, and are one of the reasons why OTP is such a powerful tool operationally. You are trading a small amount of space for a significant amount of functionality, to me it’s not even close to worth it to sacrifice that.

cmkarlsson

cmkarlsson

So either your app was extremely small or didn’t depend on much - in any case,
I suspect most real-world applications will be much larger than 18mb. ERTS
itself is only like 6mb, and anything in priv of your application or your
dependencies will also be included.

Yes, it didn’t have many dependencies. My point was that the
release is what should take up the most space. You cannot get the docker image
smaller than the release and that the alpine linux image should have
very little overhead in terms of space.

I strongly recommend not stripping debug info - those cases you mentioned are
some of the most powerful capabilities of the runtime, and are one of the
reasons why OTP is such a powerful tool operationally. You are trading a small
amount of space for a significant amount of functionality, to me it’s not even
close to worth it to sacrifice that.

Agreed. I don’t think the trade-off is worth it either but if you want
the smallest image possible you should know about the option.

We generally encrypt the debug info (we ship our software to clients).
In this case you need the key to be able to do any debugging but it
makes it a little bit harder to reconstruct the source code.

gmile

gmile OP

I’ve measured the space taken inside the container, and here’s what I’ve got.

  • here’s the root:

    docker run -it gmile/ritm:0.0.9 du / -h -d 1
    0       /dev
    4.0K    /home
    0       /proc
    4.0K    /root
    8.9M    /usr
    4.0K    /tmp
    812.0K  /bin
    80.0K   /var
    0       /sys
    1.3M    /etc
    4.0K    /run
    4.0K    /srv
    4.0K    /mnt
    220.0K  /sbin
    5.3M    /lib
    16.0K   /media
    55.7M   /app
    72.3M   /
    
  • here’s the /app folder, containing unpacked tar release:

    docker run -it gmile/ritm:0.0.9 du /app -h -d 1
    52.0K   /app/bin
    380.0K  /app/releases
    33.7M   /app/erts-8.3
    21.6M   /app/lib
    55.7M   /app
    

ERTS itself is only like 6mb

@bitwalker from what I am seeing, erts is 33.7 Mb way bigger than 6 Mb. Any ideas why so?

gmile

gmile OP

Upgrading the base image to bitwalker/alpine-elixir:1.4.5 (with erlang 20.0.1 underneath) shaved off another 12 Mb down to 48 Mb. After looking at the size stats, the shrink is due to erts loosing some weight:

docker run -it gmile/ritm:0.0.10 du /app -h -d 1
21.1M   /app/erts-9.0.1
52.0K   /app/bin
380.0K  /app/releases
22.2M   /app/lib
43.7M   /app

The size of erts is still way more than 6 Mb.

bitwalker

bitwalker

Leader

You’d have to show what is taking up that space in the ERTS folder - on my laptop, a release packed with ERTS included only shows 5.4mb in the erts-9.0 folder via du -hs <path>. Either there is more in the ERTS folder on Alpine which can be stripped (and I can tweak that in the Alpine images I produce if so) or it’s just bigger on Linux for some reason, but I can’t imagine why that would be.

Where Next?

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
silverdr
Using Phoenix.LiveView.TagEngine as an EEx.Engine is deprecated! To compile HEEx, use Phoenix.LiveView.TagEngine.compile/2 instead. Sta...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
michallepicki
I am using Oban and occasionally, shortly after a deployment, a handful of jobs can fail because of dependency on other parts of the syst...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement