Demo: Remote Code Loading

If you’ve come straight to this page, you may want to step back and reference the brief introduction to remote code loading first. Now… On with the demo!

This guide will walk through the Elixir implementation of a basic distributed Hello World slave node.

Setup

For this demo, we are going to set up two separate Digital Ocean servers, put our code on one of them, and then run a distributed application between them.

Digital Ocean Setup

After creating an account with Digital Ocean, make sure you add an SSH keypair to your account.

Then, create two droplets in Digital Ocean (I chose Ubuntu for this demo — but that is not a requirement), and make sure to enable private networking for both of them. Let’s call one the “master” and one the “slave”.

After the droplets are created, take note of their private network IP addresses — this is what you’ll want to use to connect the nodes to each other.

While nodes may communicate over their public IP interfaces, this is not recommended. Communication between nodes using the private networking interface is notably faster and will not count towards your bandwidth costs.

Slave Server Setup

The only thing we need to do for our slave nodes is install Erlang. That’s it! Let’s ssh onto the box we want to use as a slave node and do just that:

ssh root@104.131.164.35 -i ~/.ssh/seanstavro-digitalocean
# Download Erlang Solutions package listings
wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
# Add Erlang Solutions packages to the apt-get package manager
sudo dpkg -i erlang-solutions_1.0_all.deb
apt-get update
# Install Erlang
apt-get install erlang

Master Server Setup

Let’s start off by connecting through ssh onto our “master” server and installing our dependencies. You will need to connect to the public IP address of whichever server you choose to be the master.

ssh root@45.55.202.19 -i ~/.ssh/seanstavro-digitalocean
# Download Erlang Solutions package listings
wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
# Add Erlang Solutions packages to the apt-get package manager
sudo dpkg -i erlang-solutions_1.0_all.deb
apt-get update
# Install Elixir
apt-get install elixir

Next, we need to allow our master server to connect to our slave nodes. This is typically done through rsh (though you can choose an alternative). To do this, we’re going to copy our digital ocean ssh key asid_rsa onto the master box:

scp -i ~/.ssh/seanstavro-digitalocean ~/.ssh/seanstavro-digitalocean root@45.55.202.19:~/.ssh/id_rsa
In a production environment, you should take caution to set up appropriate security permissions, which is beyond the scope of this tutorial.

Next, we’re going to test the connection to the slave node’s private IP address. (It is required that you add the remote server to the known_hostsfile, which is most easily done by simply testing the ssh connection).

ssh root@10.132.162.238
The authenticity of host '10.132.162.238 (10.132.162.238)' can't be established.
ECDSA key fingerprint is a5:55:45:8d:af:6b:27:4b:d7:43:2e:da:de:15:7c:ba.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.132.162.238' (ECDSA) to the list of known hosts.

Wonderful! Now our master node has been shown to be able to connect to our slave node via SSH. Let’s exit the slave server shell and get back to our Master.

HelloMaster

Now that we’ve set our Ubuntu servers up to be able to communicate with one another, the next step is to implement our Elixir applicaton code. For the sake of brevity, I have added a couple basic modules on a public github repo called hello_master which we will use in this demo.

The HelloMaster repository consists of a couple core components:

  • A supervisor responsible for starting an erl_boot_server
  • A very basic GenServer which responds to a :hello message and returns the running node information.
  • A helper module to implement the remote procedures necessary to start and stop a remote node, as we learned about in part 1.

Now, let’s clone the repo and start up an Elixir node.

git clone https://github.com/stavro/hello_master.git
cd hello_master

We need to pay special attention to starting our Erlang VM to ensure that it is started in a distribution-friendly way. Specifically, our node needs to be assigned both a cookie and a name. For convention during this demonstration, I am using the form master@private-ip.

iex --cookie cookie --name master@10.132.162.237 -S mix
Nodes with long names cannot communicate with a node with a short name.
In general, if nodes will only communicate with each other on the same server or local network, feel free to use short names for convenience. However, if you require distributed server communication across a global network, use long names. For more information on setting up a cluster, please reference the Distribunomicon.

Now that we’re inside of our master Erlang VM, starting a slave node on any server which our existing VM can access is as simple as passing in the private IP of that server:

{:ok, server} = HelloMaster.SlaveNode.start("10.132.162.238")

And now finally, let’s invoke the Hello World server running inside the slave node on a remote host:

{:ok, remote_pid} = HelloMaster.SlaveNode.call(server, HelloMaster.Echo, :start_link, [])
HelloWorld.hello(remote_pid)
{:ok, "Hello from slave@10.132.162.238"}

To summarize, we’ve installed Erlang and Elixir on one server, added some of our application code, and enabled an ssh communication channel from our master node to our slave node. Then, through the power of Erlang/OTP, we started a remote Erlang node running our code on a completely separate host.

I hope you enjoyed this journey into Elixir and Erlang slave nodes. Stay tuned for more posts!