Building Releases with Distillery
Seems like just running the app with mix is probably fine for now, but will make using a lot of the BEAM hard/impossible later. Also, the project has multiple apps, so making different builds for each seems like it might be a good idea.
Seems like just running the app with mix is probably fine for now, but will make using a lot of the BEAM hard/impossible later. Also, the project has multiple apps, so making different builds for each seems like it might be a good idea.
This is part of a larger set of posts, see Deploying Elixir Umbrella Apps for an overview.
Setup & Building
One of the issues with Distillery is ENV variables. V2 has made some
good progress in fixing this, but does require setting up configs a
bit differently. I followed the recommendations in the docs which
basically require a config.exs file with the runtime values injected
with System.get_env
.
Distillery Intro and Distillery Docker helped get everything going.
All the Distillery is setup in a rel/
directory.
rel
├── commands
│ ├── migrate.sh
│ └── seed.sh
├── config
│ └── config.exs
├── config.exs
└── plugins
We'll look at the commands directory later.
The config/config.exs
is the runtime config file for all apps
that have runtime configs.
use Mix.Config
port = String.to_integer(System.get_env("PORT") || "4000")
config :company, Company.Repo,
url: System.get_env("DATABASE_URL"),
database: "",
ssl: true,
pool_size: 15
config :company_admin, CompanyAdmin.Endpoint,
http: [port: port],
url: [host: System.get_env("HOSTNAME"), port: port],
root: ".",
secret_key_base: System.get_env("SECRET_KEY_BASE")
config :company_api, CompanyApi.Endpoint,
http: [port: port],
url: [host: System.get_env("HOSTNAME"), port: port],
root: ".",
secret_key_base: System.get_env("SECRET_KEY_BASE")
The use Mix.Config
is important!
Distillery Config
The config.exs
is for Distillery. It's pretty much the template from the
docs. The Mix.Releases.Config.Providers.Elixir
is what allows the use of
the ENV variables.
I have two releases setup, one for the Admin and one for the Web. This does add some complications, but nothing too bad.
# Import all plugins from `rel/plugins`
# They can then be used by adding `plugin MyPlugin` to
# either an environment, or release definition, where
# `MyPlugin` is the name of the plugin module.
~w(rel plugins *.exs)
|> Path.join()
|> Path.wildcard()
|> Enum.map(&Code.eval_file(&1))
use Mix.Releases.Config,
# This sets the default release built by `mix release`
default_release: :default,
# This sets the default environment used by `mix release`
default_environment: Mix.env()
# For a full list of config options for both releases
# and environments, visit https://hexdocs.pm/distillery/config/distillery.html
# You may define one or more environments in this file,
# an environment's settings will override those of a release
# when building in that environment, this combination of release
# and environment configuration is called a profile
environment :dev do
# If you are running Phoenix, you should make sure that
# server: true is set and the code reloader is disabled,
# even in dev mode.
# It is recommended that you build with MIX_ENV=prod and pass
# the --env flag to Distillery explicitly if you want to use
# dev mode.
set(dev_mode: true)
set(include_erts: false)
set(cookie: :"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
end
environment :prod do
set(include_erts: true)
set(include_src: false)
set(cookie: :"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
set(
config_providers: [
{Mix.Releases.Config.Providers.Elixir, ["${RELEASE_ROOT_DIR}/etc/config.exs"]}
]
)
set(
overlays: [
{:copy, "rel/config/config.exs", "etc/config.exs"}
]
)
end
# You may define one or more releases in this file.
# If you have not set a default release, or selected one
# when running `mix release`, the first release in the file
# will be used by default
release :admin do
set(version: "0.0.1")
set(
applications: [
:runtime_tools,
company: :permanent,
company_admin: :permanent
]
)
set(
commands: [
migrate: "rel/commands/migrate.sh",
seed: "rel/commands/seed.sh"
]
)
end
release :web do
set(version: "0.0.1")
set(
applications: [
:runtime_tools,
fos: :permanent,
company: :permanent,
company_api: :permanent
]
)
set(
commands: [
migrate: "rel/commands/migrate.sh",
seed: "rel/commands/seed.sh"
]
)
end
Commands
Since I'm using Distillery, there isn't the ability to use mix tasks. That's what those commands files are about.
Running Migrations
describes the setup for those. I put the tasks in the main Company
application.
I used this pretty much as is.
- Add the commands to the Distillery config.
- Add the commands shell scripts.
- Add the
ReleaseTasks.ex
module.
Builds
To build a release to run locally you can use mix.
mix release --profile admin:prod
The --profile
is used to build for a specific release and environment.
You need to compile the code and assets first. To see that, checkout the Elixir Deploys with Make
Next Elixir and Docker
References
Webmentions
These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: