Just started working with Elixir a month or so ago and am trying to package an application in Docker for the first time. It builds perfectly fine, but it crashes when ran with the following error:
/opt/sergei/releases/0.1.0/../../erts-13.1.3/bin/erl: exec: line 12: /opt/sergei/erts-13.1.3/bin/erlexec: not found
I’ve shelled into the docker container; the file does exist.
Here’s my Dockerfile
FROM elixir:alpine AS build_stage
# Config
ENV MIX_ENV prod
WORKDIR /opt/build
# Dependendies
COPY mix.* ./
COPY config ./config
RUN mix local.hex --force && \
mix local.rebar --force && \
mix deps.get --only prod && \
mix deps.compile
# Build project
COPY . .
RUN mix release sergei
FROM alpine:latest
WORKDIR /opt/sergei
COPY --from=build_stage /opt/build/_build/prod/rel/sergei /opt/sergei
ENTRYPOINT ["/opt/sergei/bin/sergei"]
CMD ["start"]
I did some work to reproduce this locally and while I can’t prove it exactly, I’m willing to bet that there’s a versioning difference between elixir:alpine and alpine:latest. If I change the second FROM statement to elixir:alpine, it works fine. I’ll do some more digging (because I’m curious), but that seems like a plausible reason to me. Not sure why you’re getting a “no such file or directory” error, though.
I think I know the problem here. alpine uses musl OOTB, while most others use glibc. I cannot reproduce your problem exactly (the only way I was able to do so was by setting the build_stage FROM to elixir, which is actually Debian based), however, in that situation, I was able to do some poking. If I straceerlexec – since as you point out, it does exist – I see the following
execve("/opt/elixir_hello_world/erts-13.1.4/bin/erlexec", ["/opt/elixir_hello_world/erts-13."...], 0x7ffd6d09ac30 /* 6 vars */) = -1 ENOENT (No such file or directory)
What I suspect is going on (but is hard to pin down given I can’t fully recreate your problem) is that glibc is being brought into your container somehow (are you perhaps copying _build from your local machine when you build the release? it may be worth adding that to .dockerignore), which is causing you problems when you move onto a glibc-less system (i.e. alpine:latest). When I build the release on elixir:alpine, I see that erlexec is correctly linked to libmusl