Deploying Phoenix app with mix releases
When we start to materialize our app from an idea into code, in the first days, weeks, and months, we create, develop and test our app locally, on our machine.
Inevitably, our development will result in a semi-ready or fully developed application, and regardless of whether we build our business application, for a public or private project we will have to package, and deploy Phoenix app somewhere, either we want to release it locally or on some host.
Roadmap:
Today we will answer how to neatly and easily package our Phoenix app into a self-contained release.
We will set up mix release config and then go through other steps needed for the deployment process to succeed.
Resulting in ready-to-be-dropped into production machine package.
Let's start with a little introduction.
How we used to generate apps (most of the time)
Let's start with a little introduction. Before Elixir version 1.9+, the most reliable way to make a standalone executable from the codebase, dependencies, Erlang VM, was a library called Distillery.
Distillery your mix project and produced Erlang/OTP release.
Goodbye Distillery
With Elixir 1.9 release, most functionality of Distillery was merged into Mix itself, and the library was deprecated. If you used Distillery for your releases before, the transition to mix releases shouldn't be dramatic, although, there are some minor differences, be aware of that.
Welcome mix release
Now, we will explore how to set up and use mix release on the dummy phoenix app, be more than welcome to tag along.
The first step is to use mix command to create a basic project for us:
mix phx.new app
With our app created, you could right now build your release running mix release, output being:
* assembling app-0.1.0 on MIX_ENV=dev
* using config/runtime.exs to configure the release at runtime
Release created at _build/dev/rel/app
# To start your system
_build/dev/rel/app/bin/app start
Once the release is running:
# To connect to it remotely
_build/dev/rel/app/bin/app remote
# To stop it gracefully (you may also send SIGINT/SIGTERM)
_build/dev/rel/app/bin/app stop
To list all commands:
_build/dev/rel/app/bin/app
This command compiled release and saved it under the path: _build/[ENV]/rel/[app name] (ENV depends on which environment you invoked mix release, and app name is just the name of your app, so in our example dev and app)
There reside all files needed to start our app, often we are only interested in _build/dev/rel/app/bin/app
, because it holds all commands needed to start, connect to, stop our application, and even invoke functions using eval (for list of all commands refer to output above)
If you open _build/dev/rel/app/bin/
folder you can see that by default there is also a .bat file to control our app in windows environment. Of course, you could change that behavior, but how?
Configuring mix releases
To configure how mix release behaves we must go into mix.exs file and then we will focus on the project section.
def project do
[
app: :app,
version: "0.1.0",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
Here we can add a releases key and in this key will reside all of the configuration for mix release. To be more specific, under your release name, your config will be staying.
You can have many different releases if you want to.
For example, let's add a basic config for production that removes executables for windows and keeps some information about BEAM files, we will call this release prod.
releases: [
prod: [
include_executables_for: [:unix],
strip_beams: [keep: ["Docs", "Dbgi"]]
]
]
Cool, now to use this config for our release we simply call mix release with the name of desired configuration: prod.
So:
mix release prod
There are of course many other options, if you are interested, please refer to:
https://hexdocs.pm/mix/main/Mix.Tasks.Release.html
A few important notes before we can proceed with deployment
We will release locally but the steps I will show you could be easily packed into some build script for the auto-deployment process on a remote machine.
There is one important matter I need to mention, when you want to deploy a release, it requires the same operating system distribution and version as the one that the release was built on.
One more thing before we start, in Elixir 1.11, config/runtime.exs file was introduced.
This configs file's purpose is to provide application configuration at runtime(meaning after compilation of our project), as opposed to compile time config files.
A few other important aspects of this file is that it's running in all
environments and that config/runtime.exs is meant to run in an environment without Mix, so functions you would use to set application variables(such as Mix.env() or Mix.target() )are not available. Instead, they were added to the Config module.
The deployment
The first step is to take care of environment variables.
For our case, we only need to set DATABASE_URL (I believe it is self-explanatory) and SECRET_KEY_BASE (if you don't know, this secret is used by Endpoint configuration, it's a base to generate secrets for encrypting and signing data)
You can generate a secret using:
mix phx.gen.secret
Now, either you can manually type:
export SECRET_KEY_BASE=REALLY_LONG_SECRET
export DATABASE_URL=ecto://USER:PASS@HOST/database
into console or paste it into a .env file in the main directory of our project then type source .env
We should not forget to prepare dependencies for our project, we need to fetch them(only those that are needed for production)
and then compile them.
mix deps.get --only prod
MIX_ENV=prod mix compile
And also compile the app's assets
MIX_ENV=prod mix assets.deploy
Finally, you could now run mix release and start release on the local machine or ship the package to the target machine and run it there, but a few more things could help you in your releases.
mix phx.gen.release command generates three files,two files that helps us in running migration inside the release:
lib/app_name/release.ex - this module contains tasks to run migrations inside a release
rel/overlays/bin/migrate - and this one is for invoking our migrations using the Release module
third file: rel/overlays/bin/server is for running phoenix server inside a release with an environment variable: PHX_SERVER=true.
If you wonder what is a overlays folder, it is a folder where its content will be copied into every release, so we don't have to manually copy some files that we want in every release, for example our scripts to run the web server and migrations as we saw above or Dockerfile
so we can containerize our project, speaking of docker.
phx.gen.release has the option to make for us Dockerfile
and dockerignore.
This Dockerfile
contains all setup needed to produce the release and containerize it so we can have seamless deployment in docker container.
Closing thoughts
No complex configuration, no hours of wondering how to set up our project, just one small config and we are good to deploy elixir app and manage our package with Mix Releases. Happy deploying.
FAQ
What is Mix Release in Phoenix app development?
Mix Release is a feature integrated into Mix, Elixir's build tool, used for packaging Phoenix applications into self-contained executables including the codebase, dependencies, and the Erlang VM, facilitating easier deployment and management of Elixir applications.
How does Mix Release improve upon the older Distillery approach?
Mix Release simplifies the deployment process by incorporating the functionalities previously provided by Distillery directly into Mix. This change, introduced in Elixir 1.9, streamlines the creation of Elixir app releases without needing external libraries.
How can you set up a Mix Release for a Phoenix application?
Setting up a Mix Release involves initializing a new project with mix phx.new
, configuring release settings in the mix.exs
file, and then creating the release with the mix release
command, adjusting settings for different environments as necessary.
What configurations are necessary for a production Mix Release?
For a production release, configurations may include setting the :prod
environment, compiling assets, and customizing the release in the mix.exs
file to include or exclude certain executables and files.
What are the requirements for deploying a Mix Release on a target machine?
The target machine for deploying a Mix Release must have the same operating system distribution and version as the machine where the release was built. Additionally, environment variables like DATABASE_URL
and SECRET_KEY_BASE
should be set up properly.
What is the role of config/runtime.exs
in Mix Releases?
config/runtime.exs
is used for configuring application settings at runtime, providing a way to manage configurations that differ between environments without needing to recompile the application.
How can you manage migrations and server startup within a Mix Release?
The mix phx.gen.release
command generates scripts for managing database migrations and server startup within the release, facilitating seamless deployment processes.
What are the advantages of using Docker with Mix Releases?
Using Docker with Mix Releases allows for containerizing the Phoenix application, ensuring consistent environments across development and production, and simplifying the deployment process with Docker's infrastructure.