Building an OTP release for ejabberd with Elixir mix
ejabberd is an ubiquitous Erlang application that is widely available in Linux distributions. For that reason, it needs to rely on the de facto Linux build tools like autotools to make integration very easy for Linux and FreeBSD packagers.
However, it does not mean that ejabberd does not play well with the standard Erlang release approach.
ejabberd is fully OTP and release compliant. OTP is the standard “pattern” to build Erlang applications and ejabberd rely on them. Moreoever, it fully supports the Erlang release mechanism. A release in Erlang is a way to prepare a standalone package of a system composed of several applications. A release includes version of the Erlang VM (Beam) and all the needed dependencies, for easy deployment. A release is also a way to perform upgrade of a live running system (and downgrade if you would like to rollback a deployed change).
In this tutorial, I will show how to build a standalone Erlang release for ejabberd and how to deploy and upgrade new code in a new release without stopping the service.
To demonstrate the feature, I will rely on Elixir toolchain to build an ejabberd release, and more specifically mix
and exrm
tools.
Here is the full video tutorial, but you can read on for complete written, step-by-step explanation:
Prerequisites
As a prerequisite, you need to have Erlang R18+ and Elixir 1.0.5+ available on your machine, as well as standard GNU build tools. You can read more about ejabberd dependencies on ejabberd documentation site: [https://docs.ejabberd.im/admin/guide/installation/#installing-ejabberd-from-source-code](Installing ejabberd from source code).
Build ejabberd with Elixir mix
First, you need to checkout ejabberd from source, from ProcessOne Github:
(mkdir ejabberd-demo1; mkdir ejabberd-demo1/deploy; cd ejabberd-demo1; git clone https://github.com/processone/ejabberd.git)
Second step is to download ejabberd dependencies and to build the software. It can be done automatically with mix:
cd ejabberd-demo1/ejabberd
mix do deps.get, compile
Once this is done, we can prepare an ejabberd OTP release with the following command:
MIX_ENV=prod mix release
You can now unpack the release you want to deploy using the package release file. It is not recommended to start ejabberd from the release directory directly as you can get issue later. I recommand you copy / extract the file rel/ejabberd/releases/15.07.0/ejabberd.tar.gz
to your ejabberd deploy directory:
(mkdir -p deploy/ejabberd; tar zxvf rel/ejabberd/releases/15.07.0/ejabberd.tar.gz -C deploy/ejabberd)
Note that I am deploying inside the same ejabberd directory to avoid cluttering the local drive, but on a real server I expect you will extract the release in a place like for example /app/ejabberd/
or /home/ejabberd/deploy
or anywhere else that suit your taste.
Now, you can start ejabberd from the release directory. But first, you need to add an ejabberd config file. I have prepared a default ejabberd configuration file that you can download from Gist:
(mkdir deploy/ejabberd/config; cd deploy/ejabberd/config; wget https://gist.githubusercontent.com/mremond/383666d563025e86adfe/raw/723dfa50c955c112777f3361b4f2067b76a55d7b/ejabberd.yml)
From that point, you should be able to start ejabberd successfully. You can start ejabberd and keep an Elixir console opened with:
deploy/ejabberd/bin/ejabberd console
From that console, you can now create the user user1@localhost
with password ‘mypass’:
:ejabberd_auth.try_register("user1", "localhost", "mypass")
If you open an XMPP client, you should now be able to connect with those credentials.
ejabberd can be stopped from the console with:
:init.stop()
You can run ejabberd in background with:
deploy/ejabberd/bin/ejabberd start
At this point, you should be able to reconnect from your client.
If you want to deploy this software on your server, you can copy the compressed release package to your server, uncompress it there and run bin/ejabberd start
from the release directory. File should be named: releases/15.07.0/ejabberd.tar.gz
Please note that you need to use the same architecture to build the release than the one you are deploying on. It means if you are deploying on Linux 64-bits, you need to build your service on the same architecture (so, not directly on your OS X laptop, you can use a VM). If you do not do that, the embedded Erlang and ejabberd .so
binaries will not work.
New release / hot code upgrade
Let’s demonstrate how to make a very basic change in the code, prepare a new release and do a live code update on a running server.
Open the following page in your browser: [https://localhost:5280/http-bind]
This is the info page return by the mod\_http\_bind
module. Let’s say we want to replace the string in the code containing “To use HTTP-Bind” with “To use XMPP over BOSH” which sounds more correct.
Open the file src/mod_http_bind.erl
and search for “HTTP-Bind” and replace that string with “XMPP over BOSH”.
As your change is ready to deploy, you are ready to increase project version in mix.exs
. Increment the version number from 15.07.0
to 15.07.1
.
You can now rebuild the project. Compile it to check all is fine:
mix compile
You can prepare a release with the upgrade process:
MIX_ENV=prod mix release
You can now upgrade the live system. To do that, you need to perform the upgrade not from your build structure, but from the actual target deployment directory. exrm
deletes file during the upgrade process that may be used to produce subsequent releases.
So, to upgrade the live production system, you need to do:
Assuming the server is already running and you do not want to interrupt the existing users, you can launch live code upgrade:
deploy/ejabberd/bin/ejabberd upgrade "15.07.1"
Copy the new release file:
tar zxvf rel/ejabberd/releases/15.07.1/ejabberd.tar.gz -C deploy/ejabberd
Create new dir for release in your original deploy:
mkdir -p deploy/ejabberd/releases/15.07.1
ejabberd should upgrade just fine. If you reload the page [https://localhost:5280/http-bind] you should now clearly see your updated text. Note, that only the needed module were reload and no client have been disconnected. The upgrade has been fully live.
However, be careful. Not all upgrade paths are that simple. Depending on how deep your change goes into the internal of ejabberd, preparing the upgrade process maybe become a project in itself, requiring skillfull work.
Conclusion
As you have seen, ejabberd is:
- Able to integrate well with Linux distribution build process
- Erlang/OTP compliant
- Compliant with Erlang release mechanism and standard approach for hot code upgrade.