Search code examples
dockerelixirreleaseelixir-mix

Docker of mix release crashes with "Exec format error"


Background

I have an executable created via mix release which works just fine when I run it with start on my local machine. However, my docker image crashes when trying to start the executable and I don't know why.

Docker

FROM elixir:1.10

# Install Hex + Rebar
RUN mix do local.hex --force, local.rebar --force

COPY . /
WORKDIR /

ENV MIX_ENV=prod
RUN mix do deps.get --only $MIX_ENV, deps.compile
RUN mix release

EXPOSE 8080
ENV PORT=8080
ENV SHELL=/bin/bash

CMD ["_build/prod/rel/my_app/bin/my_app", "start"]

This is my docker file. It does nothing special other than compiling and then trying to run the release via start.

Error

However, when I execute the docker image with docker run -p 8080:8080 my-app:1.0 docker crashes:

/_build/prod/rel/my_app/releases/0.1.0/../../erts-10.5/bin/erl: 12: exec: /_build/prod/rel/my_app/erts-10.5/bin/erlexec: Exec format error

Research

At first I thought this was happening because the file _build/prod/rel/my_app/bin/my_app was missing #!/usr/bin/env bash at the top (after reading some SO questions).

While indeed it doesn't have that, it has something else that should equally work: #!/bin/sh

So this theory is out.

Question

Is something wrong with my Dockerfile? How can I get rid this error?


Solution

  • RCA

    This was a tricky one. After reading other similar questions (and the comments from @potibas and @Stefano) I found out what was happening.

    So, as I have said, the release file works well on my local machine. This happens because in my local machine the files were being compiled to its operative system (OS).

    Now, the docker VM does not have the same OS as my local machine. This matters because of this line:

    COPY . /

    Here I am copying everything from the workdir to docker. Including the binaries and dependencies compiled for my local machine's OS.

    This caused the issue above mentioned.

    Solution

    There are 2 possible solutions.

    1. Remove the _build and deps folders from the image after the COPY command, via RUN rm -r _build and RUN rm -r deps/.
    2. Add the mentioned folders as well as all the non-essential files to a .dockerignore file.

    I personally opted for the second option, as it allows me to have a leaner image.