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:

  1. Create new dir for release in your original deploy:

    mkdir -p deploy/ejabberd/releases/15.07.1
    
  2. Copy the new release file:

    tar zxvf rel/ejabberd/releases/15.07.1/ejabberd.tar.gz  -C deploy/ejabberd
    
  3. 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"
    

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.

Let us know what you think 💬


3 thoughts on “Building an OTP release for ejabberd with Elixir mix

  1. I’m using the Embedded Ejabberd in an Elixir Application. When I try to release the version via MIX_ENV=prod mix release, I get this Error:

    ** (Mix) :p1_utils is listed both as a regular application and as an included application

    Ejabberd 20.7
    Elixir 10.4
    Erlang/OTP 23

Leave a Comment


This site uses Akismet to reduce spam. Learn how your comment data is processed.