'How can I use Erlang with Docker to run a Phoenix application?
I want to use a docker image in production to run a Phoenix container, However, since Elixir is just a layer on top of Erlang, it feels like it might be a waste of space to have Elixir running in my production environment.
Ideally, I would be able to compile an entire Phoenix application into Erlang, and then use an image from erlang:alpine to actually run the app in production. Something like this...
FROM elixir:alpine as builder
(install dependencies and copy files)
RUN mix compile_app_to_erlang
FROM erlang:alpine
COPY --from=builder /path/to/compiled/erlang /some/other/path
CMD ["erlang", "run"]
note: compile_app_to_erlang is not a real command, but I'm looking for something like it. Also, I have no idea how erlang runs, so all the code in there is completely made up.
Also, from what I know, there is a project called distillery that kind of does this, but this seems like the type of thing that shouldn't be too complicated (if I knew how erlang worked,) and I'd rather not rely on another dependency if I don't have too. Plus it looks like if you use distillery you also have to use custom made docker images to run the code which is something I try to avoid.
Is something like this even possible? If so, anyone know a DIY solution?
Solution 1:[1]
Elixir 1.9 added the concept of a "release" to Mix. (This was released about 11 months after the question was initially asked.) Running mix release
will generate a tree containing the BEAM runtime, your compiled applications, and all of its dependencies. There is extensive documentation for the mix release
task on hexdocs.pm.
In a Docker context, you can combine this with a multi-stage build to do exactly what you're requesting: start from the complete elixir
image, create a tree containing the minimum required to run the image, and COPY
it into a runtime image. I've been working with a Dockerfile like:
FROM elixir:1.13 AS build
WORKDIR /build
ENV MIX_ENV=prod
# Install two tools needed to build other dependencies.
RUN mix do local.hex --force, local.rebar --force
# Download dependencies.
COPY mix.exs mix.lock ./
RUN mix deps.get --only prod
# Compile dependencies (could depend on config/config.exs)
COPY config/ config/
RUN mix deps.compile
# Build the rest of the application.
COPY lib/ lib/
COPY priv/ priv/
RUN mix release --path /app
FROM ubuntu:20.04
# Get the OpenSSL runtime library
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes \
libssl1.1
# Get the compiled application.
COPY --from=build /app /app
ENV PATH=/app/bin:$PATH
# Set ordinary metadata to run the container.
EXPOSE 4000
CMD ["myapp", "start"]
If you're using Phoenix, the Phoenix documentation has a much longer example. On the one hand that covers some details like asset compilation; on the other, its runtime image seems to have a bit more in it than may be necessary. That page also has some useful discussion on running Ecto migrations; with the Elixir fragment described there you could docker run
a temporary container to do migrations, run them in an entrypoint wrapper script, or use any other ordinary Docker technique.
Solution 2:[2]
I suggest you to use distillery to build a binary.
Then just run a alpine
container, mount the distillery release
to it, run the binary. Yeah, you can eve use supervisor to run it.
You can use remote_console
of distillery to link to the console of this binary.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | David Maze |
Solution 2 |