gmile

gmile

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 Post!

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

Most Liked

gmile

gmile OP

In case anyone is interested, this is the container I’m building right now. It uses:

  • alpine:3.6 as a builder/runner image,
  • Erlang 20.1.1
  • Elixir 1.5.2

I like to build my own image instead of a pre-backed image in this case. I like to install elixir/erlang, as well as other packages, instead of compiling them. By looking at base image, I know that there’s no magic going on here.

It’s size, including my apps compiled code and dependencies is 55.5 Mb.

FROM alpine:3.6 as builder

RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repositories

RUN apk add --update \
      git \
      erlang=20.1.1-r0 \
      elixir=1.5.2-r0 \
      erlang-crypto \
      erlang-parsetools \
      erlang-syntax-tools \
      erlang-runtime-tools

ADD . /app

WORKDIR /app

ENV MIX_ENV=prod

RUN mix do local.hex --force, \
           local.rebar --force, \
           deps.get, \
           deps.compile, \
           release

FROM alpine:3.6

RUN apk add --no-cache \
      ncurses-libs \
      zlib \
      ca-certificates \
      openssl \
      bash

WORKDIR /app

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

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

I’m relying on distillery for building releases. After the container is built, the app must be started by running bin/my_app foreground in the container:

docker run my_app_image bin/my_app foreground
gmile

gmile OP

So, the Dockerfile I’m using has changed significantly. I’m now using two of them:

  • a base one, which is updated much less frequently,
  • and the apps one, which is ran every time I need to pack the app into a container.

This is how they look like:

Base:

# edenlabllc/elixir:1.5.2

FROM alpine:edge

ENV REFRESHED_AT=2017-11-23

RUN apk add --update \
  erlang=20.1.7-r0 \
  elixir=1.5.2-r0 \
  erlang-crypto \
  erlang-parsetools \
  erlang-syntax-tools \
  erlang-runtime-tools \
  git \
  make

Everyday use:

FROM edenlabllc/elixir:1.5.2 as builder

ARG APP_NAME
ARG APP_VERSION

ADD . /app

WORKDIR /app

ENV MIX_ENV=prod

RUN mix do \
      local.hex --force, \
      local.rebar --force, \
      deps.get, \
      deps.compile, \
      release

FROM alpine:edge

ARG APP_NAME
ARG APP_VERSION

RUN apk add --no-cache \
      ncurses-libs \
      zlib \
      ca-certificates \
      openssl \
      bash

WORKDIR /app

COPY --from=builder /app/_build/prod/rel/${APP_NAME}/releases/${APP_VERSION}/${APP_NAME}.tar.gz /app

RUN tar -xzf ${APP_NAME}.tar.gz; rm ${APP_NAME}.tar.gz

ENV REPLACE_OS_VARS=true \
    APP=${APP_NAME}

CMD ./bin/${APP} foreground

In order to build this, I run:

docker build --tag "my_account/my_app:1.2.3" \
             --file Dockerfile \
             --build-arg APP_VERSION=1.2.3. \
             --build-arg APP_NAME=my_app .

I could merge both Dockerfiles, but it just didn’t make sense to re-install the compile-time dependencies every time I needed to build the app. After all, elixir and erlang release versions much less frequently.

melpon

melpon

I think openssl package is not needed if Erlang is built with ./configure --disable-dynamic-ssl-lib ....

Last Post!

gmile

gmile OP

@melpon unfortunately by default erlang for alpine is built using --enable-ssl=dynamic-ssl-lib
https://github.com/alpinelinux/aports/blob/master/community/erlang/APKBUILD#L90

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
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
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
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

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews