I wrote a simple docker image which starts up an Erlang node (rebar3 release, console launch mode). It starts fine and lets me ping the node from within the container. However, I can't get erl shell to ping it from the host — it simply returns pang and nothing is logged in the dockerized console.
The Dockerfile just starts the node, it doesn't do anything more interesting.
Checklist
- Cookie is set and matches
snameis set on both nodes- Docker node is reachable from other container nodes
- I refer to the docker node using full sname (tried
nodename@localhost,nodename@machinenameand[email protected]) epmdport is exposed (tried without it as well)
What could I have forgotten to make it work?
Disclaimer: This answer is valid for Linux systems. Also, I think that the first and last options are the easiest
There are several ways to do so, but before, let's set some key ideas:
In order for the distribution protocol to succeed, not only the node needs to be reached at the name used for the ping, the whole node name must match.
Erlang's
-nodecan be used with IP, it will be used extensively in the following commandsOptions
Now, let's get with the options (All the commands are to be run in different terminals)
Docker: Host network namespace
When starting docker in host's network namespace (
--net=host), there's no difference with running both outside of docker (for network purposes). It's the easiest way to connect both nodes using plain docker.-name (ip):
-sname with @localhost:
-sname with @$(hostname -f):
Docker: Using docker's default bridge (
docker0)By default, docker starts the containers in its own bridge, and these ips can be reached without need to expose any port.
ip a show docker0lists 172.17.0.1/16 for my machine, and erlang listens in 172.17.0.2 (shown indocker inspect <container>)-name (ip):
-sname (fake name resolving to container ip):
Docker: Using some other docker bridge
Just create the new network and repeat the previous steps, using the ips from the new network
Docker: Exposing ports with two EPMDs
When exposing ports you have to juggle ports and ips because the EPMD ports must be the same.
In this case you are going to have two epmds, one for the host and other for the container (EPMD rejects name requests from non-local peers), listening in the same port number.
The trick here is (ab)using the 127.0.0.* ips that point all to localhost to simulate different nodes. Note the flag to set the distribution port, as mentioned by @legoscia
-name (ip):
-sname (fake name resolving to 127.0.0.2)
Docker-compose
docker-composeallows you to easily set up multi-container systems. With it, you don't need to create/inspect networks.Given the following
docker-compose.yaml:If you run the following
docker-compose runcommands, you'll see the results: