Even if I strip 11 Mb, that’d make it 48 - 11 = 37, which is still 2x times than what people here are reporting, e.g. 20 Mb.
I’ll investigate further.
Even if I strip 11 Mb, that’d make it 48 - 11 = 37, which is still 2x times than what people here are reporting, e.g. 20 Mb.
I’ll investigate further.
Your ERTS is only 19mb though, of which 11mb is apparently debug info, the rest is presumably system libs and your application code. 20mb is the absolute smallest application people are reporting, not the average. My applications on average are ~50-75mb, so you are well within normal size in my opinion.
Not quite true …
# in a bare minimum Phoenix project with one C ext package
mix edib --hex --edib edib/edib-tool:latest --strip
# ...
docker images
REPOSITORY ... SIZE
local/edib_app_test ... 14.7MB
A simple hello world Elixir app without any real code and deps would be around 10ish MB with stripping.
Though I also wouldn’t recommend using stripping and/or zipping if not really necessary, of course.
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
So, the Dockerfile I’m using has changed significantly. I’m now using two of them:
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.
I think openssl
package is not needed if Erlang is built with ./configure --disable-dynamic-ssl-lib ...
.
@melpon unfortunately by default erlang for alpine is built using --enable-ssl=dynamic-ssl-lib
–