Wigny
February 15, 2025, 1:11am
1
Hey folks, I would like help to connect Livebook to an Elixir node running in a Docker container.
To run the container I usually do
docker-compose run --rm --service-ports api iex -S mix
and Livebook
docker run -p 8080:8080 -p 8081:8081 --pull always -u $(id -u):$(id -g) -v $(pwd):/data ghcr.io/livebook-dev/livebook:nightly
as described in the docs.
Now I want to attach a new notebook to the running app. If I got it right, for the node to be visible to Livebook, it must be running in the same network and have a known RELEASE_NODE
and RELEASE_COOKIE
. For that, I tried following this gist , this thread and also this discussion , but got no luck.
This is what I tried:
docker-compose run \
--rm \
--service-ports \
-e RELEASE_DISTRIBUTION="name" \
-e RELEASE_NODE="api@127.0.0.1" \
-e RELEASE_COOKIE="mycookie" \
api \
iex --name api@127.0.0.1 --cookie mycookie -S mix
docker run \
-p 8080:8080 \
-p 8081:8081 \
--pull always \
-u $(id -u):$(id -g) \
-v $(pwd):/data \
--network $API_NETWORK \
-e LIVEBOOK_NODE="livebook@127.0.0.1" \
-e LIVEBOOK_DISTRIBUTION=name \
-e LIVEBOOK_DEFAULT_RUNTIME="attached:api@127.0.0.1:mycookie" \
ghcr.io/livebook-dev/livebook:nightly
What am I missing?
1 Like
@Wigny
I think 127.0.0.1
might be the issue (Docker typically uses 172.x.x.x/16
subnets). Have you tried using container names for hostnames?
Hey @Wigny , I think @ruslandoga is correct, the iex
node needs to be api@[CONTAINER_NAME]
, as mentioned in the gist .
Sidenote:
you don’t need the RELEASE_*
env vars, they only apply to releases, but not for iex -S mix
(and you already set --name
and --cookie
instead)
LIVEBOOK_DISTRIBUTION=name
no longer has any effect, so you can skip it
Because of how they’re exposing the ports 8080:8080
, I think this will expose them like any other service on the host (i.e. nmap localhost
would show port 8080 as being open). If the syntax was just 8080
, then I believe your assumption would be correct. (Might be worth a shot also, plus better to isolate the containerized service in its own Docker network… Just gotta make sure the container name is correct then.)
Also could
Interesting, I’ll try it out.
I wasn't able to access another container in the same bridge network via localhost.
$ docker network create livebook
4c530174a62315fa9e7653147e8b3d2fbb7a16db089abf00b6600b14269c72ac
$ docker network inspect livebook
[
{
"Name": "livebook",
"Id": "4c530174a62315fa9e7653147e8b3d2fbb7a16db089abf00b6600b14269c72ac",
"Created": "2025-02-16T10:39:41.965962798Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
$ docker run -p 80:80 -d --network livebook nginx:alpine
aaa54c3c62e7bd1c80d2db3a76064a9f60dda209b6beb5fab7aa1637930277f6
$ curl http://localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ docker network inspect livebook
[
{
"Name": "livebook",
"Id": "4c530174a62315fa9e7653147e8b3d2fbb7a16db089abf00b6600b14269c72ac",
"Created": "2025-02-16T10:39:41.965962798Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"aaa54c3c62e7bd1c80d2db3a76064a9f60dda209b6beb5fab7aa1637930277f6": {
"Name": "strange_kalam",
"EndpointID": "0193b7811de9e139f7f5a562c789d332d409241c3d7a1be89b9dcf14ffaba133",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
$ docker run -ti --network livebook alpine
# apk add curl
# curl http://localhost:80
curl: (7) Failed to connect to localhost port 80 after 0 ms: Could not connect to server
# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
3: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN qlen 1000
link/gre 0.0.0.0 brd 0.0.0.0
4: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
5: erspan0@NONE: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
6: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
7: ip6_vti0@NONE: <NOARP> mtu 1428 qdisc noop state DOWN qlen 1000
link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
8: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
9: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1000
link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
10: ip6gre0@NONE: <NOARP> mtu 1448 qdisc noop state DOWN qlen 1000
link/[823] 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
# curl http://172.18.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Would you be able to modify my example to make it work?
Wigny
February 16, 2025, 10:32pm
7
Thanks for the tips!
So I got rid of the unnecessary env vars and started giving a name to my container:
docker-compose run \
--rm \
--service-ports \
--name api \
api \
iex --name test@api --cookie mycookie -S mix phx.server
docker run \
-p 8080:8080 \
-p 8081:8081 \
--pull always \
-u $(id -u):$(id -g) \
-v $(pwd):/data \
--network $API_NETWORK \
-e LIVEBOOK_DEFAULT_RUNTIME="attached:test@api:mycookie" \
ghcr.io/livebook-dev/livebook:nightly
but when trying to attach Livebook, I’m getting in the logs ** Hostname api is illegal **
.
Given our api
app has a /api/ping
endpoint, I tried checking that within the Livebook container we can access the endpoint using wget
. So by attaching to the Livebook container running docker exec -it $CONTAINERID bash
and executing wget -qO- localhost:4000/api/ping
or wget -qO- api:4000/api/ping
I had no response, but wget -qO- host.docker.internal:4000/api/ping
or wget -qO- 172.17.0.1:4000/api/ping
returns pong
…
** Hostname api is illegal **
Ah, when running using long names by specifying --name
(which Livebook now always does as well), if the hostname needs to be either an IP or a fully qualified domain name (basically, it needs at least one dot). Looks like it’s only validated when trying to connect to another node, not when starting the node itself.
One way would be for the container name to include a dot, but I believe that can also just use {container_name}.{network_name}
as the hostname and the internal Docker DNS will resolve that correctly.
1 Like
Wigny
February 22, 2025, 5:32am
9
That worked like a charm! Many thanks!
Leaving the full command here for future readers:
docker-compose run \
--rm \
--service-ports \
--name api \
api \
iex --name test@api.$API_NETWORK --cookie mycookie -S mix
docker run \
-p 8080:8080 \
-p 8081:8081 \
--pull always \
-u $(id -u):$(id -g) \
-v $(pwd):/data \
--network $API_NETWORK \
-e LIVEBOOK_DEFAULT_RUNTIME="attached:test@api.$API_NETWORK:mycookie" \
ghcr.io/livebook-dev/livebook:nightly
1 Like