Skip to content

Instantly share code, notes, and snippets.

@jbrisbin
Last active October 14, 2020 21:51
Show Gist options
  • Save jbrisbin/34a3055e861cdca1f24da499c0a1f2f6 to your computer and use it in GitHub Desktop.
Save jbrisbin/34a3055e861cdca1f24da499c0a1f2f6 to your computer and use it in GitHub Desktop.
Makefile to build an Elixir mix-based project into a reusable Docker image

Elixir Mix-based Docker Image

This bit of Makefile can be included into your make-based build system for creating a Docker image out of an Elixir project that's built with mix. It mounts the current directory into a Docker container at /usr/src/$APP_NAME (where APP_NAME is either the working directory name or can be overridden), performs a mix release, then copies the resultant rel to /opt/$APP_NAME. The base image is modified to add WORKDIR /opt/$APP_NAME and set the ENTRYPOINT of the image to be /opt/$APP_NAME/bin/$APP_NAME foreground.

Usage

If the current directory has the same name as the app, just run make.

make -f elixir-docker.mk release

You'll see output as the image is built (container ID has been replaced by ... for clarity):

Cleaning myapp_core...
docker exec ... mix clean
Building release...
docker exec ... mix release
Compiling 6 files (.ex)
Generated myapp_core app
==> Assembling release..
==> Building release myapp_core:0.1.0 using environment prod
==> One or more direct or transitive dependencies are missing from
    :applications or :included_applications, they will not be included
    in the release:

    :lager

    This can cause your application to fail at runtime. If you are sure
    that this is not an issue, you may ignore this warning.

==> Including ERTS 8.2 from /usr/lib/erlang/erts-8.2
==> Packaging release..
==> Release successfully built!
    You can run it in one of the following ways:
      Interactive: _build/prod/rel/myapp_core/bin/myapp_core console
      Foreground: _build/prod/rel/myapp_core/bin/myapp_core foreground
      Daemon: _build/prod/rel/myapp_core/bin/myapp_core start
Installing to /opt/myapp_core...
docker exec ... mkdir -p /opt/myapp_core
docker exec ... cp -R _build/prod/rel/myapp_core /opt/myapp_core
Saving changes to container myapp_core...
docker commit --change "WORKDIR /opt/myapp_core" --change "ENTRYPOINT [\"bin/myapp_core\", \"foreground\"]" ... myapp_core
sha256:4b94503183620bfafbac6a244e2cea2c6a734ea2f76f380305eaae072274b9d2
docker rm -f ...
...
WORKDIR = $(realpath .)
APP_NAME ?= $(basename $(WORKDIR))
MIX_ENV ?= prod
ELIXIR_DOCKER_IMAGE ?= jbrisbin/elixir
DOCKER_IMAGE_TAG ?= $(APP_NAME)
.PHONY: start stop build release
start::
$(eval CONTAINER := $(shell docker run -d -t --name $(APP_NAME) --entrypoint /bin/cat -e LANG=en_US.UTF-8 -e MIX_ENV=$(MIX_ENV) -v $(WORKDIR):/usr/src/$(APP_NAME) -w /usr/src/$(APP_NAME) $(ELIXIR_DOCKER_IMAGE)))
build:: start
@echo "Cleaning $(APP_NAME)..."
docker exec $(CONTAINER) mix clean
@echo "Building release..."
docker exec $(CONTAINER) mix release
release:: build
@echo "Installing to /opt/$(APP_NAME)..."
docker exec $(CONTAINER) mkdir -p /opt/$(APP_NAME)
docker exec $(CONTAINER) cp -R _build/prod/rel/$(APP_NAME) /opt/
@echo "Saving changes to container $(APP_NAME)..."
docker commit --change "WORKDIR /opt/$(APP_NAME)" --change "ENTRYPOINT [\"bin/$(APP_NAME)\", \"foreground\"]" $(CONTAINER) $(APP_NAME)
docker rm -f $(CONTAINER)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment