Post navigation

Deploying Elixir / Phoenix App Using Rolling Updates

As discussed in this post we gave rolling updates a shot after trying the releases, this kind of deployment is flexible and fast, so until we really need hot updates we’ll stay there.

There are few things to note though when deploying to production (our Server runs Ubuntu 16.04).

System Service

Though we could just run MIX_ENV=prod PORT=4000 mix phoenix.server or more elaborate MIX_ENV=prod PORT=4000 elixir –detached -S mix do compile, phoenix.server we’d like to go one step further and “supervise” our main process so that it starts and restarts itself on system startup as well as in any possible “things go wrong” scenarios.

Now this one is a little trickier since we (and most examples on the net) always used Upstart services to handle such cases and Ubuntu 16.04 switched to using systemd. systemd is a cool init system, but it differs from Upstart not only syntactically but also logically – It doesn’t have much environment setup as Upstart did, so we have to get our hands a little bit dirtier.

Here is an example of systemd service that manages an elixir app, in Ubuntu 16.04 it would have to be placed in /lib/systemd/system/myservice.service

After setting it up use systemctl enable myservice.service, this must only be done once so that the system creates symlinks to the service file. Without this step everything will work fine but will not be restarted on boot.

Any generic “my app” things like user, group and application path have to be replaced with real stuff. Few other things to note:

Environment=LANG=en_US.UTF-8 this part is important, otherwise Elixir will complain about Erlang nut using utf8, you’d get something like this logged: warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running “locale” in your shell). This issue has to do with systemd being “bare bones”, actually running “locale” will probably show a correct encoding which might create confusion

WorkingDirectory=/var/apps/my-app this makes sure there is a phoenix.server command available

ExecStart=/usr/local/bin/mix phoenix.server systemd has no path environment so we have to use full path to the mix executable. Use whereis mix to find it in your environment

After initial setup you will be able to manage your service just as any other system service:

sudo systemctl status myservice.service

sudo systemctl restart myservice.service

sudo systemctl start myservice.service

sudo systemctl stop myservice.service

systemd’s status will also show latest IO output of your app which is very helpful when debugging the service.

Logs

If you have Phoenix’ default logging to standard output, you can use journalctl to view logs, here are few examples

Nginx proxying

Though not required, using nginx as a proxy makes it easier to “play well” with other parts of the system by using port 80 and not having to run root processes, behind the scenes nginx will use root to set things up and then goes down to its normal user. Since it’s only used as a proxy there is barely an overhead.