We’re going to learn how to deploy a Phoenix project using an Elixir release (available in Elixir 1.9+). Elixir Releases allow us to package our Elixir application to run in production. A release packages your Phoenix application into a self-contained directory that includes the Erlang VM, Elixir, all of your code and dependencies. This package can then be dropped into a production machine.
We’ll go through the steps to build a Phoenix project with a Postgres database using Elixir releases.
Overview
Here are the steps we’ll cover to deploy the project:
- Create new Elixir Phoenix project
- Add users resource with Phoenix generator
- Configure your Elixir release
- Deploy your Elixir Release Locally
Prerequisites
To follow this guide, make sure you have at least the following applications installed on your machine. In the brackets are the versions with which this guide was written.
- Elixir (1.11.4-otp-24)
- Erlang (OTP 24)
- Phoenix (1.5.12)
- Node.js with npm (11.6.0)
- Docker (20.10.7)
Make sure to install at least Elixir 1.9. I like to use asdf to manage my Erlang and Elixir versions.
If you run into problems, the finished project is available on GitHub as StakNine Elixir Release. Each section is a separate commit.
Create new Elixir Phoenix project
To begin, I’m going to call this project DockerPhx because we are going to use Docker later, so use the command line to create a new Phoenix project:
$ mix phx.new docker_phx
## output ##
Fetch and install dependencies? [Yn] y
* running mix deps.get
* running cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development
* running mix deps.compile
We are almost there! The following steps are missing:
$ cd docker_phx
Then configure your database in config/dev.exs and run:
$ mix ecto.create
Start your Phoenix app with:
$ mix phx.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phx.server
Change into the docker_phx directory, create your database and test your app:
$ cd docker_phx
docker_phx $ mix ecto.create
Compiling 13 files (.ex)
Generated docker_phx app
The database for DockerPhx.Repo has been created
docker_phx $ mix phx.server
[info] Running DockerPhxWeb.Endpoint with cowboy 2.7.0 at 0.0.0.0:4000 (http)
[info] Access DockerPhxWeb.Endpoint at http://localhost:4000
Now visit http://localhost:4000
and you should see the Welcome to Phoenix! page.
Add users resource with Phoenix generator
Now we want to add users to the project with the phx.gen html
task, following the Phoenix Contexts guide.
docker_phx $ mix phx.gen.html Accounts User users name:string \
username:string:unique
* creating files...
Add the resource to your browser scope in lib/docker_phx_web/router.ex:
resources "/users", UserController
Remember to update your repository by running migrations:
$ mix ecto.migrate
Follow the directions to add the resource to the lib/docker_phx_web/router.ex
file and migrate the database with mix ecto.migrate
.
Now start your server with mix phx.server
and visit http://localhost:4000/users
on your local machine to see the index of users. Add a new user to test out the database.
We’ll use this basic project to test our database is migrated and our app is deployed properly.
Configure your Elixir release
A release consists of your application code, all of its dependencies, plus the whole Erlang Virtual Machine and runtime. Once a release is assembled, it can be packaged and deployed to a target as long as the target runs on the same operating system distribution and version as the machine that assembled the release.
A release does not require the source code to be included in your production artifacts. All of the code is precompiled and packaged.
To build, configure and start your release, we’re going to borrow the steps from the Phoenix Deploying with Releases guide to set up Mix releases.
Releases, assemble!
First set the following environment variables:
docker_phx $ mix phx.gen.secret
REALLY_LONG_SECRET
docker_phx $ export SECRET_KEY_BASE=REALLY_LONG_SECRET
docker_phx $ export DATABASE_URL=postgres://postgres:postgres@localhost:5432/docker_phx_dev
Then load dependencies to compile code and assets:
# Initial setup
$ mix deps.get --only prod
$ MIX_ENV=prod mix compile
# Compile assets
$ npm run deploy --prefix ./assets
$ mix phx.digest
Update the config file config/prod.secret.exs
with the following (you may just need to uncomment a line):
config :docker_phx, DockerPhx.Endpoint, server: true
Runtime configuration
Update the project to use runtime configuration for environment variables with the steps below. With runtime configuration, you are able to store environment variables in an external configuration system in an actual production setup.
- Rename
config/prod.secret.exs
environment file toconfig/releases.exs
- Change
use Mix.Config
inside the newconfig/releases.exs
file toimport Config
. - Change
config/prod.exs
to no longer callimport_config "prod.secret.exs"
at the bottom.
Ecto migrations and custom commands
Create a new release commands file in your application, lib/docker_phx/release.ex
, with the following:
defmodule DockerPhx.Release do
@app :docker_phx
def migrate do
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
defp repos do
Application.load(@app)
Application.fetch_env!(@app, :ecto_repos)
end
end
If you are using the file as a template, you only need to change the first two lines.
Deploy Your Elixir Release Locally
Once you’ve completed those sections, you should be able to test your app with the following commands to start building releases.
Drop the existing database and create a new database, so you can test the release command.
docker_phx $ mix ecto.drop
The database for DockerPhx.Repo has been dropped
docker_phx $ mix ecto.create
The database for DockerPhx.Repo has been created
Then run the mix command to build the release with the MIX_ENV=prod mix release
build script.
docker_phx $ MIX_ENV=prod mix release
Compiling 18 files (.ex)
Generated docker_phx app
* assembling docker_phx-0.1.0 on MIX_ENV=prod
* using config/releases.exs to configure the release at runtime
Release created at _build/prod/rel/docker_phx!
# To start your system
_build/prod/rel/docker_phx/bin/docker_phx start
Once the release is running:
# To connect to it remotely
_build/prod/rel/docker_phx/bin/docker_phx remote
# To stop it gracefully (you may also send SIGINT/SIGTERM)
_build/prod/rel/docker_phx/bin/docker_phx stop
To list all commands:
_build/prod/rel/docker_phx/bin/docker_phx
Migrate your database
docker_phx $ _build/prod/rel/docker_phx/bin/docker_phx eval "DockerPhx.Release.migrate"
19:13:05.601 [info] == Running 20200229181048 DockerPhx.Repo.Migrations.CreateUsers.change/0 forward
19:13:05.604 [info] create table users
19:13:05.676 [info] create index users_username_index
19:13:05.699 [info] == Migrated 20200229181048 in 0.0s
Start your application.
docker_phx $ _build/prod/rel/docker_phx/bin/docker_phx start
19:15:07.911 [info] Running DockerPhxWeb.Endpoint with cowboy 2.7.0 at :::4000 (http)
19:15:07.913 [info] Access DockerPhxWeb.Endpoint at http://example.com
Now you should be able to visit http://localhost:4000/users
on your local machine to see the index of users. You can add a user again to test out the site is working properly.
Conclusion
Congratulations! You’ve learned how to build an Elixir releases to package your Phoenix application to include the Erlang VM, Elixir, all of your code and dependencies. You can use the release in your deployment process when deploying your Elixir apps to a production machine.
Next learn how to Use Docker to Deploy Your Elixir App Anywhere!