Skip to content

Instantly share code, notes, and snippets.

@nicbet
Created June 27, 2019 03:00
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save nicbet/102f16359828405ce34ca083976986e1 to your computer and use it in GitHub Desktop.
Save nicbet/102f16359828405ce34ca083976986e1 to your computer and use it in GitHub Desktop.
Elixir 1.9 Releases Alpine Linux Docker Multi-Stage Build

Tiny Elixir 1.9 deployments with Alpine Linux and Docker

  1. New project mix phx.new hello --no-ecto --no-webpack
  2. Delete config/prod.secrets.exs
  3. Modify config.prod.exs with file from this gist
  4. Create config/releases.exs with file from this gist
  5. Create Dockerfile with file from this gist
  6. Modify lib/hello_web/templates/page/index.html.eex with file from this gist
  7. Build image docker build -t hello:latest .
  8. Run image docker run --rm -it -p 4000:4000 -e APP_PORT=4000 -e SECRET_KEY_BASE=$(mix phx.gen.secret) -e GREETING="Alpine MultiStage Releases Elixir 1.9" hello:latest

Credits to https://akoutmos.com/post/multipart-docker-and-elixir-1.9-releases/?utm_campaign=elixir_radar_196&utm_medium=email&utm_source=RD+Station for example with Debian.

# ---- Build Stage ----
FROM erlang:22-alpine AS app_builder
# Set environment variables for building the application
ENV MIX_ENV=prod \
TEST=1 \
LANG=C.UTF-8
# Fetch the latest version of Elixir (once the 1.9 docker image is available you won't have to do this)
RUN set -xe \
&& apk add curl make --update-cache \
&& ELIXIR_DOWNLOAD_URL="https://github.com/elixir-lang/elixir/archive/v1.9.0.tar.gz" \
&& ELIXIR_DOWNLOAD_SHA256="dbf4cb66634e22d60fe4aa162946c992257f700c7db123212e7e29d1c0b0c487" \
&& curl -fSL -o elixir-src.tar.gz $ELIXIR_DOWNLOAD_URL \
&& echo "$ELIXIR_DOWNLOAD_SHA256 elixir-src.tar.gz" | sha256sum -c - \
&& mkdir -p /usr/local/src/elixir \
&& tar -xzC /usr/local/src/elixir --strip-components=1 -f elixir-src.tar.gz \
&& rm elixir-src.tar.gz \
&& cd /usr/local/src/elixir \
&& make install clean
# Install hex and rebar
RUN mix local.hex --force && \
mix local.rebar --force
# Create the application build directory
RUN mkdir /app
WORKDIR /app
# Copy over all the necessary application files and directories
COPY config ./config
COPY lib ./lib
COPY priv ./priv
COPY mix.exs .
COPY mix.lock .
# Fetch the application dependencies and build the application
RUN mix deps.get
RUN mix deps.compile
RUN mix phx.digest
RUN mix release
# ---- Application Stage ----
FROM alpine AS app
ENV LANG=C.UTF-8
# Install openssl
RUN apk update && apk add openssl ncurses-libs
# Copy over the build artifact from the previous step and create a non root user
RUN adduser -h /home/app -D app
WORKDIR /home/app
COPY --from=app_builder /app/_build .
RUN chown -R app: ./prod
USER app
# Run the Phoenix app
CMD ["./prod/rel/hello/bin/hello", "start"]
<section class="phx-hero">
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
<p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
<p><%= Application.get_env(:hello, :greeting) %></p>
</section>
<section class="row">
<article class="column">
<h2>Resources</h2>
<ul>
<li>
<a href="https://hexdocs.pm/phoenix/overview.html">Guides &amp; Docs</a>
</li>
<li>
<a href="https://github.com/phoenixframework/phoenix">Source</a>
</li>
<li>
<a href="https://github.com/phoenixframework/phoenix/blob/v1.4/CHANGELOG.md">v1.4 Changelog</a>
</li>
</ul>
</article>
<article class="column">
<h2>Help</h2>
<ul>
<li>
<a href="https://elixirforum.com/c/phoenix-forum">Forum</a>
</li>
<li>
<a href="https://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on Freenode IRC</a>
</li>
<li>
<a href="https://twitter.com/elixirphoenix">Twitter @elixirphoenix</a>
</li>
</ul>
</article>
</section>
use Mix.Config
# For production, don't forget to configure the url host
# to something meaningful, Phoenix uses this information
# when generating URLs.
#
# Note we also include the path to a cache manifest
# containing the digested version of static files. This
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :hello, HelloWeb.Endpoint,
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
# Do not print debug messages in production
config :logger, level: :info
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
# to the previous section and set your `:url` port to 443:
#
# config :hello, HelloWeb.Endpoint,
# ...
# url: [host: "example.com", port: 443],
# https: [
# :inet6,
# port: 443,
# cipher_suite: :strong,
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
# ]
#
# The `cipher_suite` is set to `:strong` to support only the
# latest and more secure SSL ciphers. This means old browsers
# and clients may not be supported. You can set it to
# `:compatible` for wider support.
#
# `:keyfile` and `:certfile` expect an absolute path to the key
# and cert in disk or a relative path inside priv, for example
# "priv/ssl/server.key". For all supported SSL configuration
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
#
# We also recommend setting `force_ssl` in your endpoint, ensuring
# no data is ever sent via http, always redirecting to https:
#
# config :hello, HelloWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
# ## Using releases (Elixir v1.9+)
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint:
#
#
# Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information.
# Finally import the config/prod.secret.exs which loads secrets
# and configuration from environment variables.
config :hello, HelloWeb.Endpoint, server: true
import Config
secret_key_base = System.fetch_env!("SECRET_KEY_BASE")
greeting = System.fetch_env!("GREETING")
application_port = System.fetch_env!("APP_PORT")
config :hello, HelloWeb.Endpoint,
http: [:inet6, port: String.to_integer(application_port)],
secret_key_base: secret_key_base
config :hello,
greeting: greeting
@tlvenn
Copy link

tlvenn commented Oct 9, 2019

When you copy over the necessary application files, I believe you are missing the rel directory.

@scottmessinger
Copy link

One problem I'm running into is the RELEASE_NODE variable that's exported in env.sh.eex isn't passed between the build stages. At least, that's what appears be going on. Anyone tried using a multi-stage build and running Elixir distributed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment