Ease of deployment is one of the things I seriously consider when evaluating technology solutions.
In this post, a modified version of the Elixir getting started echo server will be installed as a
FreeBSD service. There are three goals.
The app needs to be able to be rebuilt and the service restarted to reflect changes on a development machine.
The service needs to automatically start when the machine is booted.
The service sould work like any other service.
The steps are a little involved, but ultimately straightforward.
Software Versions
Instructions
elixir needs to be installed. The tooling to install dependencies for elixir apps comes with the port.
First, start a new project for the echo service.
Next, add a modified version of the echo server from the Elixir getting started section.
This version loads the port from environment variables or the app configuration environment.
The default fallback is port 4040. It also gracefully handles closed sockets.
The code goes in lib/echo_elixir.ex.
Install exrm and build a release. This will create the rel/ directory.
The rc script will use environment variable knobs to configure the app.
Note that the RELX_REPLACE_OS_VARS=true environment variable needs to be defined to use environment variables for dynamic configuration.
The vm.args file is primarily used to configure the erlang VM.
It can also be used to define application configure parameters.
Application configuration parameters defined in this file can be passed into the program as atoms or integers.
Add the following to rel/vm.args.
Alternatively, sys.config can be used to pass in application configuration parameters.
In this file, application configuration parameters defined with environment variables must be strings.
Pass the port setting in as above or add the following to rel/sys.config.
The app module was written to work with either solution.
Adding both files will not break anything.
Build a release with the configuration files and do the initial install.
An rc script defines the the service.
elixir_echo_run() is called from the other functions.
It configures and calls the release.
HOME is set to the installation directory to force the erlang cookie file to be written there regardless of elixir_echo_user setting.
elixir_echo_status() echoes a user friendly message if the release can be pinged.
Add shutdown to the keyword list if the service needs to gracefull shutdown when the machine restarts.
The rest is standard rc configuration.
Add the rc script to /usr/local/etc/rc.d/elixir_echo
Enable and configure the service in /etc/rc.conf
The service can now be started. If the service is enabled, it will automatically start when the machine boots.
Optional: Adding a Release to the Systemwide Path
Adding a release to the systemwide path is not necessary, but it can be convenient.
The pass through script can be pointed at the development install instead of the service install if you want to build with exrm mix release –dev.
Create a directory for the convenience pass through script.
NODE_NAME and COOKIE need default values because vm.args has no useful default fallbacks.
PORT has a fallback.
Add the script to /usr/local/opt/bin/elixir_echo
Make the script executable.
Add /usr/local/opt/bin to the global path in /etc/profile for sh.
Add /usr/local/opt/bin to the global path in /etc/csh.cshrc for csh.
Consider updating the root path in /root/.cshrc.
Update the path in the current shell if necessary.
Fix permissions if you want to be able to run as any user. This has security implications.
It may make more sense to point the script at the development release if it is being used as a development convenience.
The release can now be conveniently controlled.
Setup Complete
Switch from root to a normal user.
Updating
Casual updates on a development machine can be performed as follows.
Troubleshooting
If configuration looks like it should be working, but nothing changes, try deleting the running-config directory.
Sometimes rebooting fixes problems, like killing zombie nodes with strange default names and cookie values.
What Next?
Consider looking into edeliver for deployment.
“edeliver is based on deliver and provides a bash script to build and deploy
Elixir and Erlang applications and perform hot-code upgrades.”