View Source Docker Support
edeliver also provides support for docker containers. It provides
- building in a docker container, which makes the need of a build host obsolete and …
- building a docker image which contains the release and can run the release as a docker container.
example-config
Example Config
#./deliver/config
# Enable building in a docker container
BUILD_HOST="docker"
# Use this image to build the release. It must contain
# all build tools required to compile and build the release
DOCKER_BUILD_IMAGE="elixir:1.13.3" # default
# Enable embedding the release in a docker image. The
# release will be embedded into a docker image with this
# name and the release version as tag. Use the `--push` flag
# as edeliver command line arg or push it manually with
# `docker push edeliver/echo-server:<version>`.
RELEASE_STORE="docker://edeliver/echo-server"
# If the release image should be pushed to the Google Container Registry,
# access rights can be granted with a Bearer token generated
# like this:
if [[ "$RELEASE_STORE" = *gcr.io* ]]; then
DOCKER_REGISTRY_TOKEN="$(gcloud auth print-access-token || :)"
else
# If using Docker Hub, the Bearer token will be be fetched
# by edeliver with the private Docker Hub access token:
DOCKER_HUB_ACCESS_TOKEN="****"
fi
# The image which is used to create the final release image
# specified in RELEASE_STORE which can be deployed. It should
# contain anything which is required during runtime. The default
# image just contains open ssl and expects that the erts is
# embedded into the release.
DOCKER_RELEASE_BASE_IMAGE="edeliver/release-base:1.0" # default
# Runtime configuration if the default edeliver container start
# script is used which is deployed on `edeliver deploy release`
# command
# Forward port 8080 from the host to the container or any other
# port(s) your app exposes
DOCKER_OPTS="--publish 8080:8080"
# Links or actually mounts the vm.args file from the (deploy) host
# into the container at /$APP/releases/$VERSION/vm.args
# It configures the erlang / elixir node and could load e.g. additional
# config from the host with --config /etc/echo-server/sys.config
# In that case /etc/echo-server/ should also be mounted into the container,
# see below ↓
LINK_VM_ARGS="/etc/echo-server/vm.args"
# mount also configs into the container
DOCKER_OPTS+=" --mount type=bind,source=/etc/echo-server,target=/etc/echo-server"
building-in-a-docker-container
Building in a Docker Container
To build the release in a docker container (1.), BUILD_HOST="docker"
must be set and optionally the DOCKER_BUILD_IMAGE
which will be pulled and used to build the release, similar to a build host and should contain all tools needed. elixir:1.13.3 is the default DOCKER_BUILD_IMAGE
but you could also use existing extended images, e.g. to build a phoenix app or build an own docker image containing everything required by your app.
building-a-docker-image
Building a Docker Image
To also embed the built release into a docker image (2.), edeliver needs to be configured to use a docker registry as release store by setting it e.g. like this in the .deliver/config
file: RELEASE_STORE="docker://<account-name>/<release-image-name>
, e.g. docker://edeliver/echo-server
or docker://eu.gcr.io/edeliver/echo-server
.
Edeliver then pulls a (runtime) base image from DOCKER_RELEASE_BASE_IMAGE
(which defaults to edeliver/release-base:1.0), copies the release into it and commits a new docker image as /<account-name>/<release-image-name>:<release-version>-<git-rev>
, e.g. edeliver/echo-server:1.0-f5ddf03
which can be pushed manually to the registry or automatically with the --push
flag. This is the image which can be deployed and started on the staging or production hosts. Ensure the docker daemon is authenticated at the (private) registry by running docker login
before or gcloud auth login
etc.
Since it is recommended to embed the erlang runtime into the release, the DOCKER_RELEASE_BASE_IMAGE
needs to contain only libraries required during runtime, e.g. like the default image provided by edeliver:
FROM ubuntu:focal-20220113
RUN apt update \
&& apt install -y libssl1.1 locales \
&& apt clean
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LC_ALL="en_US.UTF-8" LANG="en_US.UTF-8" LANGUAGE="en_US:en"
deploying-a-docker-image
Deploying a Docker Image
./edeliver deploy release to <staging|production> --version=<release-version>
deploys the release to a staging or production host by pulling the image with the release version as tag and extracting a script from the path /$APP/bin/start_container
in the container to $DELIVER_TO/bin/$APP
on the host. If no such script is embedded, edeliver copies its own generic script there. It can also be used as template and when embedding a modified extended version. The script location in the container can be changed with CONTAINER_START_SCRIPT
.
When extracting the script or copying the default script edeliver pins the deployed version by replacing the string {{edeliver-version}}
with the deployed version, {{edeliver-docker-image}}
with the image name from the RELEASE_STORE
and other tags, like {{edeliver-app}}
with $APP
and {{edeliver-docker-opts}}
with DOCKER_OPTS
from the .deliver/config
. They can be used e.g. to expose ports used by the release from inside of the container to the host, e.g. DOCKER_OPTS="--publish 8080"
.
It is required, that the deploy host is also authenticated at the private docker registry. To list available tags / versions you can run ./edeliver show releases
. For a private registry DOCKER_REGISTRY_TOKEN
must be set in the .deliver/config
because listing tags requires authentication at the docker registry directly because listing is not supported by the docker daemon. For gcloud you can set it e.g. like this: DOCKER_REGISTRY_TOKEN="$(gcloud auth print-access-token || :)"
, for DockerHub you can set the DOCKER_HUB_ACCESS_TOKEN
and edeliver will generate the token for you. For any other registry you need to fetch or set the DOCKER_REGISTRY_TOKEN
used as Bearer token in your config yourself.
running-a-docker-image
Running a Docker Image
The extracted script at $DELIVER_TO/bin/$APP
can be used to start and control the release as usual, e.g. to start the container in the foreground run $DELIVER_TO/bin/$APP console
or to connect to a running node $DELIVER_TO/bin/$APP remote_console
. This script configures the container and the erlang / elixir node to be able to run in a container and to connect to a running node in the container.
To achieve this, edeliver starts the release epmd-less and with an own epmd module. Ensure edeliver is embedded as application in your release to ensure it is available when the release boots.
By default a node started by edeliver in a container binds to a fixed distribution port set as ERL_DIST_PORT
env, by default 4321
. Known nodes which are configured to run on a different port (e.g. because they run on the same host) can be configured by the nodes
edeliver
application config e.g. in the sys.config
file of the release or be passed space-separated in the EDELIVER_NODES
environment variable. The port can be specified separated by a :
if it does not listen on the default ERL_DIST_PORT
or DEFAULT_DIST_PORT
respectively which precedes the latter.
e.g.
EDELIVER_NODES="foo@bar.local baz@bar.local:4323` bin/my-app console
Starts a my-app node which can connect to foo@bar.local
at distribution port 4321
and to
node baz@bar.local
at port 4323
. Same can be achieved when setting it in the sys.config
[{kernel, [{net_ticktime. 20}, …]},
{edeliver, [{nodes, ['foo@bar.local', 'baz@bar.local:4323']},
…]}]
The docker container listens by default on 127.0.0.1
for connections from other nodes. To connect nodes from different hosts, you can bind to the internal IP of the host by setting the INTERNAL_INTERFACE
environment variable, e.g. in /etc/environment
on the host.
distillery-considerations
Distillery Considerations
When using distillery to build a docker release with edeliver, you must use long node names while edeliver will configre distillery to replace the $HOST
env in the vm.args
file, which should look like this:
-name my_app@${HOST_NAME}
+K true
#…
Ensure edeliver is added as dependency and included into the release:
# ./mix.exs
def application do
[applications: [:sasl, :edeliver, …],
mod: {:my_app, []}]
end
…
defp deps do
[…
{:distillery, "~> 2.0"},
{:edeliver, "~> 1.9.2"}]
end
rebar3-considerations
rebar3 Considerations
When using rebar3 to build a docker release with edeliver, you can use short node names but need to configure the inet_dist_use_interface
in your vm.args.src
file, while edeliver will configre rebar3 to replace the $INET_DIST_USE_INTERFACE
env in the vm.args.src
file. It should look like this:
-sname eco
-kernel inet_dist_use_interface ${INET_DIST_USE_INTERFACE}
+K true
#…
Using a vm.args.src
file which replaces env vars is enabled in the rebar3.config
like this:
{relx, [{release, { my_app, "0.1.0" }, [sasl, edeliver, …]},
…
{vm_args_src, "./config/vm.args.src"},
…
{include_erts, false},
{extended_start_script, true}]
}.
mix-considerations
mix Considerations
When using mix to build a docker release with edeliver, just ensure that edeliver is added as dependency and included into the release and distillery as build time dependency which is required to build edeliver, but should not be included into the release:
# ./mix.exs
def application do
[applications: [:sasl, :edeliver, …],
mod: {:my_app, []}]
end
…
defp deps do
[…
{:distillery, "~> 2.0", runtime: false},
{:edeliver, "~> 1.9.2"}]
end