Skip to content

Instantly share code, notes, and snippets.

@nirev
Last active June 30, 2020 14:03
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nirev/d5f2e3e9245cf17a07da7e37a7ed787d to your computer and use it in GitHub Desktop.
Save nirev/d5f2e3e9245cf17a07da7e37a7ed787d to your computer and use it in GitHub Desktop.
Elixir docker deployment
ARG OTP_VERSION=22.0
##################################################
# Base - setup project and docker cache for build
FROM erlang:${OTP_VERSION}-alpine as base
# elixir expects utf8.
ENV ELIXIR_VERSION="v1.9.1" \
LANG=C.UTF-8
RUN set -xe \
&& ELIXIR_DOWNLOAD_URL="https://github.com/elixir-lang/elixir/archive/${ELIXIR_VERSION}.tar.gz" \
&& ELIXIR_DOWNLOAD_SHA256="94daa716abbd4493405fb2032514195077ac7bc73dc2999922f13c7d8ea58777" \
&& buildDeps=' \
ca-certificates \
curl \
make \
' \
&& apk add --no-cache --virtual .build-deps $buildDeps \
&& 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 \
&& apk del .build-deps
# Install building packages
RUN apk --no-cache add git
RUN mix do local.hex --force, local.rebar --force
WORKDIR /build
# Cache dependencies
COPY ./mix.* ./
RUN mix deps.get
# Cache configs
COPY ./config ./config
#################################################
# Builder - stage for running lint, test and dev
FROM base as builder
WORKDIR /build
COPY . .
RUN rm -rf ./_build
##########################################
# Release - builds release for production
FROM builder as release
ENV MIX_ENV prod
WORKDIR /build
RUN mix do phx.digest, release
#######################################
# Script runner - minimal script runner environment
FROM alpine:3.9 as runner
RUN apk add --update --no-cache bash openssl curl
WORKDIR /app
COPY --from=release /build/_build/prod/rel/myapp ./
RUN chown -R nobody: /app
USER nobody
#######################################
# Runtime - minimal production runtime
FROM runner as runtime
# Set APP_VERSION at last, to reuse cached layers
ARG APP_VERSION
ENV APP_VERSION $APP_VERSION
ENV PORT 4040
EXPOSE $PORT
# Set release binary as entrypoint, no shell access
ENTRYPOINT ["/app/bin/myapp"]
CMD ["myapp"]
setup:
addons:
- plan: heroku-postgresql
config:
PORT: 80
build:
docker:
web: Dockerfile
release:
dockerfile: Dockerfile
target: runner
release:
image: release
command:
- /app/bin/myapp eval 'MyApp.ReleaseTasks.migrate()'
defmodule MyApp.ReleaseTasks do
require Logger
@repo_apps [
:crypto,
:ssl,
:postgrex,
:ecto_sql
]
@repos Application.get_env(:my_app, :ecto_repos, [])
def migrate(args \\ []) do
{:ok, _} = Application.ensure_all_started(:logger)
Logger.info("[task] running migrate")
start_repo()
run_migrations(args)
Logger.info("[task] finished migrate")
stop()
end
defp start_repo() do
IO.puts("Starting dependencies...")
Enum.each(@repo_apps, fn app ->
{:ok, _} = Application.ensure_all_started(app)
end)
IO.puts("Starting repos...")
:ok = Application.load(:my_app)
Enum.each(@repos, fn repo ->
{:ok, _} = repo.start_link(pool_size: 2)
end)
end
defp run_migrations(args) do
Enum.each(@repos, fn repo ->
app = Keyword.get(repo.config(), :otp_app)
IO.puts("Running migrations for #{app}")
case args do
["--step", n] -> migrate(repo, :up, step: String.to_integer(n))
["-n", n] -> migrate(repo, :up, step: String.to_integer(n))
["--to", to] -> migrate(repo, :up, to: to)
["--all"] -> migrate(repo, :up, all: true)
[] -> migrate(repo, :up, all: true)
end
end)
end
defp migrate(repo, direction, opts) do
migrations_path = priv_path_for(repo, "migrations")
Ecto.Migrator.run(repo, migrations_path, direction, opts)
end
defp priv_path_for(repo, filename) do
app = Keyword.get(repo.config(), :otp_app)
priv_dir = Application.app_dir(app, "priv")
Path.join([priv_dir, "repo", filename])
end
defp stop() do
IO.puts("Stopping...")
:init.stop()
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment