een lange titel

Erlang nodes in Docker

Gedistribueerde Erlang nodes zijn ook mogelijk in Docker.

Eigenlijk is Docker helemaal niet nodig als je gedistribueerde Erlang nodes wil maken. Een Erlang node is al een soort container op zich. Maar met de komst van Docker Swarm zou het wel eens interessant kunnen zijn om de Erlang nodes binnen Docker containers te draaien.

Als je een gedistribueerde Erlang applicatie wil uitbaten dan is Docker Swarm een goed hulpmiddel. Elke Erlang node draait dan binnen zijn eigen Docker container en elke Docker container plaatsen we op één Docker node. Deze architectuur heb je nodig als je rekenintensieve Erlang applicaties maakt. Een goed voorbeeld zijn de mierenkoloniealgoritmes.

In deze post is alleen maar getest of je een Erlang ping kan uitvoeren tussen twee Erlang nodes die elk een eigen container draaien. Beide containers draaien op dezelfde host. Voor deze test is een recente Docker versie nodig omdat er docker network wordt gebruikt. Met dit commando kan je eigen virtuele netwerken beheren. Deze netwerken maken de koppeling tussen containers toe.

Na enige testen is het gelukt om in Docker Erlang gedistribueerde nodes met elkaar te koppelen. Elke node draait in een eigen Docker container. De volgende Dockerfile maakt de image.

FROM erlang:19.1.6

RUN apt-get update
RUN apt-get install -y dnsutils

EXPOSE 4000-50000

CMD [erl]

Deze eigen image is nodig. De EXPOSE geeft aan welke poorten binnen deze image toegankelijk moeten zijn. De daemon epmd draait op poort 4369 en elke node krijgt dynamisch een poort toegewezen. Deze poorten zijn niet op voorhand bekend, vandaar de range in de EXPOSE.

Alle Docker commando’s staan in de volgende Makefile.

build:
	docker build -t lrutten/erlang .

network-create:
	docker network create lokaal

network-ls:
	docker network ls

erl1:
	docker -D run --name huis1 -it --rm --dns-search=straat.org --net=lokaal -h huis1 --network-alias=huis1.straat.org lrutten/erlang erl -name huis1@huis1.straat.org -setcookie abc

erl2:
	docker -D run --name huis2 -it --rm --dns-search=straat.org --net=lokaal -h huis2 --network-alias=huis2.straat.org lrutten/erlang erl -name huis2@huis2.straat.org -setcookie abc

bash1:
	docker -D run --name huis1 -it --rm --dns-search=straat.org --net=lokaal -h huis1 --network-alias=huis1.straat.org lrutten/erlang /bin/bash

bash2:
	docker -D run --name huis2 -it --rm --dns-search=straat.org --net=lokaal -h huis2 --network-alias=huis2.straat.org lrutten/erlang /bin/bash

stop1:
	docker stop huis1

stop2:
	docker stop huis2

images:
	docker images

Dit is de werkwijze. Bouw de image.

make build

Maak dan een netwerk:

make network-create

Je kan dat netwerk bekijken met:

make network-ls

lokaal is de naam van het netwerk. Het subnet is dan 172.19.0.0/16 en de gateway is dan 172.19.0.1/16.

Het voordeel van een eigen netwerk is dat er dan een eigen DNS server beschikbaar is op adres 127.0.0.11. De container gekoppeld met dit netwerk kunnen elkaar dan bereiken via de domeinnaam. De DNS server kan je testen met dig.

Start de twee containers:

make erl1
make erl2

Deze containers werken dan interactief. In één van beide start je het ping commando:

Erlang/OTP 19 [erts-8.1.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.1.1  (abort with ^G)
(huis1@huis1.straat.org)1> net_adm:ping('huis2@huis2.straat.org').
pong
(huis1@huis1.straat.org)2> nodes().
['huis2@huis2.straat.org']

In de andere container zie je dan de nodes().

Erlang/OTP 19 [erts-8.1.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.1.1  (abort with ^G)
(huis2@huis2.straat.org)1> nodes().
['huis1@huis1.straat.org']
(huis2@huis2.straat.org)2> 

Door het gebruik van de Makefile heof je niet al die docker run parameters te onthouden. Voor alle duidelijkheid worden ze hier opgesomd:

  • --name huis1 dit is de naam van de container
  • -it de container werkt iteratief
  • --rm na het stoppen van de container wordt die verwijderd
  • --dns-search=straat.org zorgt voor de search optie in /etc/resolv.conf
  • --net=lokaal deze container wordt in het lokaal netwerk geplaatst
  • -h huis1 dit is de hostname
  • --network-alias=huis1.straat.org dit is een extra domeinnaam voor het netwerk. Anders werkt de Linux ping met de FQDN niet.
  • lrutten/erlang de gebruikte image
  • erl -name huis1@huis1.straat.org -setcookie abc de start van de Erlang node, dat kan ook /bin/bash zijn.

In de container ziet /etc/resolv.conf er dan zo uit:

search straat.org
nameserver 127.0.0.11
options ndots:0

Het bestand /etc/resolv.conf heeft zijn eigen mount en komt niet uit de image. Zo kan je elke container andere instellingen geven ook al werk je met dezelfde image. Dit geldt ook voor /etc/hostname en /etc/hosts.

Deze links zijn nuttig: